Skip to content

Commit

Permalink
Merge branch 'core/solving-log'
Browse files Browse the repository at this point in the history
  • Loading branch information
jcoupey committed Sep 13, 2024
2 parents 74e6be7 + 95ae7aa commit f6ae995
Show file tree
Hide file tree
Showing 22 changed files with 477 additions and 89 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@

### Added

#### Internals

- LOG_LS flag to generate debug info on the internal solving process (#1124)

### Changed

#### Internals
Expand Down
16 changes: 8 additions & 8 deletions libvroom_examples/libvroom.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -218,11 +218,11 @@ void run_example_with_osrm() {
// - jobs 3 and 4 can only be served by vehicle 2
// - jobs 5 and 6 can be served by either one of the vehicles

// Solve!
// Solve using exploration level as depth and number of searches.
auto sol =
problem_instance.solve(vroom::DEFAULT_EXPLORATION_LEVEL, // Exploration
// level.
vroom::DEFAULT_THREADS_NUMBER); // Use 4 threads.
problem_instance.solve(vroom::DEFAULT_EXPLORATION_LEVEL,
vroom::DEFAULT_EXPLORATION_LEVEL,
vroom::DEFAULT_THREADS_NUMBER); // Use 4 threads.

log_solution(sol, GEOMETRY);
}
Expand Down Expand Up @@ -274,11 +274,11 @@ void run_example_with_custom_matrix() {
problem_instance.add_job(j);
}

// Solve!
// Solve using exploration level as depth and number of searches.
auto sol =
problem_instance.solve(vroom::DEFAULT_EXPLORATION_LEVEL, // Exploration
// level.
vroom::DEFAULT_THREADS_NUMBER); // Use 4 threads.
problem_instance.solve(vroom::DEFAULT_EXPLORATION_LEVEL,
vroom::DEFAULT_EXPLORATION_LEVEL,
vroom::DEFAULT_THREADS_NUMBER); // Use 4 threads.

log_solution(sol, GEOMETRY);
}
Expand Down
80 changes: 75 additions & 5 deletions src/algorithms/local_search/local_search.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,11 +75,11 @@ LocalSearch<Route,
PriorityReplace,
TSPFix>::LocalSearch(const Input& input,
std::vector<Route>& sol,
unsigned max_nb_jobs_removal,
unsigned depth,
const Timeout& timeout)
: _input(input),
_nb_vehicles(_input.vehicles.size()),
_max_nb_jobs_removal(max_nb_jobs_removal),
_depth(depth),
_deadline(timeout.has_value() ? utils::now() + timeout.value()
: Deadline()),
_all_routes(_nb_vehicles),
Expand Down Expand Up @@ -162,7 +162,12 @@ void LocalSearch<Route,
RouteSplit,
PriorityReplace,
TSPFix>::try_job_additions(const std::vector<Index>& routes,
double regret_coeff) {
double regret_coeff
#ifdef LOG_LS
,
bool log_addition_step
#endif
) {
bool job_added;

std::vector<std::vector<RouteInsertion>> route_job_insertions;
Expand Down Expand Up @@ -318,6 +323,16 @@ void LocalSearch<Route,
route_job_insertions[best_route_idx][j].eval.cost += fixed_cost;
}
}

#ifdef LOG_LS
if (log_addition_step) {
steps.push_back({utils::now(),
log::EVENT::JOB_ADDITION,
OperatorName::MAX,
utils::SolutionIndicators<Route>(_input, _sol),
std::nullopt});
}
#endif
}
} while (job_added);

Expand Down Expand Up @@ -1830,6 +1845,14 @@ void LocalSearch<Route,
++applied_moves.at(best_ops[best_source][best_target]->get_name());
#endif

#ifdef LOG_LS
steps.push_back({utils::now(),
log::EVENT::OPERATOR,
best_ops[best_source][best_target]->get_name(),
utils::SolutionIndicators<Route>(_input, _sol),
std::nullopt});
#endif

#ifndef NDEBUG
// Update route costs.
const auto previous_eval =
Expand Down Expand Up @@ -1869,7 +1892,12 @@ void LocalSearch<Route,

try_job_additions(best_ops[best_source][best_target]
->addition_candidates(),
0);
0
#ifdef LOG_LS
,
true
#endif
);

