PGROUTING  3.2
minCostMaxFlow.c
Go to the documentation of this file.
1 /*PGR-GNU*****************************************************************
2 File: minCostMaxFlow.c
3 
4 Generated with Template by:
5 Copyright (c) 2015 pgRouting developers
7 
8 Function's developer:
9 Copyright (c) 2018 Maoguang Wang
11 
12 
13 ------
14 
15 This program is free software; you can redistribute it and/or modify
16 it under the terms of the GNU General Public License as published by
17 the Free Software Foundation; either version 2 of the License, or
18 (at your option) any later version.
19 
20 This program is distributed in the hope that it will be useful,
21 but WITHOUT ANY WARRANTY; without even the implied warranty of
22 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 GNU General Public License for more details.
24 
25 You should have received a copy of the GNU General Public License
26 along with this program; if not, write to the Free Software
27 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
28 
29  ********************************************************************PGR-GNU*/
30 
46 #include <stdbool.h>
48 #include "utils/array.h"
49 
50 
51 /* for macro PGR_DBG */
52 #include "c_common/debug_macro.h"
53 /* for pgr_global_report */
54 #include "c_common/e_report.h"
55 /* for time_msg & clock */
56 #include "c_common/time_msg.h"
57 /* for functions to get edges information */
58 #include "c_common/edges_input.h"
59 /* for functions to get array input */
60 #include "c_common/arrays_input.h"
62 
63 #include "drivers/max_flow/minCostMaxFlow_driver.h" // the link to the C++ code of the function
64 
65 PGDLLEXPORT Datum _pgr_maxflowmincost(PG_FUNCTION_ARGS);
67 
68 
69 /******************************************************************************/
70 /* MODIFY AS NEEDED */
71 static
72 void
74  char* edges_sql,
75  char* combinations_sql,
76  ArrayType *starts,
77  ArrayType *ends,
78  bool only_cost,
79  pgr_flow_t **result_tuples,
80  size_t *result_count) {
81  /*
82  * https://www.postgresql.org/docs/current/static/spi-spi-connect.html
83  */
85 
86  int64_t *sourceVertices = NULL;
87  size_t sizeSourceVerticesArr = 0;
88 
89  int64_t *sinkVertices = NULL;
90  size_t sizeSinkVerticesArr = 0;
91 
92  PGR_DBG("Load data");
93  pgr_costFlow_t *edges = NULL;
94  size_t total_edges = 0;
95 
96  pgr_combination_t *combinations = NULL;
97  size_t total_combinations = 0;
98 
99  if (starts && ends) {
100  sourceVertices = (int64_t*)
101  pgr_get_bigIntArray(&sizeSourceVerticesArr, starts);
102  sinkVertices = (int64_t*)
103  pgr_get_bigIntArray(&sizeSinkVerticesArr, ends);
104  } else if (combinations_sql) {
105  pgr_get_combinations(combinations_sql, &combinations, &total_combinations);
106  if (total_combinations == 0) {
107  if (combinations)
108  pfree(combinations);
109  pgr_SPI_finish();
110  return;
111  }
112  }
113 
114  pgr_get_costFlow_edges(edges_sql, &edges, &total_edges);
115  PGR_DBG("Total %ld edges in query:", total_edges);
116 
117  if (total_edges == 0) {
118  if (sourceVertices)
119  pfree(sourceVertices);
120  if (sinkVertices)
121  pfree(sinkVertices);
122  PGR_DBG("No edges found");
123  pgr_SPI_finish();
124  return;
125  }
126 
127  PGR_DBG("Starting processing");
128  clock_t start_t = clock();
129  char *log_msg = NULL;
130  char *notice_msg = NULL;
131  char *err_msg = NULL;
132 
134  edges, total_edges,
135  combinations, total_combinations,
136  sourceVertices, sizeSourceVerticesArr,
137  sinkVertices, sizeSinkVerticesArr,
138  only_cost,
139 
140  result_tuples, result_count,
141 
142  &log_msg,
143  &notice_msg,
144  &err_msg);
145 
146  if (only_cost) {
147  time_msg(" processing pgr_minCostMaxFlow_Cost", start_t, clock());
148  } else {
149  time_msg(" processing pgr_minCostMaxFlow", start_t, clock());
150  }
151 
152  PGR_DBG("Returning %ld tuples", *result_count);
153 
154  if (edges)
155  pfree(edges);
156  if (sourceVertices)
157  pfree(sourceVertices);
158  if (sinkVertices)
159  pfree(sinkVertices);
160 
161  if (err_msg && (*result_tuples)) {
162  pfree(*result_tuples);
163  (*result_tuples) = NULL;
164  (*result_count) = 0;
165  }
166 
167  pgr_global_report(log_msg, notice_msg, err_msg);
168 
169  if (log_msg) pfree(log_msg);
170  if (notice_msg) pfree(notice_msg);
171  if (err_msg) pfree(err_msg);
172 
173  pgr_SPI_finish();
174 }
175 /* */
176 /******************************************************************************/
177 
178 PGDLLEXPORT Datum _pgr_maxflowmincost(PG_FUNCTION_ARGS) {
179  FuncCallContext *funcctx;
180  TupleDesc tuple_desc;
181 
182  /**************************************************************************/
183  /* MODIFY AS NEEDED */
184  /* */
185  pgr_flow_t *result_tuples = NULL;
186  size_t result_count = 0;
187  /* */
188  /**************************************************************************/
189 
190  if (SRF_IS_FIRSTCALL()) {
191  MemoryContext oldcontext;
192  funcctx = SRF_FIRSTCALL_INIT();
193  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
194 
195 
196  /**********************************************************************/
197  /* MODIFY AS NEEDED */
198  /*
199  TEXT,
200  BIGINT,
201  BIGINT,
202  **********************************************************************/
203 
204 
205  PGR_DBG("Calling process");
206 
207  if (PG_NARGS() == 4) {
208  /*
209  * many to many
210  */
211  process(
212  text_to_cstring(PG_GETARG_TEXT_P(0)),
213  NULL,
214  PG_GETARG_ARRAYTYPE_P(1),
215  PG_GETARG_ARRAYTYPE_P(2),
216  PG_GETARG_BOOL(3),
217  &result_tuples,
218  &result_count);
219 
220  } else if (PG_NARGS() == 3) {
221  /*
222  * combinations
223  */
224  process(
225  text_to_cstring(PG_GETARG_TEXT_P(0)),
226  text_to_cstring(PG_GETARG_TEXT_P(1)),
227  NULL,
228  NULL,
229  PG_GETARG_BOOL(2),
230  &result_tuples,
231  &result_count);
232  }
233 
234  /* */
235  /**********************************************************************/
236 
237 #if PGSQL_VERSION > 94
238  funcctx->max_calls = (uint32_t)result_count;
239 #else
240  funcctx->max_calls = (uint32_t)result_count;
241 #endif
242  funcctx->user_fctx = result_tuples;
243  if (get_call_result_type(fcinfo, NULL, &tuple_desc)
244  != TYPEFUNC_COMPOSITE) {
245  ereport(ERROR,
246  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
247  errmsg("function returning record called in context "
248  "that cannot accept type record")));
249  }
250 
251  funcctx->tuple_desc = tuple_desc;
252  MemoryContextSwitchTo(oldcontext);
253  }
254 
255  funcctx = SRF_PERCALL_SETUP();
256  tuple_desc = funcctx->tuple_desc;
257  result_tuples = (pgr_flow_t*) funcctx->user_fctx;
258 
259  if (funcctx->call_cntr < funcctx->max_calls) {
260  HeapTuple tuple;
261  Datum result;
262  Datum *values;
263  bool* nulls;
264 
265  /**********************************************************************/
266  /* MODIFY AS NEEDED */
267  /*
268  ***********************************************************************/
269 
270  values = palloc(8 * sizeof(Datum));
271  nulls = palloc(8 * sizeof(bool));
272 
273 
274  size_t i;
275  for (i = 0; i < 8; ++i) {
276  nulls[i] = false;
277  }
278 
279  // postgres starts counting from 1
280  values[0] = Int32GetDatum(funcctx->call_cntr + 1);
281  values[1] = Int64GetDatum(result_tuples[funcctx->call_cntr].edge);
282  values[2] = Int64GetDatum(result_tuples[funcctx->call_cntr].source);
283  values[3] = Int64GetDatum(result_tuples[funcctx->call_cntr].target);
284  values[4] = Int64GetDatum(result_tuples[funcctx->call_cntr].flow);
285  values[5] = Int64GetDatum(
286  result_tuples[funcctx->call_cntr].residual_capacity);
287  values[6] = Float8GetDatum(result_tuples[funcctx->call_cntr].cost);
288  values[7] = Float8GetDatum(result_tuples[funcctx->call_cntr].agg_cost);
289  /**********************************************************************/
290 
291  tuple = heap_form_tuple(tuple_desc, values, nulls);
292  result = HeapTupleGetDatum(tuple);
293  SRF_RETURN_NEXT(funcctx, result);
294  } else {
295  /**********************************************************************/
296  /* MODIFY AS NEEDED */
297 
298  PGR_DBG("Clean up code");
299 
300  /**********************************************************************/
301 
302  SRF_RETURN_DONE(funcctx);
303  }
304 }
305 
minCostMaxFlow_driver.h
pgr_flow_t::residual_capacity
int64_t residual_capacity
Definition: pgr_flow_t.h:42
combinations_input.h
pgr_flow_t::source
int64_t source
Definition: pgr_flow_t.h:39
time_msg.h
postgres_connection.h
pgr_flow_t::flow
int64_t flow
Definition: pgr_flow_t.h:41
pgr_SPI_connect
void pgr_SPI_connect(void)
Definition: postgres_connection.c:82
pgr_flow_t::agg_cost
double agg_cost
Definition: pgr_flow_t.h:44
pgr_SPI_finish
void pgr_SPI_finish(void)
Definition: postgres_connection.c:71
process
static void process(char *edges_sql, char *combinations_sql, ArrayType *starts, ArrayType *ends, bool only_cost, pgr_flow_t **result_tuples, size_t *result_count)
Definition: minCostMaxFlow.c:73
e_report.h
arrays_input.h
pgr_flow_t
Definition: pgr_flow_t.h:37
debug_macro.h
_pgr_maxflowmincost
PGDLLEXPORT Datum _pgr_maxflowmincost(PG_FUNCTION_ARGS)
postgres_connection.h
Definition: minCostMaxFlow.c:178
pgr_flow_t::target
int64_t target
Definition: pgr_flow_t.h:40
pgr_get_bigIntArray
int64_t * pgr_get_bigIntArray(size_t *arrlen, ArrayType *input)
Enforces the input array to be NOT empty.
Definition: arrays_input.c:146
PGR_DBG
#define PGR_DBG(...)
Definition: debug_macro.h:34
pgr_combination_t
Definition: pgr_combination_t.h:43
pgr_get_combinations
void pgr_get_combinations(char *combinations_sql, pgr_combination_t **combinations, size_t *total_combinations)
combinations_sql
Definition: combinations_input.c:147
PG_FUNCTION_INFO_V1
PG_FUNCTION_INFO_V1(_pgr_maxflowmincost)
pgr_get_costFlow_edges
void pgr_get_costFlow_edges(char *sql, pgr_costFlow_t **edges, size_t *total_edges)
read edges for cost flow
Definition: edges_input.c:701
if
if(DOXYGEN_FOUND) configure_file($
Definition: doxygen/CMakeLists.txt:13
time_msg
void time_msg(char *msg, clock_t start_t, clock_t end_t)
Definition: time_msg.c:32
pgr_costFlow_t
Definition: pgr_costFlow_t.h:38
pgr_flow_t::cost
double cost
Definition: pgr_flow_t.h:43
edges_input.h
pgr_flow_t::edge
int64_t edge
Definition: pgr_flow_t.h:38
do_pgr_minCostMaxFlow
void do_pgr_minCostMaxFlow(pgr_costFlow_t *data_edges, size_t total_edges, pgr_combination_t *combinations, size_t total_combinations, int64_t *sourceVertices, size_t sizeSourceVerticesArr, int64_t *sinkVertices, size_t sizeSinkVerticesArr, bool only_cost, pgr_flow_t **return_tuples, size_t *return_count, char **log_msg, char **notice_msg, char **err_msg)
Definition: minCostMaxFlow_driver.cpp:43
pgr_global_report
void pgr_global_report(char *log, char *notice, char *err)
notice & error
Definition: e_report.c:93