PGROUTING  3.2
vehicle.cpp
Go to the documentation of this file.
1 /*PGR-GNU*****************************************************************
2 
3 FILE: vehicle.cpp
4 
5 Copyright (c) 2015 pgRouting developers
7 
8 ------
9 
10 This program is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
14 
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19 
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
23 
24  ********************************************************************PGR-GNU*/
25 
26 #include "vrp/vehicle.h"
27 
28 #include <deque>
29 #include <iostream>
30 #include <algorithm>
31 #include <tuple>
32 #include <limits>
33 #include <string>
34 #include <utility>
35 #include <vector>
36 
37 #include "cpp_common/pgr_assert.h"
38 
39 #include "vrp/pgr_pickDeliver.h"
40 
41 
42 namespace pgrouting {
43 namespace vrp {
44 
45 Pgr_pickDeliver* Vehicle::problem;
46 
50 Pgr_messages&
52  return problem->msg;
53 }
54 
55 void
57  pgassert(m_path.size() >= 2);
58  pgassert(m_path.front().is_start());
59  pgassert(m_path.back().is_end());
60 }
61 
62 size_t
63 Vehicle::insert(std::pair<POS, POS> position_limits, const Vehicle_node &node) {
64  invariant();
65  pgassert(position_limits.first <= m_path.size());
66  pgassert(position_limits.second <= m_path.size());
67 
68  auto low = position_limits.first;
69  auto high = position_limits.second;
70  auto best = low;
71 
72 
73  insert(low, node);
74 
75  Vehicle::Cost best_cost(cost());
76 
77 
78  while (low < high) {
79  swap(low, low + 1);
80  ++low;
81  if (cost_compare(best_cost, cost())) {
82  best_cost = cost();
83  best = low;
84  }
85  }
86  return best;
87 
88  pgassert(best < m_path.size());
89  pgassert(m_path[best].idx() == node.idx());
90  invariant();
91 }
92 
93 
94 
95 
96 bool
97 Vehicle::cost_compare(const Cost &lhs, const Cost &rhs) const {
98  /*
99  * capacity violations
100  */
101  if (std::get<1>(lhs) < std::get<1>(rhs))
102  return true;
103  if (std::get<1>(lhs) > std::get<1>(rhs))
104  return false;
105 
106  /*
107  * time window violations
108  */
109  if (std::get<0>(lhs) < std::get<0>(rhs))
110  return true;
111  if (std::get<0>(lhs) > std::get<0>(rhs))
112  return false;
113 
114  /*
115  * waiting time
116  */
117  if (std::get<3>(lhs) < std::get<3>(rhs))
118  return true;
119  if (std::get<3>(lhs) > std::get<3>(rhs))
120  return false;
121 
122  /*
123  * duration
124  */
125  if (std::get<4>(lhs) < std::get<4>(rhs))
126  return true;
127  if (std::get<4>(lhs) > std::get<4>(rhs))
128  return false;
129 
130  /*
131  * truck size
132  */
133  if (std::get<2>(lhs) < std::get<2>(rhs))
134  return true;
135  if (std::get<2>(lhs) > std::get<2>(rhs))
136  return false;
137 
138  return false;
139 }
140 
141 
142 
143 std::vector<General_vehicle_orders_t>
145  int vid) const {
146  std::vector<General_vehicle_orders_t> result;
147  /* postgres numbering starts with 1 */
148  int stop_seq(1);
149  msg().log << "getting solution: " << tau() << "\n";
150  for (const auto &p_stop : m_path) {
151  General_vehicle_orders_t data = {
152  vid,
153  id(),
154  stop_seq,
155  /* order_id
156  * The order_id is invalid for stops type 0 and 5
157  */
158  (p_stop.type() == 0 || p_stop.type() == 5)? -1 : p_stop.order(),
159  p_stop.id(),
160  p_stop.type(),
161  p_stop.cargo(),
162  p_stop.travel_time(),
163  p_stop.arrival_time(),
164  p_stop.wait_time(),
165  p_stop.service_time(),
166  p_stop.departure_time()};
167  result.push_back(data);
168  ++stop_seq;
169  }
170  return result;
171 }
172 
173 
175 Vehicle::cost() const {
176  return std::make_tuple(
177  twvTot(), cvTot(), m_path.size(),
179 }
180 
181 
182 void
184  invariant();
185  pgassert(at <= m_path.size());
186 
187  m_path.insert(m_path.begin() + static_cast<difference_type>(at), node);
188  evaluate(at);
189 
190  pgassert(at < m_path.size());
191  pgassert(m_path[at].idx() == node.idx());
192  invariant();
193 }
194 
195 
196 
197 void
199  invariant();
200 
201  POS pos = 0;
202  for ( ; pos < m_path.size() ; ++pos) {
203  if (node.idx() == m_path[pos].idx())
204  break;
205  }
206 
207  erase(pos);
209  evaluate(pos);
210 
211  invariant();
212 }
213 
214 
215 
216 
217 
218 void
220  invariant();
221 
222  pgassert(m_path.size() > 2);
223  pgassert(at < m_path.size());
224  pgassert(!m_path[at].is_start());
225  pgassert(!m_path[at].is_end());
226 
227  m_path.erase(m_path.begin() + static_cast<difference_type>(at));
228  evaluate(at);
229 
230  invariant();
231 }
232 
233 void
235  invariant();
236  pgassert(m_path.size() > 3);
237  pgassert(!m_path[i].is_start());
238  pgassert(!m_path[i].is_end());
239  pgassert(!m_path[j].is_start());
240  pgassert(!m_path[j].is_end());
241 
242  std::swap(m_path[i], m_path[j]);
243  i < j ? evaluate(i) : evaluate(j);
244 
245  invariant();
246 }
247 
248 
249 void
251  invariant();
252 
253  evaluate(0);
254 
255  invariant();
256 }
257 
258 bool
259 Vehicle::empty() const {
260  invariant();
261  return m_path.size() <= 2;
262 }
263 
264 size_t
265 Vehicle::size() const {
266  invariant();
267  return m_path.size() - 2;
268 }
269 
270 void
272  invariant();
273  // preconditions
274  pgassert(from < m_path.size());
275 
276 
277  auto node = m_path.begin() + static_cast<difference_type>(from);
278 
279  while (node != m_path.end()) {
280  if (node == m_path.begin()) {
281  node->evaluate(m_capacity);
282  } else {
283  node->evaluate(*(node - 1), m_capacity, speed());
284  }
285 
286  ++node;
287  }
288  invariant();
289 }
290 
291 std::deque< Vehicle_node >
292 Vehicle::path() const {
293  invariant();
294  return m_path;
295 }
296 
297 
298 std::pair<size_t, size_t>
300  POS high = getPosHighLimit(node);
301  POS low = getPosLowLimit(node);
302  return std::make_pair(low, high);
303 }
304 
305 std::pair<size_t, size_t>
307  POS high = getPosHighLimit(node);
308  POS low = getDropPosLowLimit(node);
309  return std::make_pair(low, high);
310 }
311 
312 /*
313  * start searching from postition low = pos(E)
314  *
315  * S 1 2 3 4 5 6 7 ..... E
316  * node -> E
317  * node -> ...
318  * node -> 7
319  * node -> 6
320  * node -> 5
321  * node /-> 4
322  *
323  * return low_limit = 5
324  *
325  */
326 size_t
328  invariant();
329 
330  POS low = 0;
331  POS high = m_path.size();
332  POS low_limit = high;
333 
334  /* J == m_path[low_limit - 1] */
335  while (low_limit > low
336  && m_path[low_limit - 1].is_compatible_IJ(nodeI, speed())
337  && !m_path[low_limit - 1].is_pickup()) {
338  --low_limit;
339  }
340 
341  invariant();
342  return low_limit;
343 }
344 
345 /*
346  * start searching from postition low = pos(E)
347  *
348  * S 1 2 3 4 5 6 7 ..... E
349  * node -> E
350  * node -> ...
351  * node -> 7
352  * node -> 6
353  * node -> 5
354  * node /-> 4
355  *
356  * return low_limit = 5
357  *
358  */
359 size_t
361  invariant();
362 
363  POS low = 0;
364  POS high = m_path.size();
365  POS low_limit = high;
366 
367  /* J == m_path[low_limit - 1] */
368  while (low_limit > low
369  && m_path[low_limit - 1].is_compatible_IJ(nodeI, speed())) {
370  --low_limit;
371  }
372 
373  invariant();
374  return low_limit;
375 }
376 
377 
378 /*
379  * start searching from postition low = pos(S)
380  *
381  * S 1 2 3 4 5 6 7 ..... E
382  * S -> node
383  * 1 -> node
384  * 2 -> node
385  * ...
386  * 6 -> node
387  * 7 /-> node
388  *
389  * returns high_limit = 7
390  */
391 size_t
393  invariant();
394 
395  POS low = 0;
396  POS high = m_path.size();
397  POS high_limit = low;
398 
399  /* I == m_path[high_limit] */
400  while (high_limit < high
401  && nodeJ.is_compatible_IJ(m_path[high_limit], speed())) {
402  ++high_limit;
403  }
404 
405  invariant();
406  return high_limit;
407 }
408 
409 bool
410 Vehicle::is_ok() const {
411  pgassert((m_path.front().opens() <= m_path.front().closes())
412  && (m_path.back().opens() <= m_path.back().closes())
413  && (m_capacity > 0));
414  return (start_site().opens() <= start_site().closes())
415  && (end_site().opens() <= end_site().closes())
416  && (m_capacity > 0);
417 }
418 
420  size_t p_idx,
421  int64_t p_id,
422  const Vehicle_node &starting_site,
423  const Vehicle_node &ending_site,
424  double p_m_capacity,
425  double p_speed,
426  double p_factor) :
427  Identifier(p_idx, p_id),
428  m_capacity(p_m_capacity),
429  m_factor(p_factor),
430  m_speed(p_speed) {
431 #if 0
432  ENTERING();
433 #endif
434  m_path.clear();
435  pgassert(starting_site.opens() <= starting_site.closes());
436  pgassert(ending_site.opens() <= ending_site.closes());
437  pgassert(capacity() > 0);
438 #if 0
439  msg().log << "p_idx: " << p_idx << "\t idx(): " << idx() << "\n";
440  msg().log << "p_id: " << p_id << "\tid(): " << id() << "\n";
441 #endif
442 
443  m_path.push_back(starting_site);
444  m_path.push_back(ending_site);
445 
446  evaluate(0);
447  msg().log << tau() << "\n";
448  invariant();
449 #if 0
450  EXITING();
451 #endif
452  }
453 
454 
455 
456 std::string
457 Vehicle::tau() const {
458  pgassert(m_path.size() > 1);
459  std::ostringstream log;
460  log << "Truck " << id() << "(" << idx() << ")"
461  << " (";
462  for (const auto &p_stop : m_path) {
463  if (!(p_stop == m_path.front()))
464  log << ", ";
465  log << p_stop.id();
466  }
467  log << ")" << " \t(cv, twv, wait_time, duration) = ("
468  << cvTot() << ", "
469  << twvTot() << ", "
470  << total_wait_time() << ", "
471  << duration() << ")";
472 
473  return log.str();
474 }
475 
476 double
477 Vehicle::speed() const {
478  return m_speed/m_factor;
479 }
480 
481 /****** FRIENDS *******/
482 
483 std::ostream&
484 operator << (std::ostream &log, const Vehicle &v) {
485  v.invariant();
486  int i(0);
487  log << "\n\n****************** " << v.idx() << "th VEHICLE*************\n";
488  log << "id = " << v.id()
489  << "\tcapacity = " << v.m_capacity
490  << "\tfactor = " << v.m_factor << "\n"
491  << "\tspeed = " << v.m_speed << "\n"
492  << "\tnew speed = " << v.speed() << "\n";
493 
494  for (const auto &path_stop : v.path()) {
495  log << "Path_stop" << ++i << "\n";
496  log << path_stop << "\n";
497  }
498  return log;
499 }
500 
501 bool
502 operator<(const Vehicle &lhs, const Vehicle &rhs) {
503  lhs.invariant();
504  rhs.invariant();
505 
506  if (lhs.m_path.size() < rhs.m_path.size()) return true;
507 
508  /* here because sizes are equal */
509 
510  if (lhs.m_path.back().total_travel_time()
511  < rhs.m_path.back().total_travel_time()) return true;
512 
513  return false;
514 }
515 
516 } // namespace vrp
517 } // namespace pgrouting
518 
pgrouting::vrp::Vehicle::m_path
std::deque< Vehicle_node > m_path
Definition: vehicle.h:77
pgr_pickDeliver.h
pgrouting::vrp::Vehicle::getPosHighLimit
POS getPosHighLimit(const Vehicle_node &node) const
Definition: vehicle.cpp:392
pgrouting::vrp::Vehicle::speed
double speed() const
Definition: vehicle.cpp:477
pgrouting::vrp::Vehicle::is_ok
bool is_ok() const
Definition: vehicle.cpp:410
EXITING
#define EXITING(x)
Definition: pgr_messages.h:94
pgrouting::vrp::Vehicle::cost
Cost cost() const
Definition: vehicle.cpp:175
pgrouting::vrp::Vehicle::m_capacity
double m_capacity
Definition: vehicle.h:82
pgrouting::vrp::Vehicle::cvTot
int cvTot() const
Definition: vehicle.h:216
pgrouting::vrp::Vehicle::get_postgres_result
std::vector< General_vehicle_orders_t > get_postgres_result(int vid) const
Definition: vehicle.cpp:144
pgrouting::vrp::Vehicle::duration
double duration() const
Definition: vehicle.h:201
ENTERING
#define ENTERING(x)
Definition: pgr_messages.h:93
pgrouting::vrp::Vehicle_node
Extend Tw_node to evaluate the vehicle at node level.
Definition: vehicle_node.h:48
pgrouting::vrp::Vehicle::size
size_t size() const
return number of nodes in the truck
Definition: vehicle.cpp:265
pgrouting::vrp::operator<<
std::ostream & operator<<(std::ostream &log, const Swap_info &d)
Definition: book_keeping.cpp:47
pgrouting::Pgr_messages::log
std::ostringstream log
Stores the hint information.
Definition: pgr_messages.h:81
pgrouting::vrp::Pgr_pickDeliver::msg
Pgr_messages msg
message controller for all classes
Definition: pgr_pickDeliver.h:99
pgrouting::vrp::Tw_node::is_compatible_IJ
bool is_compatible_IJ(const Tw_node &I, double speed) const
Definition: tw_node.cpp:60
pgrouting::vrp::Vehicle::getDropPosLowLimit
POS getDropPosLowLimit(const Vehicle_node &node) const
Definition: vehicle.cpp:327
pgrouting::vrp::Vehicle::m_speed
double m_speed
Definition: vehicle.h:84
pgassert
#define pgassert(expr)
Uses the standard assert syntax.
Definition: pgr_assert.h:94
pgrouting::vrp::Vehicle::getPosLowLimit
POS getPosLowLimit(const Vehicle_node &node) const
Definition: vehicle.cpp:360
pgrouting::Identifier::idx
size_t idx() const
Definition: identifier.cpp:37
pgrouting::vrp::Vehicle::m_factor
double m_factor
Definition: vehicle.h:83
pgrouting::vrp::Vehicle::path
std::deque< Vehicle_node > path() const
@ {
Definition: vehicle.cpp:292
pgrouting::vrp::Vehicle
Vehicle with time windows.
Definition: vehicle.h:73
pgrouting::vrp::Vehicle::twvTot
int twvTot() const
Definition: vehicle.h:213
pgrouting::vrp::Vehicle::evaluate
void evaluate()
@ {
Definition: vehicle.cpp:250
pgrouting::vrp::Vehicle::POS
size_t POS
Definition: vehicle.h:75
pgrouting::Identifier::id
int64_t id() const
Definition: identifier.cpp:42
pgrouting::vrp::Vehicle::end_site
Vehicle_node end_site() const
Definition: vehicle.h:235
pgrouting::vrp::Tw_node::closes
double closes() const
Returns the closing time.
Definition: tw_node.h:79
pgrouting::vrp::Vehicle::capacity
double capacity() const
Definition: vehicle.h:238
pgr_assert.h
An assert functionality that uses C++ throw().
pgrouting::vrp::operator<
bool operator<(const Vehicle &lhs, const Vehicle &rhs)
Definition: vehicle.cpp:502
pgrouting::vrp::Vehicle::difference_type
std::deque< Vehicle_node >::difference_type difference_type
Definition: vehicle.h:76
General_vehicle_orders_t
Definition: general_vehicle_orders_t.h:49
pgrouting::vrp::Vehicle::drop_position_limits
std::pair< POS, POS > drop_position_limits(const Vehicle_node node) const
Definition: vehicle.cpp:306
pgrouting::vrp::Vehicle::invariant
void invariant() const
Invariant The path must:
Definition: vehicle.cpp:56
vehicle.h
pgrouting::vrp::Tw_node::opens
double opens() const
Returns the opening time.
Definition: tw_node.h:76
pgrouting::Identifier
Definition: identifier.h:39
pgrouting::vrp::Vehicle::position_limits
std::pair< POS, POS > position_limits(const Vehicle_node node) const
Definition: vehicle.cpp:299
pgrouting::vrp::Vehicle::total_wait_time
double total_wait_time() const
Definition: vehicle.h:204
pgrouting::vrp::Vehicle::empty
bool empty() const
return true when no nodes are in the truck
Definition: vehicle.cpp:259
pgrouting::vrp::Vehicle::problem
static Pgr_pickDeliver * problem
Pointer to problem.
Definition: vehicle.h:315
pgrouting::vrp::Vehicle::start_site
Vehicle_node start_site() const
Definition: vehicle.h:232
pgrouting::vrp::Vehicle::Vehicle
Vehicle(const Vehicle &)=default
pgrouting::vrp::Vehicle::cost_compare
bool cost_compare(const Cost &, const Cost &) const
Definition: vehicle.cpp:97
pgrouting::vrp::Vehicle::insert
void insert(POS pos, Vehicle_node node)
@ {
Definition: vehicle.cpp:183
pgrouting::vrp::Vehicle::Cost
std::tuple< int, int, size_t, double, double > Cost
Definition: vehicle.h:90
pgrouting
Book keeping class for swapping orders between vehicles.
Definition: pgr_alphaShape.cpp:56
pgrouting::vrp::Vehicle::swap
void swap(POS i, POS j)
Swap two nodes in the path.
Definition: vehicle.cpp:234
pgrouting::vrp::Vehicle::msg
static Pgr_messages & msg()
Access to the problem's message.
Definition: vehicle.cpp:51
pgrouting::vrp::Vehicle::erase
void erase(const Vehicle_node &node)
Erase node.id()
Definition: vehicle.cpp:198
pgrouting::vrp::Vehicle::tau
std::string tau() const
Definition: vehicle.cpp:457