Skip to content

Commit c6c75ac

Browse files
Reset base to working commit
1 parent 620c98c commit c6c75ac

56 files changed

Lines changed: 1153 additions & 1242 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CHANGELOG.md

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,13 @@
66

77
#### Features
88

9-
- Ability to set different tasks setup/service time per vehicle type (#336)
9+
- Ability to set different task times per vehicle type (#336)
10+
- Task times can be included in the cost used internally for optimization (#1130)
11+
- Support for cost per hour spent on tasks on a vehicle basis (#1130)
1012

1113
#### Internals
1214

1315
- Apply heuristics to partial solutions provided in input (#977)
14-
- LOG_LS flag to generate debug info on the internal solving process (#1124)
1516

1617
### Changed
1718

@@ -31,6 +32,10 @@
3132
- Remove heuristic synchronisation (#1188)
3233
- Refactor gain evaluation in operators to ease code maintenance and extension (#1266)
3334
- Remove `LOG_LS_OPERATORS` (#1263)
35+
- Update README to clarify high-level purpose and usage of the project (#1264)
36+
- Remove unused `breaks_travel_margin` members from TWRoute and associated code (#1295)
37+
- Run routing requests in parallel (#1218)
38+
- Refactor parallel solving (#1305)
3439

3540
#### CI
3641

@@ -44,6 +49,7 @@
4449
#### Dependency
4550

4651
- Update `LibosrmWrapper` to breaking change introduced in OSRM v6 (#1234)
52+
- Update `asio` usage for deprecated `io_service` and `query` (#1279)
4753

4854
### Fixed
4955

@@ -60,6 +66,9 @@
6066
- Solution "shadowing" when only comparing indicators (#1199)
6167
- Too loose `max_tasks` bound derived from TW (#1243)
6268
- Wrong evaluation in `ReverseTwoOpt` (#1271)
69+
- Misleading error with custom distance matrix (#1281)
70+
- Wrong distance-based optimization with only custom durations (#1298)
71+
- Break positioning heuristic shortcoming (#1251)
6372

6473
#### Internals
6574

README.md

Lines changed: 52 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,46 @@
1-
# Vehicle Routing Open-source Optimization Machine
1+
# Complex Route Optimization in Milliseconds
22

33
_Good solutions, fast._
44

55
---
66

77
## About
88

9-
VROOM is an open-source optimization engine written in C++20 that aim
10-
at providing good solutions to various real-life [vehicle routing
9+
Vroom is an open-source route optimization engine written in C++20
10+
that solves complex [vehicle routing
1111
problems](https://en.wikipedia.org/wiki/Vehicle_routing_problem) (VRP)
12-
within a small computing time.
13-
14-
The project has been initiated by [Verso](https://verso-optim.com/) to
15-
power its [route optimization
16-
API](https://blog.verso-optim.com/category/route-optimization/api/).
12+
in milliseconds.
13+
14+
The project is maintained by [Verso](https://verso-optim.com). If you
15+
want to get started as quickly as possible with route optimization,
16+
you want white-glove support to increase the ROI from your
17+
optimization project and/or you need access to the best possible data
18+
for even more accurate route timing, you should use the [Vroom Premium
19+
API](https://verso-optim.com/api/).
20+
21+
## Why use Vroom?
22+
23+
Vroom is ideally suited to situations in which route optimization has
24+
to be done quickly, both to react to changes and new requests and to
25+
iterate on your routes to find the solution that works best for all
26+
stakeholders.
27+
28+
Vroom doesn't replace domain expertise. It allows fleet managers and
29+
business owners to apply their domain knowledge and understanding of
30+
the company culture to larger, more complex optimization problems than
31+
they could manage manually.
32+
33+
The open source project is ideal for companies who want to control
34+
their own infrastructure, have the technical expertise to do so and
35+
can manage their own data integration. If you would rather not manage
36+
your own infrastructure, if you want access to expertise around route
37+
optimization or if you want more accurate ETA relying on enhanced
38+
speed estimates, consider using the [Vroom Premium
39+
API](https://verso-optim.com/api/).
1740

1841
## Supported problem types
1942

20-
VROOM can solve several well-known types of vehicle routing problems
43+
Vroom solves several well-known types of vehicle routing problems
2144
(VRP).
2245

2346
- TSP (travelling salesman problem)
@@ -26,11 +49,13 @@ VROOM can solve several well-known types of vehicle routing problems
2649
- MDHVRPTW (multi-depot heterogeneous vehicle VRPTW)
2750
- PDPTW (pickup-and-delivery problem with TW)
2851

29-
VROOM can also solve any mix of the above problem types.
52+
Vroom solves all of the above routing problems at the same time — and
53+
delivers the optimized route in milliseconds, even when complex
54+
variables are involved.
3055

31-
## Features
56+
## How it works
3257

33-
VROOM models a VRP with a description of resources (`vehicles`),
58+
Vroom models a VRP with a description of resources (`vehicles`),
3459
single-location pickup and/or delivery tasks (`jobs`) and
3560
pickup-and-delivery tasks that should happen within the same route
3661
(`shipments`).
@@ -55,14 +80,14 @@ pickup-and-delivery tasks that should happen within the same route
5580

5681
## Supported routing engines
5782

58-
VROOM works out-of-the-box on top of several open-source routing
83+
Vroom works out-of-the-box on top of several open-source routing
5984
engines.
6085

6186
- [OSRM](http://project-osrm.org/)
6287
- [Openrouteservice](https://openrouteservice.org/)
6388
- [Valhalla](https://github.com/valhalla/valhalla)
6489

65-
VROOM can also use a custom cost matrix computed from any other
90+
Vroom can also use a custom cost matrix computed from any other
6691
source.
6792

6893
## Getting started
@@ -72,54 +97,54 @@ source.
7297
- The [demo frontend](http://map.vroom-project.org/) provides a simple
7398
user interface for quick tests.
7499
- The [demo
75-
server](https://github.com/VROOM-Project/vroom/wiki/Demo-server) makes
100+
server](https://github.com/Vroom-Project/vroom/wiki/Demo-server) makes
76101
it easy to send sample optimization requests for testing purposes.
77102

78-
### Setup your own VROOM stack
103+
### Setup your own Vroom stack
79104

80105
#### Solving engine
81106

82107
Several options are available to get `vroom` running on command-line.
83108

84109
1. Build from source following [the wiki
85-
instructions](https://github.com/VROOM-Project/vroom/wiki/Building).
110+
instructions](https://github.com/Vroom-Project/vroom/wiki/Building).
86111
2. Use
87-
[`vroom-docker`](https://github.com/VROOM-Project/vroom-docker).
112+
[`vroom-docker`](https://github.com/Vroom-Project/vroom-docker).
88113

89114
### Command-line usage
90115

91116
Refer to [this wiki
92-
page](https://github.com/VROOM-Project/vroom/wiki/Usage)
117+
page](https://github.com/Vroom-Project/vroom/wiki/Usage)
93118

94119
#### Http wrapper
95120

96-
[`vroom-express`](https://github.com/VROOM-Project/vroom-express) is a
121+
[`vroom-express`](https://github.com/Vroom-Project/vroom-express) is a
97122
simple wrapper to use `vroom` with http requests. It's already bundled
98123
in the `vroom-docker` setup.
99124

100125
#### Using libvroom from C++
101126

102127
The project can also used as a library from any C++ project, refer to
103128
[this wiki
104-
page](https://github.com/VROOM-Project/vroom/wiki/Using-libvroom).
129+
page](https://github.com/Vroom-Project/vroom/wiki/Using-libvroom).
105130

106131
## Tests
107132

108133
### CI builds
109134

110-
[![vroom](https://github.com/VROOM-Project/vroom/actions/workflows/vroom.yml/badge.svg)](https://github.com/VROOM-Project/vroom/actions/workflows/vroom.yml)
135+
[![vroom](https://github.com/Vroom-Project/vroom/actions/workflows/vroom.yml/badge.svg)](https://github.com/Vroom-Project/vroom/actions/workflows/vroom.yml)
111136

112-
[![vroom + libosrm](https://github.com/VROOM-Project/vroom/actions/workflows/vroom_libosrm.yml/badge.svg?branch=master)](https://github.com/VROOM-Project/vroom/actions/workflows/vroom_libosrm.yml)
137+
[![vroom + libosrm](https://github.com/Vroom-Project/vroom/actions/workflows/vroom_libosrm.yml/badge.svg?branch=master)](https://github.com/Vroom-Project/vroom/actions/workflows/vroom_libosrm.yml)
113138

114-
[Github Actions](https://github.com/VROOM-Project/vroom/actions) are
139+
[Github Actions](https://github.com/Vroom-Project/vroom/actions) are
115140
used to check the build across various compilers and settings.
116141

117142
### Functional tests
118143

119144
Several sets of instances are used.
120145

121146
1. Benchmark instances from papers (see [wiki page with
122-
results](https://github.com/VROOM-Project/vroom/wiki/Benchmarks)).
147+
results](https://github.com/Vroom-Project/vroom/wiki/Benchmarks)).
123148
2. Custom random instances generated to target typical use-cases and
124149
constraints settings.
125150
3. Real-life instances.
@@ -131,11 +156,11 @@ solution quality and computing times.
131156

132157
## Reference in publications
133158

134-
To cite VROOM in publications, please use:
159+
To cite Vroom in publications, please use:
135160

136161
```bibtex
137162
@manual{vroom_v1.14,
138-
title = {{VROOM v1.14, Vehicle Routing Open-source Optimization Machine}},
163+
title = {{Vroom v1.14, Vehicle Routing Open-source Optimization Machine}},
139164
author = {Coupey, Julien and Nicod, Jean-Marc and Varnier, Christophe},
140165
year = 2024,
141166
organization = {Verso (\url{https://verso-optim.com/})},

docs/API.md

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,7 @@ A `cost` object has the following properties:
132132
| ----------- | ----------- |
133133
| [`fixed`] | integer defining the cost of using this vehicle in the solution (defaults to `0`) |
134134
| [`per_hour`] | integer defining the cost for one hour of travel time with this vehicle (defaults to `3600`) |
135+
| [`per_task_hour`] | integer defining the cost for one hour of task time (setup + service) with this vehicle (defaults to `0`) |
135136
| [`per_km`] | integer defining the cost for one km of travel time with this vehicle (defaults to `0`) |
136137

137138
Using a non-default `per-hour` value means defining travel costs based
@@ -310,12 +311,14 @@ integers filed under the `profile` key, then under:
310311

311312
- `durations` for a custom travel-time matrix that will be used for
312313
all checks against timing constraints;
313-
- `distances` for a custom distance matrix;
314+
- `distances` for a custom distance matrix (requires also providing
315+
custom `durations`);
314316
- `costs` for a custom cost matrix that will be used within all route
315317
cost evaluations.
316318

317-
If only the `durations` matrix is provided, internal costs are derived from
318-
durations based on vehicles `costs` properties.
319+
If `durations` are provided without `distances` and distances are
320+
required (either by `-g` or a non-zero `per_km` cost), then a call to
321+
the routing engine is generated to fetch distances.
319322

320323
Example of describing different matrices for different vehicle
321324
profiles:

src/algorithms/heuristics/heuristics.cpp

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -153,31 +153,38 @@ template <class Route> struct UnassignedCosts {
153153
min_unassigned_to_route(input.jobs.size(),
154154
std::numeric_limits<Cost>::max()) {
155155
for (const auto job_rank : unassigned) {
156-
const auto unassigned_job_index = input.jobs[job_rank].index();
156+
const auto& unassigned_job = input.jobs[job_rank];
157+
const auto unassigned_job_index = unassigned_job.index();
158+
159+
// The purpose here is to generate insertion lower bounds so we
160+
// only account for service times (no setup) which are
161+
// independent of insertion rank.
162+
const auto added_service = unassigned_job.services[vehicle.type];
163+
const auto service_cost = vehicle.task_eval(added_service).cost;
157164

158165
if (vehicle.has_start()) {
159166
const auto start_to_job =
160167
vehicle.eval(vehicle.start.value().index(), unassigned_job_index)
161168
.cost;
162-
min_route_to_unassigned[job_rank] = start_to_job;
169+
min_route_to_unassigned[job_rank] = start_to_job + service_cost;
163170
}
164171

165172
if (vehicle.has_end()) {
166173
const auto job_to_end =
167174
vehicle.eval(unassigned_job_index, vehicle.end.value().index()).cost;
168-
min_unassigned_to_route[job_rank] = job_to_end;
175+
min_unassigned_to_route[job_rank] = job_to_end + service_cost;
169176
}
170177

171178
for (const auto j : route.route) {
172179
const auto job_index = input.jobs[j].index();
173180

174181
const auto job_to_unassigned =
175-
vehicle.eval(job_index, unassigned_job_index).cost;
182+
vehicle.eval(job_index, unassigned_job_index).cost + service_cost;
176183
min_route_to_unassigned[job_rank] =
177184
std::min(min_route_to_unassigned[job_rank], job_to_unassigned);
178185

179186
const auto unassigned_to_job =
180-
vehicle.eval(unassigned_job_index, job_index).cost;
187+
vehicle.eval(unassigned_job_index, job_index).cost + service_cost;
181188
min_unassigned_to_route[job_rank] =
182189
std::min(min_unassigned_to_route[job_rank], unassigned_to_job);
183190
}
@@ -215,15 +222,19 @@ template <class Route> struct UnassignedCosts {
215222
const std::set<Index>& unassigned,
216223
Index inserted_index) {
217224
for (const auto j : unassigned) {
218-
const auto unassigned_job_index = input.jobs[j].index();
225+
const auto& unassigned_job = input.jobs[j];
226+
const auto unassigned_job_index = unassigned_job.index();
227+
228+
const auto added_service = unassigned_job.services[vehicle.type];
229+
const auto service_cost = vehicle.task_eval(added_service).cost;
219230

220231
const auto to_unassigned =
221-
vehicle.eval(inserted_index, unassigned_job_index).cost;
232+
vehicle.eval(inserted_index, unassigned_job_index).cost + service_cost;
222233
min_route_to_unassigned[j] =
223234
std::min(min_route_to_unassigned[j], to_unassigned);
224235

225236
const auto from_unassigned =
226-
vehicle.eval(unassigned_job_index, inserted_index).cost;
237+
vehicle.eval(unassigned_job_index, inserted_index).cost + service_cost;
227238
min_unassigned_to_route[j] =
228239
std::min(min_unassigned_to_route[j], from_unassigned);
229240
}
@@ -279,7 +290,7 @@ inline Eval fill_route(const Input& input,
279290

280291
for (Index r = 0; r <= route.size(); ++r) {
281292
const auto current_eval =
282-
utils::addition_cost(input, job_rank, vehicle, route.route, r);
293+
utils::addition_eval(input, job_rank, vehicle, route.route, r);
283294

284295
const double current_cost =
285296
static_cast<double>(current_eval.cost) -
@@ -317,7 +328,7 @@ inline Eval fill_route(const Input& input,
317328
route.route.size() + 1);
318329

319330
for (unsigned d_rank = 0; d_rank <= route.route.size(); ++d_rank) {
320-
d_adds[d_rank] = utils::addition_cost(input,
331+
d_adds[d_rank] = utils::addition_eval(input,
321332
job_rank + 1,
322333
vehicle,
323334
route.route,
@@ -329,7 +340,7 @@ inline Eval fill_route(const Input& input,
329340
}
330341

331342
for (Index pickup_r = 0; pickup_r <= route.size(); ++pickup_r) {
332-
const auto p_add = utils::addition_cost(input,
343+
const auto p_add = utils::addition_eval(input,
333344
job_rank,
334345
vehicle,
335346
route.route,
@@ -370,7 +381,7 @@ inline Eval fill_route(const Input& input,
370381

371382
Eval current_eval;
372383
if (pickup_r == delivery_r) {
373-
current_eval = utils::addition_cost(input,
384+
current_eval = utils::addition_eval(input,
374385
job_rank,
375386
vehicle,
376387
route.route,

src/algorithms/local_search/insertion_search.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ compute_best_insertion_single(const Input& input,
4444
rank < sol_state.insertion_ranks_end[v][j];
4545
++rank) {
4646
const Eval current_eval =
47-
utils::addition_cost(input, j, v_target, route.route, rank);
47+
utils::addition_eval(input, j, v_target, route.route, rank);
4848
if (current_eval.cost < result.eval.cost &&
4949
v_target.ok_for_range_bounds(sol_state.route_evals[v] +
5050
current_eval) &&
@@ -113,7 +113,7 @@ RouteInsertion compute_best_insertion_pd(const Input& input,
113113
bool found_valid = false;
114114
for (unsigned d_rank = begin_d_rank; d_rank < end_d_rank; ++d_rank) {
115115
d_adds[d_rank] =
116-
utils::addition_cost(input, j + 1, v_target, route.route, d_rank);
116+
utils::addition_eval(input, j + 1, v_target, route.route, d_rank);
117117
if (result.eval < d_adds[d_rank]) {
118118
valid_delivery_insertions[d_rank] = false;
119119
} else {
@@ -132,7 +132,7 @@ RouteInsertion compute_best_insertion_pd(const Input& input,
132132
pickup_r < sol_state.insertion_ranks_end[v][j];
133133
++pickup_r) {
134134
const Eval p_add =
135-
utils::addition_cost(input, j, v_target, route.route, pickup_r);
135+
utils::addition_eval(input, j, v_target, route.route, pickup_r);
136136
if (result.eval < p_add) {
137137
// Even without delivery insertion more expensive than current best.
138138
continue;
@@ -173,7 +173,7 @@ RouteInsertion compute_best_insertion_pd(const Input& input,
173173

174174
Eval pd_eval;
175175
if (pickup_r == delivery_r) {
176-
pd_eval = utils::addition_cost(input,
176+
pd_eval = utils::addition_eval(input,
177177
j,
178178
v_target,
179179
route.route,

0 commit comments

Comments
 (0)