PGROUTING  2.4
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
VRP.c
Go to the documentation of this file.
1 /*PGR-GNU*****************************************************************
2 
3 Copyright (c) 2013 Khondoker Md. Razequl Islam
4 ziboncsedu@gmail.com
5 
6 ------
7 
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12 
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17 
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 
22 ********************************************************************PGR-GNU*/
23 
24 #include "./../../common/src/postgres_connection.h"
25 #include "catalog/pg_type.h"
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <search.h>
29 #include <string.h>
30 // #include <math.h>
31 
32 
33 #include "./VRP.h"
34 
35 
36 
37 
38 #include "./../../common/src/pgr_types.h"
39 
40 #undef qsort
41 
42 // -------------------------------------------------------------------------
43 
44 /*
45  * Define this to have profiling enabled
46  */
47 // #define PROFILE
48 
49 #ifdef PROFILE
50 #include <sys/time.h>
51 
52 struct timeval prof_astar, prof_store, prof_extract, prof_total;
53 int64_t proftime[5];
54 int64_t profipts1, profipts2, profopts;
55 
56 #define profstart(x) do { gettimeofday(&x, NULL); } while (0);
57 #define profstop(n, x) do { struct timeval _profstop; \
58  int64_t _proftime; \
59  gettimeofday(&_profstop, NULL); \
60  _proftime = (_profstop.tv_sec*1000000+_profstop.tv_usec) - \
61  (x.tv_sec*1000000+x.tv_usec); \
62  elog(NOTICE, \
63  "PRF(%s) %lu (%f ms)", \
64  (n), \
65  _proftime, _proftime / 1000.0); \
66 } while (0);
67 
68 #else
69 
70 #define profstart(x) do { } while (0);
71 #define profstop(n, x) do { } while (0);
72 
73 #endif // PROFILE
74 
75 
76 // ------------------------------------------------------------------------
77 
78 PGDLLEXPORT Datum vrp(PG_FUNCTION_ARGS);
79 
80 #undef DEBUG
81 // #define DEBUG 1
82 #include "../../common/src/debug_macro.h"
83 
84 
85 // The number of tuples to fetch from the SPI cursor at each iteration
86 #define TUPLIMIT 1000
87 
88 #ifndef PG_MODULE_MAGIC
90 #endif
91 
92 typedef struct vehicle_columns {
94  int capacity;
96 
97 typedef struct order_columns {
98  int id;
103 
104  int x;
105  int y;
107 
108 typedef struct distance_columns {
109  int src_id;
110  int dest_id;
111  int cost;
112  int distance;
115 
116 
117 // float DISTANCE[MAX_TOWNS][MAX_TOWNS];
118 // float x[MAX_TOWNS], y[MAX_TOWNS];
119 
120 #if 0
121 static char *
122 text2char(text *in) {
123  char *out = (char*)palloc(VARSIZE(in));
124 
125  memcpy(out, VARDATA(in), VARSIZE(in) - VARHDRSZ);
126  out[VARSIZE(in) - VARHDRSZ] = '\0';
127  return out;
128 }
129 #endif
130 
131 static int
132 finish(int *code) {
133  *code = SPI_finish();
134  if (*code != SPI_OK_FINISH) {
135  elog(ERROR, "couldn't disconnect from SPI");
136  return -1;
137  }
138  return 0;
139 }
140 
141 
142 
143 static int
145  PGR_DBG("Fetching distance");
146  if (tuptable) {}
147 
148  distance_columns->src_id = SPI_fnumber(SPI_tuptable->tupdesc, "src_id");
149  distance_columns->dest_id = SPI_fnumber(SPI_tuptable->tupdesc, "dest_id");
150  distance_columns->cost = SPI_fnumber(SPI_tuptable->tupdesc, "cost");
151  distance_columns->distance = SPI_fnumber(SPI_tuptable->tupdesc, "distance");
152  distance_columns->traveltime = SPI_fnumber(SPI_tuptable->tupdesc, "traveltime");
153  if (distance_columns->src_id == SPI_ERROR_NOATTRIBUTE ||
154  distance_columns->dest_id == SPI_ERROR_NOATTRIBUTE ||
155  distance_columns->cost == SPI_ERROR_NOATTRIBUTE ||
156  distance_columns->distance == SPI_ERROR_NOATTRIBUTE ||
157  distance_columns->traveltime == SPI_ERROR_NOATTRIBUTE) {
158  elog(ERROR, "Error, query must return columns "
159  "'src_id', 'dest_id', 'cost', 'distance' and 'traveltime'");
160  return -1;
161  }
162 
163  return 0;
164 }
165 
166 
167 static void
168 fetch_distance(HeapTuple *tuple, TupleDesc *tupdesc,
170  Datum binval;
171  bool isnull;
172  if (t) {}
173 
174  PGR_DBG("fetch_distance: src_id col:%i", distance_columns->src_id);
175 
176  binval = SPI_getbinval(*tuple, *tupdesc, distance_columns->src_id, &isnull);
177 
178  PGR_DBG("back from SPI_getbinval for src_id");
179  // PGR_DBG("binval = %i", binval);
180 
181  if (isnull)
182  elog(ERROR, "src_id contains a null value");
183 
184  dist->src_id = DatumGetInt32(binval);
185 
186  PGR_DBG("back from DatumGetInt32");
187  PGR_DBG("src_id = %i", dist->src_id);
188 
189  binval = SPI_getbinval(*tuple, *tupdesc, distance_columns->dest_id, &isnull);
190  if (isnull)
191  elog(ERROR, "dest_id contains a null value");
192 
193  dist->dest_id = DatumGetInt32(binval);
194 
195  PGR_DBG("dest_id = %i", dist->dest_id);
196 
197  binval = SPI_getbinval(*tuple, *tupdesc, distance_columns->cost, &isnull);
198 
199  if (isnull)
200  elog(ERROR, "cost contains a null value");
201 
202  dist->cost = DatumGetFloat8(binval);
203 
204  PGR_DBG("cost = %lf", dist->cost);
205 
206  binval = SPI_getbinval(*tuple, *tupdesc, distance_columns->distance, &isnull);
207  if (isnull)
208  elog(ERROR, "distance contains a null value");
209 
210  dist->distance = DatumGetFloat8(binval);
211 
212  PGR_DBG("distance = %lf", dist->distance);
213 
214  binval = SPI_getbinval(*tuple, *tupdesc, distance_columns->traveltime, &isnull);
215 
216  if (isnull)
217  elog(ERROR, "traveltime contains a null value");
218 
219  dist->traveltime = DatumGetFloat8(binval);
220 
221  PGR_DBG("traveltime = %lf", dist->traveltime);
222 
223  // PGR_DBG("dist[%i][%i] = %f\n", from_point, to_point, value);
224 
225 
226  // PGR_DBG("dist[%i(%i:%i)][%i(%i:%i)] = %f\n", from, from_order, from_point, to, to_order, to_point, *(dist + (num_rows * from) + to));
227 }
228 
229 static int
231  PGR_DBG("Fetching order");
232  if (tuptable) {}
233 
234  // order_columns->id = SPI_fnumber(SPI_tuptable->tupdesc, "id");
235  order_columns->id = SPI_fnumber(SPI_tuptable->tupdesc, "id");
236  order_columns->order_unit = SPI_fnumber(SPI_tuptable->tupdesc, "order_unit");
237  order_columns->open_time = SPI_fnumber(SPI_tuptable->tupdesc, "open_time");
238  order_columns->close_time = SPI_fnumber(SPI_tuptable->tupdesc, "close_time");
239  order_columns->service_time = SPI_fnumber(SPI_tuptable->tupdesc, "service_time");
240  order_columns->x = SPI_fnumber(SPI_tuptable->tupdesc, "x");
241  order_columns->y = SPI_fnumber(SPI_tuptable->tupdesc, "y");
242  if ( // order_columns->id == SPI_ERROR_NOATTRIBUTE ||
243  order_columns->id == SPI_ERROR_NOATTRIBUTE ||
244  order_columns->open_time == SPI_ERROR_NOATTRIBUTE ||
245  order_columns->order_unit == SPI_ERROR_NOATTRIBUTE ||
246  order_columns->close_time == SPI_ERROR_NOATTRIBUTE ||
247  order_columns->service_time == SPI_ERROR_NOATTRIBUTE ||
248  order_columns->x == SPI_ERROR_NOATTRIBUTE ||
249  order_columns->y == SPI_ERROR_NOATTRIBUTE
250  ) {
251  // elog(ERROR, "Error, query must return columns "
252  // "'id', 'order_id', 'pu_time', 'do_time', 'pu_time_window', 'do_time_window', 'from_x', 'to_x', 'from_y', 'to_y' and 'size'");
253  elog(ERROR, "Error, query must return columns "
254  // "'id',
255  "'id', 'order_unit', 'open_time', 'close_time', 'service_time', 'x', 'y'");
256  return -1;
257  }
258 
259  return 0;
260 }
261 
262 static void
263 fetch_order(HeapTuple *tuple, TupleDesc *tupdesc,
264  order_columns_t *order_columns, vrp_orders_t *order, size_t t) {
265  Datum binval;
266  bool isnull;
267 
268  PGR_DBG("inside fetch_order\n");
269 
270  // binval = SPI_getbinval(*tuple, *tupdesc, order_columns->id, &isnull);
271  //
272  // PGR_DBG("got binval\n");
273  //
274  // if (isnull)
275  // elog(ERROR, "id contains a null value");
276  //
277  // order->id = DatumGetInt32(binval);
278  order->id = (int)t + 1;
279 
280  PGR_DBG("id = %i\n", order->id);
281 
282  binval = SPI_getbinval(*tuple, *tupdesc, order_columns->id, &isnull);
283  if (isnull)
284  elog(ERROR, "order_id contains a null value");
285 
286  order->id = DatumGetInt32(binval);
287 
288  PGR_DBG("order_id = %i\n", order->id);
289 
290 
291  binval = SPI_getbinval(*tuple, *tupdesc, order_columns->order_unit, &isnull);
292  if (isnull)
293  elog(ERROR, "order_unit contains a null value");
294 
295  order->order_unit = DatumGetInt32(binval);
296 
297  PGR_DBG("order_unit = %i\n", order->order_unit);
298 
299  binval = SPI_getbinval(*tuple, *tupdesc, order_columns->open_time, &isnull);
300  if (isnull)
301  elog(ERROR, "open_time contains a null value");
302 
303  order->open_time = DatumGetInt32(binval);
304 
305  PGR_DBG("open_time = %i\n", order->open_time);
306 
307  binval = SPI_getbinval(*tuple, *tupdesc, order_columns->close_time, &isnull);
308  if (isnull)
309  elog(ERROR, "close_time contains a null value");
310 
311  order->close_time = DatumGetInt32(binval);
312 
313  PGR_DBG("close_time = %d\n", order->close_time);
314 
315  binval = SPI_getbinval(*tuple, *tupdesc, order_columns->service_time, &isnull);
316  if (isnull)
317  elog(ERROR, "service_time contains a null value");
318 
319  order->service_time = DatumGetInt32(binval);
320 
321  PGR_DBG("service_time = %d\n", order->service_time);
322 
323  binval = SPI_getbinval(*tuple, *tupdesc, order_columns->x, &isnull);
324  if (isnull)
325  elog(ERROR, "x contains a null value");
326 
327  order->x = DatumGetFloat8(binval);
328 
329  PGR_DBG("x = %f\n", order->x);
330 
331  binval = SPI_getbinval(*tuple, *tupdesc, order_columns->y, &isnull);
332  if (isnull)
333  elog(ERROR, "y contains a null value");
334 
335  order->y = DatumGetFloat8(binval);
336 
337  PGR_DBG("doUT = %f\n", order->y);
338 }
339 
340 static int
342  PGR_DBG("Fetching order");
343  if (tuptable) {}
344 
345  vehicle_columns->vehicle_id = SPI_fnumber(SPI_tuptable->tupdesc, "vehicle_id");
346  vehicle_columns->capacity = SPI_fnumber(SPI_tuptable->tupdesc, "capacity");
347 
348  if (vehicle_columns->vehicle_id == SPI_ERROR_NOATTRIBUTE ||
349  vehicle_columns->capacity == SPI_ERROR_NOATTRIBUTE) {
350  elog(ERROR, "Error, query must return columns "
351  "'id' and 'capacity'");
352  return -1;
353  }
354 
355  return 0;
356 }
357 
358 static void
359 fetch_vehicle(HeapTuple *tuple, TupleDesc *tupdesc,
360  vehicle_columns_t *vehicle_columns, vrp_vehicles_t *vehicle, size_t t) {
361  Datum binval;
362  bool isnull;
363  if (t) {}
364 
365  PGR_DBG("inside fetch_vehicle\n");
366 
367  // binval = SPI_getbinval(*tuple, *tupdesc, vehicle_columns->id, &isnull);
368  // PGR_DBG("Got id\n");
369  //
370  // if (isnull)
371  // elog(ERROR, "id contains a null value");
372  //
373  // vehicle->id = DatumGetInt32(binval);
374 
375 
376  binval = SPI_getbinval(*tuple, *tupdesc, vehicle_columns->vehicle_id, &isnull);
377  PGR_DBG("Got vehicle_id\n");
378 
379  if (isnull)
380  elog(ERROR, "vehicle_id contains a null value");
381 
382  vehicle->id = DatumGetInt32(binval);
383 
384  PGR_DBG("vehicle_id = %i\n", vehicle->id);
385 
386  binval = SPI_getbinval(*tuple, *tupdesc, vehicle_columns->capacity, &isnull);
387  if (isnull)
388  elog(ERROR, "capacity contains a null value");
389 
390  vehicle->capacity = DatumGetInt32(binval);
391 
392  PGR_DBG("capacity = %d\n", vehicle->capacity);
393 }
394 
395 static int conn(int *SPIcode) {
396  int res = 0;
397 
398  *SPIcode = SPI_connect();
399 
400  if (*SPIcode != SPI_OK_CONNECT) {
401  elog(ERROR, "vrp: couldn't open a connection to SPI");
402  res = -1;
403  }
404 
405  return res;
406 }
407 
408 static int prepare_query(Portal *SPIportal, char* sql) {
409  int res = 0;
410 
411  void* SPIplan = SPI_prepare(sql, 0, NULL);
412 
413  if (SPIplan == NULL) {
414  elog(ERROR, "vrp: couldn't create query plan via SPI");
415  res = -1;
416  }
417 
418  if ((*SPIportal = SPI_cursor_open(NULL, SPIplan, NULL, NULL, true)) == NULL) {
419  elog(ERROR, "vrp: SPI_cursor_open('%s') returns NULL", sql);
420  res = -1;
421  }
422 
423  return res;
424 }
425 
426 static int solve_vrp(char* orders_sql, char* vehicles_sql,
427  char* dist_sql,
428  int depot,
429  vrp_result_element_t** path, size_t *path_count) {
430  int SPIcode;
431 
432  Portal SPIportal_o;
433  Portal SPIportal_v;
434  Portal SPIportal_d;
435  // Portal SPIportal_p;
436 
437  bool moredata = TRUE;
438  size_t ntuples;
439 
440  size_t order_num;
441  size_t vehicle_num;
442  size_t dist_num;
443 
444  vrp_vehicles_t *vehicles = NULL;
445  vehicle_columns_t vehicle_columns = {.vehicle_id = -1, .capacity = -1};
446 
447  vrp_orders_t *orders = NULL;
448  order_columns_t order_columns = {.id = -1, .order_unit = -1, .open_time = -1, .close_time = -1, .service_time = -1, .x = -1, .y = -1};
449 
450  vrp_cost_element_t *costs = NULL;
451  distance_columns_t distance_columns = {.src_id = -1, .dest_id = -1, .cost = -1, .distance = -1, .traveltime = -1};
452 
453  char *err_msg = NULL;
454  int ret = -1;
455 
456  // int z = 0;
457 
458  // int tt, cc;
459  // double dx, dy;
460  // float fit = 0.0;
461 
462  int prep = -1, con = -1;
463 
464  // int total_tuples = 0;
465  order_num = 0;
466  vehicle_num = 0;
467 
468  PGR_DBG("start solve_vrp\n");
469 
470  // vrp_orders_t depot_ord = {id:0, order_id:depot, from:depot_point, to:depot_point};
471  // orders = palloc(1 * sizeof(vrp_orders_t));
472  // orders[0] = depot_ord;
473 
474  con = conn(&SPIcode);
475 
476  if (con < 0)
477  return ret;
478 
479 
480  // Fetching orders
481 
482  PGR_DBG("calling prepare_query for orders_sql");
483 
484  prep = prepare_query(&SPIportal_o, orders_sql);
485 
486  if (prep < 0)
487  return ret;
488 
489  PGR_DBG("Query: %s\n", orders_sql);
490  PGR_DBG("Query executed\n");
491 
492  PGR_DBG("Orders before: %lu\n", order_num);
493 
494  while (moredata == TRUE) {
495  SPI_cursor_fetch(SPIportal_o, TRUE, TUPLIMIT);
496 
497  PGR_DBG("cursor fetched\n");
498 
499  if (order_columns.id == -1) {
500  if (fetch_order_columns(SPI_tuptable, &order_columns) == -1)
501  return finish(&SPIcode);
502  }
503 
504  ntuples = SPI_processed;
505 
506  order_num += ntuples;
507 
508  PGR_DBG("Tuples: %lu\n", order_num);
509 
510  if (!orders)
511  orders = palloc(order_num * sizeof(vrp_orders_t));
512  else
513  orders = repalloc(orders, (order_num + 1) * sizeof(vrp_orders_t));
514 
515  if (orders == NULL) {
516  elog(ERROR, "Out of memory");
517  return finish(&SPIcode);
518  }
519 
520  if (ntuples > 0) {
521  SPITupleTable *tuptable = SPI_tuptable;
522  TupleDesc tupdesc = SPI_tuptable->tupdesc;
523 
524  PGR_DBG("Got tuple desc\n");
525  size_t t;
526  for (t = 0; t < ntuples; t++) {
527  HeapTuple tuple = tuptable->vals[t];
528  // PGR_DBG("Before order fetched [%i]\n", order_num - ntuples + t);
529  fetch_order(&tuple, &tupdesc, &order_columns,
530  &orders[order_num - ntuples + t], t);
531 
532  // &orders[t+1], t);
533  PGR_DBG("Order fetched\n");
534  }
535 
536  SPI_freetuptable(tuptable);
537  } else {
538  moredata = FALSE;
539  }
540  } // end of fetching orders
541  // finish(&SPIcode_o);
542  /*
543  int o;
544  for (o = 0; o<order_num+1;++o)
545  {
546  elog(NOTICE, "ORDERS[%i] = {id = %i, open = %i, close = %i, service = %i}", o, orders[o].id, orders[o].open_time, orders[o].close_time, orders[o].service_time);
547  }
548  */
549  PGR_DBG("order_num = %lu", order_num);
550 
551  // qsort (orders, order_num+1, sizeof (vrp_orders_t), order_cmp);
552 
553 
554  // Fetching vehicles
555 
556  moredata = TRUE;
557  prep = prepare_query(&SPIportal_v, vehicles_sql);
558 
559  if (prep < 0)
560  return ret;
561 
562  PGR_DBG("Query: %s\n", vehicles_sql);
563  PGR_DBG("Query executed\n");
564 
565 
566  while (moredata == TRUE) {
567  SPI_cursor_fetch(SPIportal_v, TRUE, TUPLIMIT);
568 
569  if (vehicle_columns.vehicle_id == -1) {
570  if (fetch_vehicle_columns(SPI_tuptable, &vehicle_columns) == -1)
571  return finish(&SPIcode);
572  }
573 
574 
575  ntuples = SPI_processed;
576 
577  vehicle_num += ntuples;
578 
579  PGR_DBG("Tuples: %lu\n", vehicle_num);
580 
581  if (!vehicles)
582  vehicles = palloc(vehicle_num * sizeof(vrp_vehicles_t));
583  else
584  vehicles = repalloc(vehicles, vehicle_num * sizeof(vrp_vehicles_t));
585 
586  if (vehicles == NULL) {
587  elog(ERROR, "Out of memory");
588  return finish(&SPIcode);
589  }
590 
591  if (ntuples > 0) {
592  SPITupleTable *tuptable = SPI_tuptable;
593  TupleDesc tupdesc = SPI_tuptable->tupdesc;
594 
595  PGR_DBG("Got tuple desc\n");
596 
597  size_t t;
598  for (t = 0; t < ntuples; t++) {
599  HeapTuple tuple = tuptable->vals[t];
600  PGR_DBG("Before vehicle fetched\n");
601  fetch_vehicle(&tuple, &tupdesc, &vehicle_columns,
602  &vehicles[vehicle_num - ntuples + t], t);
603  PGR_DBG("Vehicle fetched\n");
604  }
605 
606  SPI_freetuptable(tuptable);
607  } else {
608  moredata = FALSE;
609  }
610  } // end of fetching vehicles
611  // finish(&SPIcode_v);
612 
613  // double dist[order_num*2+1][order_num*2+1];
614 
615  // Fetching distances
616 
617  dist_num = 0;
618  moredata = TRUE;
619  prep = prepare_query(&SPIportal_d, dist_sql);
620 
621  if (prep < 0)
622  return ret;
623 
624  PGR_DBG("Query: %s\n", dist_sql);
625  PGR_DBG("Query executed\n");
626 
627  while (moredata == TRUE) {
628  SPI_cursor_fetch(SPIportal_d, TRUE, TUPLIMIT);
629 
630  if (distance_columns.src_id == -1) {
631  if (fetch_distance_columns(SPI_tuptable, &distance_columns) == -1)
632  return finish(&SPIcode);
633  }
634 
635  ntuples = SPI_processed;
636  dist_num += ntuples;
637 
638  PGR_DBG("Tuples: %lu\n", vehicle_num);
639 
640  if (!costs)
641  costs = palloc(dist_num * sizeof(vrp_cost_element_t));
642  else
643  costs = repalloc(costs, dist_num * sizeof(vrp_cost_element_t));
644 
645  if (costs == NULL) {
646  elog(ERROR, "Out of memory");
647  return finish(&SPIcode);
648  }
649 
650  if (ntuples > 0) {
651  SPITupleTable *tuptable = SPI_tuptable;
652  TupleDesc tupdesc = SPI_tuptable->tupdesc;
653 
654  PGR_DBG("Got tuple desc\n");
655  size_t t;
656  for (t = 0; t < ntuples; t++) {
657  HeapTuple tuple = tuptable->vals[t];
658  PGR_DBG("Before distance fetched\n");
659  fetch_distance(&tuple, &tupdesc, &distance_columns,
660  &costs[dist_num - ntuples + t], t);
661  PGR_DBG("Distance fetched\n");
662  }
663 
664  SPI_freetuptable(tuptable);
665  } else {
666  moredata = FALSE;
667  }
668  } // end of fetching distances
669 
670 
671  PGR_DBG("Calling vrp\n");
672 
673  profstop("extract", prof_extract);
674  profstart(prof_vrp);
675 
676  PGR_DBG("Total orders: %lu\n", order_num);
677  PGR_DBG("Total vehicles: %lu\n", vehicle_num);
678 
679 
680  // qsort (orders, order_num+1, sizeof (vrp_orders_t), order_cmp_asc);
681 
682 
683 #ifdef DEBUG
684  int o;
685  for (o = 0; o < order_num + 1; ++o) {
686  PGR_DBG("ORDERS[%i] = {id = %i, open = %i, close = %i, service = %i}", o, orders[o].id, orders[o].open_time, orders[o].close_time, orders[o].service_time);
687  }
688 #endif
689 
690 
691 
692  // itinerary = (vrp_result_element_t *)palloc(sizeof(vrp_result_element_t)*(order_num*2-1)*vehicle_num);
693 
694  PGR_DBG("Calling vrp solver\n");
695  // elog(NOTICE, "Calling find_vrp_solution: vehicles: %i, orders: %i, dists: %i, depot: %i", vehicle_num, order_num, dist_num, depot);
696 
697  ret = find_vrp_solution(vehicles, vehicle_num,
698  orders, order_num,
699  costs, dist_num,
700  depot,
701  path, path_count, &err_msg);
702 
703  // ret = -1;
704  // elog(NOTICE, "vrp solved! ret: %d, path_count: %d", ret, *path_count);
705  // int pp;
706  /*
707  for (pp = 0; pp < *path_count; pp++)
708  {
709  elog(NOTICE, "Row: %d: %d %d %d %d %d", pp, (*path)[pp].order_id, (*path)[pp].order_pos, (*path)[pp].vehicle_id, (*path)[pp].arrival_time, (*path)[pp].depart_time);
710  }
711  */
712  PGR_DBG("vrp solved! ret: %d, path_count: %lu", ret, *path_count);
713  // PGR_DBG("Score: %f\n", fit);
714 
715  profstop("vrp", prof_vrp);
716  profstart(prof_store);
717 
718  PGR_DBG("Profile changed and ret is %i", ret);
719 
720  if (ret < 0) {
721  // elog(ERROR, "Error computing path: %s", err_msg);
722  ereport(ERROR, (errcode(ERRCODE_E_R_E_CONTAINING_SQL_NOT_PERMITTED), errmsg("Error computing path: %s", err_msg)));
723  }
724 
725  // pfree(vehicles);
726  // pfree(orders);
727  return finish(&SPIcode);
728 }
729 
731 PGDLLEXPORT Datum
732 vrp(PG_FUNCTION_ARGS) {
733  FuncCallContext *funcctx;
734  TupleDesc tuple_desc;
736 
737  /* stuff done only on the first call of the function */
738  if (SRF_IS_FIRSTCALL()) {
739  MemoryContext oldcontext;
740  // int path_count;
741  // int ret = -1;
742  size_t path_count = 0;
743 
744  // XXX profiling messages are not thread safe
745  profstart(prof_total);
746  profstart(prof_extract);
747 
748  /* create a function context for cross-call persistence */
749  funcctx = SRF_FIRSTCALL_INIT();
750 
751  /* switch to memory context appropriate for multiple function calls */
752  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
753 
754 
755  // path = (vrp_result_element_t *)palloc(sizeof(vrp_result_element_t)*(MAX_ORDERS-1)*2*MAX_VEHICLES);
756 
757 
758  PGR_DBG("Calling solve_vrp ...");
759 
760  // ret =
761  solve_vrp( // text_to_cstring(PG_GETARG_TEXT_P(0)), // points sql
762  text_to_cstring(PG_GETARG_TEXT_P(0)), // orders sql
763  text_to_cstring(PG_GETARG_TEXT_P(1)), // vehicles sql
764  text_to_cstring(PG_GETARG_TEXT_P(2)), // distances query
765  PG_GETARG_INT32(3), // depot id
766  &path, &path_count);
767 
768  PGR_DBG("Back from solve_vrp, path_count:%lu", path_count);
769  // elog(NOTICE, "Back from solve_vrp, path_count:%d", path_count);
770 
771  /* total number of tuples to be returned */
772  // PGR_DBG("Counting tuples number\n");
773 
774 #if PGSQL_VERSION > 95
775  funcctx->max_calls = path_count;
776 #else
777  funcctx->max_calls = (uint32_t)path_count;
778 #endif
779  funcctx->user_fctx = path;
780 
781  /* Build a tuple descriptor for our result type */
782  if (get_call_result_type(fcinfo, NULL, &tuple_desc) != TYPEFUNC_COMPOSITE)
783  ereport(ERROR,
784  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
785  errmsg("function returning record called in context "
786  "that cannot accept type record")));
787 
788  funcctx->tuple_desc = BlessTupleDesc(tuple_desc);
789 
790  /*
791  * generate attribute metadata needed later to produce tuples from raw
792  * C strings
793  */
794  // attinmeta = TupleDescGetAttInMetadata(tuple_desc);
795  // funcctx->attinmeta = attinmeta;
796 
797  MemoryContextSwitchTo(oldcontext);
798  // elog(NOTICE, "table formed");
799  }
800 
801  /* stuff done on every call of the function */
802  funcctx = SRF_PERCALL_SETUP();
803 
804  tuple_desc = funcctx->tuple_desc;
805  path = (vrp_result_element_t *)funcctx->user_fctx;
806 
807  // elog(NOTICE, "Point 1");
808  // PGR_DBG("Trying to allocate some memory\n");
809  // PGR_DBG("funcctx->call_cntr = %i, max_calls = %i\n", funcctx->call_cntr, max_calls);
810 
811  if (funcctx->call_cntr < funcctx->max_calls) {
812  /* do when there is more left to send */
813  HeapTuple tuple;
814  Datum result;
815  Datum *values;
816  char* nulls;
817 
818  values = palloc(5 * sizeof(Datum));
819  nulls = palloc(5 * sizeof(char));
820 
821  values[0] = Int32GetDatum(path[funcctx->call_cntr].order_id); // order id
822  nulls[0] = ' ';
823  values[1] = Int32GetDatum(path[funcctx->call_cntr].order_pos); // order pos
824  nulls[1] = ' ';
825  values[2] = Int32GetDatum(path[funcctx->call_cntr].vehicle_id); // vehicle id
826  nulls[2] = ' ';
827  values[3] = Int32GetDatum(path[funcctx->call_cntr].arrival_time); // arrival time
828  nulls[3] = ' ';
829  // values[4] = TimeTzADTPGetDatum(&path[funcctx->call_cntr].time);
830  values[4] = Int32GetDatum(path[funcctx->call_cntr].depart_time); // departure time
831  nulls[4] = ' ';
832 
833  // PGR_DBG("Heap making\n");
834  // elog(NOTICE, "Result %d %d %d", funcctx->call_cntr, path[funcctx->call_cntr].order_id, max_calls);
835  tuple = heap_form_tuple(tuple_desc, values, nulls);
836 
837  // PGR_DBG("Datum making\n");
838 
839  /* make the tuple into a datum */
840  result = HeapTupleGetDatum(tuple);
841 
842  // PGR_DBG("Trying to free some memory\n");
843 
844  /* clean up */
845  pfree(values);
846  pfree(nulls);
847 
848 
849  SRF_RETURN_NEXT(funcctx, result);
850  } else {
851  /* do when there is no more left */
852 
853  PGR_DBG("Ending function\n");
854  profstop("store", prof_store);
855  profstop("total", prof_total);
856  PGR_DBG("Profiles stopped\n");
857 
858  PGR_DBG("Itinerary cleared\n");
859 
860  SRF_RETURN_DONE(funcctx);
861  }
862 }
int capacity
Definition: VRP.h:31
static void fetch_order(HeapTuple *tuple, TupleDesc *tupdesc, order_columns_t *order_columns, vrp_orders_t *order, size_t t)
Definition: VRP.c:263
int path_count
Definition: BDATester.cpp:51
double y
Definition: VRP.h:43
int traveltime
Definition: VRP.c:113
static void fetch_vehicle(HeapTuple *tuple, TupleDesc *tupdesc, vehicle_columns_t *vehicle_columns, vrp_vehicles_t *vehicle, size_t t)
Definition: VRP.c:359
int open_time
Definition: VRP.c:100
int depart_time
Definition: VRP.h:60
int id
Definition: VRP.h:30
int service_time
Definition: VRP.c:102
int capacity
Definition: VRP.c:94
#define PGR_DBG(...)
Definition: debug_macro.h:34
static int finish(int *code)
Definition: VRP.c:132
static int fetch_vehicle_columns(SPITupleTable *tuptable, vehicle_columns_t *vehicle_columns)
Definition: VRP.c:341
int service_time
Definition: VRP.h:40
double distance
Definition: VRP.h:50
int dest_id
Definition: VRP.h:48
static int fetch_distance_columns(SPITupleTable *tuptable, distance_columns_t *distance_columns)
Definition: VRP.c:144
static int conn(int *SPIcode)
Definition: VRP.c:395
int open_time
Definition: VRP.h:38
static int solve_vrp(char *orders_sql, char *vehicles_sql, char *dist_sql, int depot, vrp_result_element_t **path, size_t *path_count)
Definition: VRP.c:426
double traveltime
Definition: VRP.h:51
int id
Definition: VRP.c:98
PGDLLEXPORT Datum vrp(PG_FUNCTION_ARGS)
Definition: VRP.c:732
#define profstart(x)
Definition: VRP.c:70
int order_unit
Definition: VRP.h:37
struct vehicle_columns vehicle_columns_t
int close_time
Definition: VRP.c:101
int vehicle_id
Definition: VRP.c:93
struct order_columns order_columns_t
static int prepare_query(Portal *SPIportal, char *sql)
Definition: VRP.c:408
int order_id
Definition: VRP.h:56
static int fetch_order_columns(SPITupleTable *tuptable, order_columns_t *order_columns)
Definition: VRP.c:230
int id
Definition: VRP.h:36
static char * text2char(text *in)
Definition: trsp.c:51
int arrival_time
Definition: VRP.h:59
int order_pos
Definition: VRP.h:57
int find_vrp_solution(vrp_vehicles_t *vehicles, size_t vehicle_count, vrp_orders_t *orders, size_t order_count, vrp_cost_element_t *costmatrix, size_t cost_count, int depot_id, vrp_result_element_t **result, size_t *result_count, char **err_msg)
Definition: VRP_core.cpp:139
#define profstop(n, x)
Definition: VRP.c:71
int order_unit
Definition: VRP.c:99
int src_id
Definition: VRP.h:47
path_element_t * path
Definition: BDATester.cpp:49
Definition: VRP.h:35
double cost
Definition: VRP.h:49
char * err_msg
Definition: BDATester.cpp:50
#define TUPLIMIT
Definition: VRP.c:86
int close_time
Definition: VRP.h:39
int x
Definition: VRP.c:104
double x
Definition: VRP.h:42
int vehicle_id
Definition: VRP.h:58
int distance
Definition: VRP.c:112
int src_id
Definition: VRP.c:109
struct distance_columns distance_columns_t
int y
Definition: VRP.c:105
PG_FUNCTION_INFO_V1(vrp)
int dest_id
Definition: VRP.c:110
static void fetch_distance(HeapTuple *tuple, TupleDesc *tupdesc, distance_columns_t *distance_columns, vrp_cost_element_t *dist, size_t t)
Definition: VRP.c:168
PG_MODULE_MAGIC
Definition: VRP.c:89