for (auto v_rank : update_candidates) {
_sol_state.update_costs(_sol[v_rank].route, v_rank);
Expand Down Expand Up @@ -1982,6 +2010,14 @@ void LocalSearch<Route,

unsigned current_nb_removal = 1;

#ifdef LOG_LS
steps.push_back({utils::now(),
log::EVENT::START,
OperatorName::MAX,
_best_sol_indicators,
utils::format_solution(_input, _best_sol)});
#endif

while (try_ls_step) {
// A round of local search.
run_ls_step();
Expand All @@ -1992,6 +2028,14 @@ void LocalSearch<Route,
current_sol_indicators < _best_sol_indicators) {
_best_sol_indicators = current_sol_indicators;
_best_sol = _sol;

#ifdef LOG_LS
steps.push_back({utils::now(),
log::EVENT::LOCAL_MINIMA,
OperatorName::MAX,
_best_sol_indicators,
utils::format_solution(_input, _best_sol)});
#endif
} else {
if (!first_step) {
++current_nb_removal;
Expand All @@ -2001,11 +2045,21 @@ void LocalSearch<Route,
_sol = _best_sol;
_sol_state.setup(_sol);
}
#ifdef LOG_LS
if (_best_sol_indicators < current_sol_indicators or
_best_sol_indicators == current_sol_indicators) {
steps.push_back({utils::now(),
log::EVENT::ROLLBACK,
OperatorName::MAX,
_best_sol_indicators,
std::nullopt});
}
#endif
}

// Try again on each improvement until we reach last job removal
// level or deadline is met.
try_ls_step = (current_nb_removal <= _max_nb_jobs_removal) &&
try_ls_step = (current_nb_removal <= _depth) &&
(!_deadline.has_value() || utils::now() < _deadline.value());

if (try_ls_step) {
Expand All @@ -2023,6 +2077,14 @@ void LocalSearch<Route,
}
}

#ifdef LOG_LS
steps.push_back({utils::now(),
log::EVENT::RUIN,
OperatorName::MAX,
utils::SolutionIndicators<Route>(_input, _sol),
utils::format_solution(_input, _sol)});
#endif

// Update insertion ranks ranges.
for (std::size_t v = 0; v < _sol.size(); ++v) {
_sol_state.set_insertion_ranks(_sol[v], v);
Expand All @@ -2043,6 +2105,14 @@ void LocalSearch<Route,
_sol_state.set_pd_matching_ranks(_sol[v].route, v);
_sol_state.set_pd_gains(_sol[v].route, v);
}

#ifdef LOG_LS
steps.push_back({utils::now(),
log::EVENT::RECREATE,
OperatorName::MAX,
utils::SolutionIndicators<Route>(_input, _sol),
utils::format_solution(_input, _sol)});
#endif
}

first_step = false;
Expand Down
26 changes: 23 additions & 3 deletions src/algorithms/local_search/local_search.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ All rights reserved (see LICENSE).
#include "structures/vroom/solution_indicators.h"
#include "structures/vroom/solution_state.h"

#ifdef LOG_LS
#include "algorithms/local_search/log_local_search.h"
#endif

