PGROUTING  3.2
vehicle_pickDeliver.cpp
Go to the documentation of this file.
1 /*PGR-GNU*****************************************************************
2 
3 FILE: vehicle_pickDeliver.cpp
4 
5 Copyright (c) 2016 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 
27 
28 #include <iostream>
29 #include <deque>
30 #include <set>
31 #include <string>
32 #include <sstream>
33 #include <limits>
34 
35 
36 #include "cpp_common/pgr_assert.h"
37 #include "vrp/order.h"
38 #include "vrp/vehicle.h"
39 #include "vrp/pgr_pickDeliver.h"
40 
41 
42 
43 namespace pgrouting {
44 namespace vrp {
45 
46 
47 
49  size_t idx,
50  int64_t id,
51  const Vehicle_node &starting_site,
52  const Vehicle_node &ending_site,
53  double p_capacity,
54  double p_speed,
55  double factor) :
56  Vehicle(idx, id, starting_site, ending_site, p_capacity, p_speed, factor),
57  cost((std::numeric_limits<double>::max)()),
58  m_orders_in_vehicle(),
59  m_orders(),
60  m_feasable_orders() {
61 #if 0
62  ENTERING();
63 #endif
64  invariant();
65 #if 0
66  EXITING();
67 #endif
68  }
69 
70 
71 
72 bool
74  return m_orders_in_vehicle.has(order.idx());
75 }
76 
77 
78 bool
80  invariant();
81  pgassert(!has_order(order));
82 
83  auto pick_pos(position_limits(order.pickup()));
84  auto deliver_pos(position_limits(order.delivery()));
85 #ifndef NDEBUG
86  std::ostringstream err_log;
87  err_log << "\n\tpickup limits (low, high) = ("
88  << pick_pos.first << ", "
89  << pick_pos.second << ") "
90  << "\n\tdeliver limits (low, high) = ("
91  << deliver_pos.first << ", "
92  << deliver_pos.second << ") "
93  << "\noriginal" << tau();
94 #endif
95 
96  if (pick_pos.second < pick_pos.first) {
97  /*
98  * pickup generates twv evrywhere
99  */
100  return false;
101  }
102 
103  if (deliver_pos.second < deliver_pos.first) {
104  /*
105  * delivery generates twv evrywhere
106  */
107  return false;
108  }
109  /*
110  * Because delivery positions were estimated without
111  * the pickup:
112  * - increase the upper limit position estimation
113  */
114  ++deliver_pos.first;
115  ++deliver_pos.second;
116 
117 
118  auto d_pos_backup(deliver_pos);
119  auto best_pick_pos = m_path.size();
120  auto best_deliver_pos = m_path.size() + 1;
121  auto current_duration(duration());
122  auto min_delta_duration = (std::numeric_limits<double>::max)();
123  auto found(false);
124  pgassertwm(!has_order(order), err_log.str());
125  while (pick_pos.first <= pick_pos.second) {
126 #ifndef NDEBUG
127  err_log << "\n\tpickup cycle limits (low, high) = ("
128  << pick_pos.first << ", "
129  << pick_pos.second << ") ";
130 #endif
131  Vehicle::insert(pick_pos.first, order.pickup());
132 #ifndef NDEBUG
133  err_log << "\npickup inserted: " << tau();
134 #endif
135 
136  if (deliver_pos.first <= pick_pos.first) deliver_pos.first = pick_pos.first + 1;
137 
138  while (deliver_pos.first <= deliver_pos.second) {
139  Vehicle::insert(deliver_pos.first, order.delivery());
140  m_orders_in_vehicle += order.idx();
141  pgassertwm(has_order(order), err_log.str());
142 #ifndef NDEBUG
143  err_log << "\ndelivery inserted: " << tau();
144 #endif
145  if (is_feasable()) {
147  auto delta_duration = duration() - current_duration;
148  if (delta_duration < min_delta_duration) {
149 #ifndef NDEBUG
150  err_log << "\nsuccess" << tau();
151 #endif
152  min_delta_duration = delta_duration;
153  best_pick_pos = pick_pos.first;
154  best_deliver_pos = deliver_pos.first;
155  found = true;
156  }
157  }
158  Vehicle::erase(deliver_pos.first);
159 #ifndef NDEBUG
160  err_log << "\ndelivery erased: " << tau();
161 #endif
162  ++deliver_pos.first;
163  }
164  Vehicle::erase(pick_pos.first);
165 #ifndef NDEBUG
166  err_log << "\npickup erased: " << tau();
167 #endif
168  m_orders_in_vehicle -= order.idx();
169  pgassertwm(!has_order(order), err_log.str());
170 
171  deliver_pos = d_pos_backup;
172 #ifndef NDEBUG
173  err_log << "\n\trestoring deliver limits (low, high) = ("
174  << deliver_pos.first << ", "
175  << deliver_pos.second << ") ";
176 #endif
177  ++pick_pos.first;
178  }
179  pgassertwm(!has_order(order), err_log.str());
180  if (!found) {
181  /* order causes twv or cv */
182  return false;
183  }
184  Vehicle::insert(best_pick_pos, order.pickup());
185  Vehicle::insert(best_deliver_pos, order.delivery());
186 
187  m_orders_in_vehicle += order.idx();
188  pgassertwm(is_feasable(), err_log.str());
189  pgassertwm(has_order(order), err_log.str());
190  pgassertwm(!has_cv(), err_log.str());
191  invariant();
192  return true;
193 }
194 
195 
196 void
198  invariant();
199  pgassert(!has_order(order));
200 
201  m_orders_in_vehicle += order.idx();
202  m_path.insert(m_path.end() - 1, order.pickup());
203  m_path.insert(m_path.end() - 1, order.delivery());
204  evaluate(m_path.size() - 3);
205 
206  pgassert(has_order(order));
207  invariant();
208 }
209 
210 
211 void
213  invariant();
214  pgassert(!has_order(order));
215 
216  m_orders_in_vehicle += order.idx();
217  m_path.insert(m_path.begin() + 1, order.delivery());
218  m_path.insert(m_path.begin() + 1, order.pickup());
219  evaluate(1);
220 
221  pgassert(has_order(order));
222  invariant();
223 }
224 
225 
226 void
228  Initials_code kind,
229  Identifiers<size_t> &unassigned,
230  Identifiers<size_t> &assigned) {
232 #if 0
233  msg.log << "unasigned" << unassigned << "\n";
234  msg.log << "m_feasable_orders" << m_feasable_orders << "\n";
235 #endif
236  auto current_feasable = m_feasable_orders * unassigned;
237 
238  while (!current_feasable.empty()) {
239 #if 0
240  msg.log << "current_feasable" << current_feasable << "\n";
241 #endif
242  auto order = m_orders[current_feasable.front()];
243 
244  switch (kind) {
245  case OnePerTruck:
246  push_back(order);
248  assigned += order.idx();
249  unassigned -= order.idx();
250  invariant();
251  return;
252  break;
253  case FrontTruck:
254  push_front(order);
255  break;
256  case BackTruck:
257  push_back(order);
258  break;
259  case BestInsert:
260  insert(order);
261  break;
262  case BestBack:
263  order = m_orders[m_orders.find_best_J(current_feasable)];
264  insert(order);
265  break;
266  case BestFront:
267  order = m_orders[m_orders.find_best_I(current_feasable)];
268  insert(order);
269  break;
270  case OneDepot:
271  semiLIFO(order);
272  break;
273  default: pgassert(false);
274  }
275 
276  if (orders_size() == 1 && !is_feasable()) {
277  pgassert(false);
278  }
279 
280  if (!is_feasable()) {
281  erase(order);
282  } else if (has_order(order)) {
283  assigned += order.idx();
284  unassigned -= order.idx();
285  if (kind == BestBack) {
286  current_feasable = m_orders[order.idx()].subsetJ(
287  current_feasable);
288  }
289  if (kind == BestFront) {
290  current_feasable = m_orders[order.idx()].subsetI(
291  current_feasable);
292  }
293  }
294 
295  current_feasable -= order.idx();
296  invariant();
297  }
298 
300  invariant();
301 }
302 
303 
304 void
306  invariant();
307  pgassert(has_order(order));
308 
309 
310  Vehicle::erase(order.pickup());
311  Vehicle::erase(order.delivery());
312  m_orders_in_vehicle -= order.idx();
313 
314  invariant();
315  pgassert(!has_order(order));
316 }
317 
318 
319 
320 
321 void
323  m_orders = orders;
324  for (const auto &o : orders) {
325  if (is_order_feasable(o)) m_feasable_orders += o.idx();
326  }
328 }
329 
330 bool
332  auto test_truck = *this;
333  test_truck.push_back(order);
334  return test_truck.is_feasable();
335 }
336 
337 bool
339  invariant();
340  pgassert(!has_order(order));
341 
342  /*
343  * Insert pick up as first picked
344  */
345  Vehicle::insert(1, order.pickup());
346 
347  auto deliver_pos(drop_position_limits(order.delivery()));
348 
349  /*
350  * delivery generates twv in all positions
351  */
352  if (deliver_pos.second < deliver_pos.first) {
353  /*
354  * Remove inserted pickup
355  */
356  Vehicle::erase(1);
357  invariant();
358  return false;
359  }
360 
361  pgassert(!has_order(order));
362 
363  while (deliver_pos.first <= deliver_pos.second) {
364  Vehicle::insert(deliver_pos.second, order.delivery());
365 
366  if (is_feasable() && !m_path[deliver_pos.second + 1].is_pickup()) {
367  /*
368  * Found a position to insert the delivery
369  */
370 
371 
372  m_orders_in_vehicle += order.idx();
373 
374  /*
375  * There is one more order in the vehicle
376  */
377  pgassert(has_order(order));
379  pgassert(!has_cv());
380  pgassert(!has_twv());
381  pgassert(has_order(order));
382  invariant();
383  return true;
384  }
385 
386  /*
387  * This position in path is not suitable
388  */
389  Vehicle::erase(deliver_pos.second);
390 
391  /*
392  * got to next position
393  */
394  --deliver_pos.second;
395  }
396 
397  /*
398  * Order could not be inserted
399  */
400  Vehicle::erase(1);
401 
402  pgassert(!has_order(order));
403  invariant();
404  return false;
405 }
406 
407 } // namespace vrp
408 } // namespace pgrouting
409 
410 
pgrouting::vrp::Vehicle::m_path
std::deque< Vehicle_node > m_path
Definition: vehicle.h:77
pgr_pickDeliver.h
pgrouting::vrp::Vehicle::speed
double speed() const
Definition: vehicle.cpp:477
pgrouting::vrp::Vehicle_pickDeliver::m_orders_in_vehicle
Identifiers< size_t > m_orders_in_vehicle
orders inserted in this vehicle
Definition: vehicle_pickDeliver.h:51
EXITING
#define EXITING(x)
Definition: pgr_messages.h:94
pgrouting::vrp::Vehicle_pickDeliver::erase
void erase(const Order &order)
Definition: vehicle_pickDeliver.cpp:305
pgrouting::vrp::Vehicle_pickDeliver::orders
const PD_Orders & orders() const
Definition: vehicle_pickDeliver.h:77
pgrouting::vrp::BestInsert
@ BestInsert
Insetion at the back of the truck.
Definition: initials_code.h:41
pgrouting::vrp::OnePerTruck
@ OnePerTruck
All orders in one truck.
Definition: initials_code.h:38
pgrouting::vrp::Vehicle::duration
double duration() const
Definition: vehicle.h:201
pgrouting::vrp::Vehicle_pickDeliver::push_back
void push_back(const Order &order)
puts an order at the end of the truck
Definition: vehicle_pickDeliver.cpp:197
pgrouting::vrp::Vehicle_pickDeliver::semiLIFO
bool semiLIFO(const Order &order)
Inserts an order In semi-Lifo order.
Definition: vehicle_pickDeliver.cpp:338
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_pickDeliver::m_orders
PD_Orders m_orders
Definition: vehicle_pickDeliver.h:52
pgassertwm
#define pgassertwm(expr, msg)
Adds a message to the assertion.
Definition: pgr_assert.h:117
pgrouting::vrp::Vehicle_pickDeliver::push_front
void push_front(const Order &order)
Puts an order at the end front of the truck.
Definition: vehicle_pickDeliver.cpp:212
pgrouting::Pgr_messages::log
std::ostringstream log
Stores the hint information.
Definition: pgr_messages.h:81
pgrouting::vrp::Vehicle::is_feasable
bool is_feasable() const
Definition: vehicle.h:226
pgrouting::vrp::BackTruck
@ BackTruck
Insetion at the front of the truck.
Definition: initials_code.h:40
pgassert
#define pgassert(expr)
Uses the standard assert syntax.
Definition: pgr_assert.h:94
pgrouting::Identifier::idx
size_t idx() const
Definition: identifier.cpp:37
pgrouting::vrp::Vehicle_pickDeliver::m_feasable_orders
Identifiers< size_t > m_feasable_orders
orders that fit in the truck
Definition: vehicle_pickDeliver.h:54
pgrouting::vrp::Vehicle::has_cv
bool has_cv() const
Definition: vehicle.h:222
pgrouting::vrp::OneDepot
@ OneDepot
Push front order that allows more orders to be inserted at the front.
Definition: initials_code.h:44
pgrouting::vrp::Vehicle_pickDeliver::set_compatibles
void set_compatibles(const PD_Orders &orders)
Definition: vehicle_pickDeliver.cpp:322
pgrouting::vrp::Vehicle
Vehicle with time windows.
Definition: vehicle.h:73
pgrouting::vrp::Vehicle::evaluate
void evaluate()
@ {
Definition: vehicle.cpp:250
pgrouting::vrp::PD_Orders::find_best_J
size_t find_best_J(Identifiers< size_t > &within_this_set) const
Definition: pd_orders.cpp:125
pgrouting::vrp::Vehicle_pickDeliver::is_order_feasable
bool is_order_feasable(const Order &order) const
Definition: vehicle_pickDeliver.cpp:331
pgr_assert.h
An assert functionality that uses C++ throw().
pgrouting::vrp::Order::pickup
const Vehicle_node & pickup() const
The delivery node identifier.
Definition: order.cpp:88
pgrouting::vrp::Vehicle_pickDeliver::orders_size
size_t orders_size() const
Definition: vehicle_pickDeliver.h:78
pgrouting::vrp::BestBack
@ BestBack
Best place to insert Order.
Definition: initials_code.h:42
vehicle_pickDeliver.h
pgrouting::vrp::Vehicle::drop_position_limits
std::pair< POS, POS > drop_position_limits(const Vehicle_node node) const
Definition: vehicle.cpp:306
pgrouting::vrp::Order::delivery
const Vehicle_node & delivery() const
The delivery node identifier.
Definition: order.cpp:82
pgrouting::vrp::Order
Definition: order.h:42
pgrouting::vrp::Vehicle::invariant
void invariant() const
Invariant The path must:
Definition: vehicle.cpp:56
vehicle.h
Identifiers::has
bool has(const T other) const
true ids() has element
Definition: identifiers.hpp:98
pgrouting::vrp::Vehicle_pickDeliver::insert
bool insert(const Order &order)
Inserts an order.
Definition: vehicle_pickDeliver.cpp:79
pgrouting::vrp::Vehicle::position_limits
std::pair< POS, POS > position_limits(const Vehicle_node node) const
Definition: vehicle.cpp:299
pgrouting::vrp::FrontTruck
@ FrontTruck
One Order per truck.
Definition: initials_code.h:39
pgrouting::vrp::PD_Orders
Definition: pd_orders.h:48
pgrouting::vrp::BestFront
@ BestFront
Push back order that allows more orders to be inserted at the back.
Definition: initials_code.h:43
order.h
pgrouting::vrp::Vehicle_pickDeliver::has_order
bool has_order(const Order &order) const
Definition: vehicle_pickDeliver.cpp:73
pgrouting::vrp::PD_Orders::set_compatibles
void set_compatibles(double speed)
Definition: pd_orders.cpp:116
pgrouting::vrp::Vehicle::has_twv
bool has_twv() const
Definition: vehicle.h:219
pgrouting::vrp::PD_Orders::find_best_I
size_t find_best_I(Identifiers< size_t > &within_this_set) const
Definition: pd_orders.cpp:144
pgrouting::vrp::Vehicle_pickDeliver::Vehicle_pickDeliver
Vehicle_pickDeliver(size_t idx, int64_t id, const Vehicle_node &starting_site, const Vehicle_node &ending_site, double p_capacity, double p_speed, double factor)
Definition: vehicle_pickDeliver.cpp:48
pgrouting::vrp::Initials_code
Initials_code
Different kinds to insert an order into the vehicle.
Definition: initials_code.h:36
pgrouting::vrp::Vehicle::insert
void insert(POS pos, Vehicle_node node)
@ {
Definition: vehicle.cpp:183
pgrouting
Book keeping class for swapping orders between vehicles.
Definition: pgr_alphaShape.cpp:56
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
Identifiers< size_t >
pgrouting::vrp::Vehicle_pickDeliver::do_while_feasable
void do_while_feasable(Initials_code kind, Identifiers< size_t > &unassigned, Identifiers< size_t > &assigned)
Definition: vehicle_pickDeliver.cpp:227
pgrouting::vrp::Vehicle::tau
std::string tau() const
Definition: vehicle.cpp:457