namespace vroom::ls {

template <class Route,
Expand Down Expand Up @@ -40,7 +44,7 @@ class LocalSearch {
const Input& _input;
const std::size_t _nb_vehicles;

const unsigned _max_nb_jobs_removal;
const unsigned _depth;
const Deadline _deadline;

std::vector<Index> _all_routes;
Expand All @@ -58,7 +62,17 @@ class LocalSearch {
std::array<unsigned, OperatorName::MAX> applied_moves;
#endif

void try_job_additions(const std::vector<Index>& routes, double regret_coeff);
#ifdef LOG_LS
std::vector<log::Step<Route>> steps;
#endif

void try_job_additions(const std::vector<Index>& routes,
double regret_coeff
#ifdef LOG_LS
,
bool log_addition_step = false
#endif
);

void run_ls_step();

Expand All @@ -78,7 +92,7 @@ class LocalSearch {
public:
LocalSearch(const Input& input,
std::vector<Route>& tw_sol,
unsigned max_nb_jobs_removal,
unsigned depth,
const Timeout& timeout);

utils::SolutionIndicators<Route> indicators() const;
Expand All @@ -88,6 +102,12 @@ class LocalSearch {
#ifdef LOG_LS_OPERATORS
std::array<OperatorStats, OperatorName::MAX> get_stats() const;
#endif

#ifdef LOG_LS
std::vector<log::Step<Route>> get_steps() {
return steps;
}
#endif
};

} // namespace vroom::ls
Expand Down
42 changes: 42 additions & 0 deletions src/algorithms/local_search/log_local_search.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#ifndef LOG_LOCAL_SEARCH_H
#define LOG_LOCAL_SEARCH_H

/*
This file is part of VROOM.
Copyright (c) 2015-2024, Julien Coupey.
All rights reserved (see LICENSE).
*/

#include "structures/vroom/solution/solution.h"
#include "structures/vroom/solution_indicators.h"

namespace vroom::ls::log {

enum class EVENT {
START,
OPERATOR,
LOCAL_MINIMA,
JOB_ADDITION,
RUIN,
RECREATE,
ROLLBACK
};

template <class Route> struct Step {
TimePoint time_point;
EVENT event;
OperatorName operator_name;
vroom::utils::SolutionIndicators<Route> indicators;
std::optional<Solution> solution;
};

template <class Route> struct Dump {
HeuristicParameters heuristic_parameters;
std::vector<Step<Route>> steps;
};
} // namespace vroom::ls::log

#endif
27 changes: 22 additions & 5 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ int main(int argc, char** argv) {
std::string limit_arg;
std::string output_file;
std::vector<std::string> heuristic_params_arg;
unsigned exploration_level;

cxxopts::Options options("vroom",
"VROOM Copyright (C) 2015-2024, Julien Coupey\n"
Expand Down Expand Up @@ -79,19 +80,28 @@ int main(int argc, char** argv) {
("v,version", "output version information and exit")
("x,explore",
"exploration level to use (0..5)",
cxxopts::value<unsigned>(cl_args.exploration_level)->default_value(std::to_string(vroom::DEFAULT_EXPLORATION_LEVEL)))
cxxopts::value<unsigned>(exploration_level)->default_value(std::to_string(vroom::DEFAULT_EXPLORATION_LEVEL)))
("stdin",
"optional input positional arg",
cxxopts::value<std::string>(cl_args.input));

// we don't want to print debug args on --help
std::optional<unsigned> debug_depth;
std::optional<unsigned> debug_nb_searches;

options.add_options("debug_group")
("e,heuristic-param",
"Heuristic parameter",
cxxopts::value<std::vector<std::string>>(heuristic_params_arg))
("f,apply-tsp-fix",
"apply experimental TSPFix local search operator",
cxxopts::value<bool>(cl_args.apply_TSPFix)->default_value("false"));
cxxopts::value<bool>(cl_args.apply_TSPFix)->default_value("false"))
("d,depth",
"search depth",
cxxopts::value<std::optional<unsigned>>(debug_depth))
("s,nb-searches",
"number of searches to perform in parallel",
cxxopts::value<std::optional<unsigned>>(debug_nb_searches));

// clang-format on
try {
Expand Down Expand Up @@ -153,8 +163,14 @@ int main(int argc, char** argv) {
for (const auto& port : port_args) {
vroom::io::update_port(cl_args.servers, port);
}
cl_args.exploration_level =
std::min(cl_args.exploration_level, vroom::MAX_EXPLORATION_LEVEL);
exploration_level = std::min(exploration_level, vroom::MAX_EXPLORATION_LEVEL);
vroom::io::set_exploration_level(cl_args, exploration_level);
if (debug_depth) {
cl_args.depth = debug_depth.value();
}
if (debug_nb_searches) {
cl_args.nb_searches = debug_nb_searches.value();
}

// Determine routing engine (defaults to ROUTER::OSRM).
if (router_arg == "libosrm") {
Expand Down Expand Up @@ -220,7 +236,8 @@ int main(int argc, char** argv) {

vroom::Solution sol = (cl_args.check)
? problem_instance.check(cl_args.nb_threads)
: problem_instance.solve(cl_args.exploration_level,
: problem_instance.solve(cl_args.nb_searches,
cl_args.depth,
cl_args.nb_threads,
cl_args.timeout,
cl_args.h_params);
Expand Down
6 changes: 4 additions & 2 deletions src/problems/cvrp/cvrp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,8 @@ const std::vector<HeuristicParameters> CVRP::heterogeneous_parameters =
CVRP::CVRP(const Input& input) : VRP(input) {
}

Solution CVRP::solve(unsigned exploration_level,
Solution CVRP::solve(unsigned nb_searches,
unsigned depth,
unsigned nb_threads,
const Timeout& timeout,
const std::vector<HeuristicParameters>& h_param) const {
Expand All @@ -164,7 +165,8 @@ Solution CVRP::solve(unsigned exploration_level,
return utils::format_solution(_input, {r});
}

return VRP::solve<RawRoute, cvrp::LocalSearch>(exploration_level,
return VRP::solve<RawRoute, cvrp::LocalSearch>(nb_searches,
depth,
nb_threads,
timeout,
h_param,
Expand Down
3 changes: 2 additions & 1 deletion src/problems/cvrp/cvrp.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ class CVRP : public VRP {
explicit CVRP(const Input& input);

Solution
solve(unsigned exploration_level,
solve(unsigned nb_searches,
unsigned depth,
unsigned nb_threads,
const Timeout& timeout,
const std::vector<HeuristicParameters>& h_param) const override;
Expand Down
Loading

0 comments on commit f6ae995

Please sign in to comment.