diff --git a/NEWS.md b/NEWS.md index bc2855eb35..591db40a52 100644 --- a/NEWS.md +++ b/NEWS.md @@ -21,6 +21,7 @@ To see all issues & pull requests closed by this release see the * [#3060](https://github.com/pgRouting/pgrouting/issues/3060): dagShortestPath: use the shortest_path process and driver * [#3064](https://github.com/pgRouting/pgrouting/issues/3064): Astar: create and use a process and driver for Astar * [#3075](https://github.com/pgRouting/pgrouting/issues/3075): Spanning tree: create and use a process and driver +* [#3086](https://github.com/pgRouting/pgrouting/issues/3086): MaxFlow: create and use a process and driver ## pgRouting 4.0 diff --git a/doc/src/release_notes.rst b/doc/src/release_notes.rst index 795aa5c0be..9104cc6b11 100644 --- a/doc/src/release_notes.rst +++ b/doc/src/release_notes.rst @@ -46,6 +46,7 @@ To see all issues & pull requests closed by this release see the * :issue:`3060`: dagShortestPath: use the shortest_path process and driver * :issue:`3064`: Astar: create and use a process and driver for Astar * :issue:`3075`: Spanning tree: create and use a process and driver +* :issue:`3086`: MaxFlow: create and use a process and driver pgRouting 4.0 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ diff --git a/include/c_common/enums.h b/include/c_common/enums.h index 6ffad2994b..b2b5fced59 100644 --- a/include/c_common/enums.h +++ b/include/c_common/enums.h @@ -44,7 +44,8 @@ enum Which { PRIM = 510, PRIMDD, PRIMDFS, PRIMBFS, DFS = 520, BFS = 530, - DIJKSTRADD = 540 + DIJKSTRADD = 540, + MAXFLOW, PUSHRELABEL, BOYKOV, EDMONDSKARP }; #endif // INCLUDE_C_COMMON_ENUMS_H_ diff --git a/include/cpp_common/combinations.hpp b/include/cpp_common/combinations.hpp index 467606c9a9..500fc7bae5 100644 --- a/include/cpp_common/combinations.hpp +++ b/include/cpp_common/combinations.hpp @@ -62,6 +62,9 @@ get_combinations(const std::vector&); std::map> get_combinations(const std::string&, ArrayType*, ArrayType*, bool, bool&); +std::map> +get_combinations(const std::string&, ArrayType*, ArrayType*, bool); + std::map> get_combinations(const char*, ArrayType*, ArrayType*, bool); diff --git a/include/cpp_common/to_postgres.hpp b/include/cpp_common/to_postgres.hpp index 026b59c6c2..e36a0c0aab 100644 --- a/include/cpp_common/to_postgres.hpp +++ b/include/cpp_common/to_postgres.hpp @@ -36,6 +36,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. #include "c_types/routes_t.h" #include "c_types/path_rt.h" #include "c_types/mst_rt.h" +#include "c_types/flow_t.h" #include "cpp_common/path.hpp" #include "cpp_common/base_graph.hpp" @@ -68,6 +69,11 @@ size_t get_tuples(const std::deque&, Path_rt*&); */ size_t get_tuples(const std::deque&, MST_rt*&); +/* + * @brief get tuples for Flow_t + */ +size_t get_tuples(const std::vector&, Flow_t*&); + /* * @brief get tuples for spanning tree driver */ diff --git a/include/cpp_common/utilities.hpp b/include/cpp_common/utilities.hpp index 6d59a2933d..e033e932cf 100644 --- a/include/cpp_common/utilities.hpp +++ b/include/cpp_common/utilities.hpp @@ -33,6 +33,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. #include "c_common/enums.h" #include "c_types/mst_rt.h" +#include "c_types/flow_t.h" namespace pgrouting { @@ -42,6 +43,7 @@ std::string get_name(Which, bool, bool, bool); char estimate_drivingSide(char, Which); void get_new_queries(const std::string&, const std::string&, std::string&, std::string&); std::vector only_root_result(const std::set&); +std::vector only_maxFlow_result(int64_t); } // namespace pgrouting diff --git a/include/drivers/maxFlow_driver.hpp b/include/drivers/maxFlow_driver.hpp new file mode 100644 index 0000000000..5220fe7349 --- /dev/null +++ b/include/drivers/maxFlow_driver.hpp @@ -0,0 +1,57 @@ +/*PGR-GNU***************************************************************** +File: maxFlow_driver.hpp + +Generated with Template by: +Copyright (c) 2007-2026 pgRouting developers +Mail: project@pgrouting.org + +Function's developer: +Copyright (c) 2016 Andrea Nardelli +Mail: nrd.nardelli@gmail.com + +------ + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + ********************************************************************PGR-GNU*/ + +#ifndef INCLUDE_DRIVERS_MAXFLOW_DRIVER_HPP_ +#define INCLUDE_DRIVERS_MAXFLOW_DRIVER_HPP_ + +#include +#include +#include +#include + +#include "c_common/enums.h" + +using Flow_t = struct Flow_t; +using ArrayType = struct ArrayType; + +namespace pgrouting { +namespace drivers { + +void do_maxFlow( + const std::string&, const std::string&, + ArrayType*, ArrayType*, + + Which, + Flow_t*&, size_t&, + std::ostringstream&, std::ostringstream&, std::ostringstream&); + +} // namespace drivers +} // namespace pgrouting + +#endif // INCLUDE_DRIVERS_MAXFLOW_DRIVER_HPP_ diff --git a/include/max_flow/maxflow.hpp b/include/max_flow/maxflow.hpp index b0064fc652..0443ebd5f3 100644 --- a/include/max_flow/maxflow.hpp +++ b/include/max_flow/maxflow.hpp @@ -44,6 +44,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. #include "c_types/flow_t.h" #include "cpp_common/edge_t.hpp" +#include "c_common/enums.h" #include "c_types/path_rt.h" #include "cpp_common/interruption.hpp" @@ -107,10 +108,10 @@ class PgrFlowGraph { } PgrFlowGraph( - const std::vector &edges, - const std::set &source_vertices, - const std::set &sink_vertices, - int algorithm); + const std::vector&, + const std::set&, + const std::set&, + Which); PgrFlowGraph( const std::vector &edges, diff --git a/include/drivers/max_flow/max_flow_driver.h b/include/process/maxFlow_process.h similarity index 68% rename from include/drivers/max_flow/max_flow_driver.h rename to include/process/maxFlow_process.h index ad58f61809..48522aa9dd 100644 --- a/include/drivers/max_flow/max_flow_driver.h +++ b/include/process/maxFlow_process.h @@ -1,5 +1,5 @@ /*PGR-GNU***************************************************************** -File: max_flow_driver.h +File: maxFlow_process.h Generated with Template by: Copyright (c) 2007-2026 pgRouting developers @@ -27,49 +27,38 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ********************************************************************PGR-GNU*/ -#ifndef INCLUDE_DRIVERS_MAX_FLOW_MAX_FLOW_DRIVER_H_ -#define INCLUDE_DRIVERS_MAX_FLOW_MAX_FLOW_DRIVER_H_ +#ifndef INCLUDE_PROCESS_MAXFLOW_PROCESS_H_ +#define INCLUDE_PROCESS_MAXFLOW_PROCESS_H_ #pragma once #ifdef __cplusplus -extern "C" { -#endif - -#include -#include - -#ifdef __cplusplus -} -#endif - -#include "cpp_common/undefPostgresDefine.hpp" - -#ifdef __cplusplus -# include -# include +#include +#include using Flow_t = struct Flow_t; +using ArrayType = struct ArrayType; #else -# include -# include +#include +#include +#include typedef struct Flow_t Flow_t; +typedef struct ArrayType ArrayType; #endif +#include "c_common/enums.h" + #ifdef __cplusplus extern "C" { #endif -void pgr_do_max_flow( - const char*, - const char*, +void pgr_process_maxFlow( + const char*, const char*, ArrayType*, ArrayType*, - int, bool, - - Flow_t**, size_t*, - char**, char**, char**); + enum Which, + Flow_t**, size_t*); #ifdef __cplusplus } #endif -#endif // INCLUDE_DRIVERS_MAX_FLOW_MAX_FLOW_DRIVER_H_ +#endif // INCLUDE_PROCESS_MAXFLOW_PROCESS_H_ diff --git a/locale/en/LC_MESSAGES/pgrouting_doc_strings.po b/locale/en/LC_MESSAGES/pgrouting_doc_strings.po index e3d55a1fc8..8edb97b173 100644 --- a/locale/en/LC_MESSAGES/pgrouting_doc_strings.po +++ b/locale/en/LC_MESSAGES/pgrouting_doc_strings.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: pgRouting v4.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-02-21 01:08+0000\n" +"POT-Creation-Date: 2026-03-01 21:16+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -3961,6 +3961,11 @@ msgid "" "tree: create and use a process and driver" msgstr "" +msgid "" +"`#3086 `__: MaxFlow: " +"create and use a process and driver" +msgstr "" + msgid "All releases" msgstr "" diff --git a/locale/pot/pgrouting_doc_strings.pot b/locale/pot/pgrouting_doc_strings.pot index bf3e750913..e4721ccc0b 100644 --- a/locale/pot/pgrouting_doc_strings.pot +++ b/locale/pot/pgrouting_doc_strings.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: pgRouting v4.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-02-21 01:08+0000\n" +"POT-Creation-Date: 2026-03-01 21:16+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -3550,6 +3550,9 @@ msgstr "" msgid "`#3075 `__: Spanning tree: create and use a process and driver" msgstr "" +msgid "`#3086 `__: MaxFlow: create and use a process and driver" +msgstr "" + msgid "All releases" msgstr "" diff --git a/src/cpp_common/combinations.cpp b/src/cpp_common/combinations.cpp index 4e8c60a878..c8e4fa3057 100644 --- a/src/cpp_common/combinations.cpp +++ b/src/cpp_common/combinations.cpp @@ -182,5 +182,13 @@ get_combinations( return result; } +std::map> +get_combinations( + const std::string &combinations_sql, + ArrayType* startsArr, ArrayType* endsArr, bool normal) { + bool is_matrix = false; + return get_combinations(combinations_sql, startsArr, endsArr, normal, is_matrix); +} + } // namespace utilities } // namespace pgrouting diff --git a/src/cpp_common/to_postgres.cpp b/src/cpp_common/to_postgres.cpp index 4fa565d537..cdc6b853ba 100644 --- a/src/cpp_common/to_postgres.cpp +++ b/src/cpp_common/to_postgres.cpp @@ -34,6 +34,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. #include "c_types/routes_t.h" #include "c_types/path_rt.h" #include "c_types/mst_rt.h" +#include "c_types/flow_t.h" #include "cpp_common/path.hpp" #include "cpp_common/alloc.hpp" @@ -242,6 +243,23 @@ get_tuples( return count; } +size_t +get_tuples( + const std::vector &results, + Flow_t* &tuples) { + pgassert(!tuples); + + auto count = results.size(); + if (count == 0) return 0; + + tuples = pgr_alloc(count, tuples); + + for (size_t i = 0; i < count; i++) { + tuples[i] = results[i]; + } + return count; +} + size_t get_tuples( diff --git a/src/cpp_common/utilities.cpp b/src/cpp_common/utilities.cpp index 9735d37818..3a94081a9a 100644 --- a/src/cpp_common/utilities.cpp +++ b/src/cpp_common/utilities.cpp @@ -92,6 +92,18 @@ get_name(Which which) { case DIJKSTRADD: return "pgr_drivingDistance"; break; + case MAXFLOW: + return "pgr_maxFlow"; + break; + case PUSHRELABEL: + return "pgr_pushRelabel"; + break; + case BOYKOV: + return "pgr_boykovKolmogorov"; + break; + case EDMONDSKARP: + return "pgr_edmondsKarp"; + break; default: return "unknown"; break; @@ -213,4 +225,11 @@ only_root_result(const std::set &vids) { return results; } +std::vector +only_maxFlow_result(int64_t maxFlow) { + std::vector results; + results.push_back({-1, -1, -1, maxFlow, -1, 0, 0}); + return results; +} + } // namespace pgrouting diff --git a/src/max_flow/CMakeLists.txt b/src/max_flow/CMakeLists.txt index 8c8d98cf47..47cd593645 100644 --- a/src/max_flow/CMakeLists.txt +++ b/src/max_flow/CMakeLists.txt @@ -7,7 +7,9 @@ ADD_LIBRARY(max_flow OBJECT maximum_cardinality_matching.c edge_disjoint_paths.c - max_flow_driver.cpp + maxFlow_driver.cpp + maxFlow_process.cpp + maximum_cardinality_matching_driver.cpp edge_disjoint_paths_driver.cpp minCostMaxFlow_driver.cpp diff --git a/src/max_flow/maxFlow_driver.cpp b/src/max_flow/maxFlow_driver.cpp new file mode 100644 index 0000000000..ab0fcef7ba --- /dev/null +++ b/src/max_flow/maxFlow_driver.cpp @@ -0,0 +1,147 @@ +/*PGR-GNU***************************************************************** +File: maxFlow_driver.cpp + +Generated with Template by: +Copyright (c) 2015-2026 pgRouting developers +Mail: project@pgrouting.org + +Function's developer: +Copyright (c) 2016 Andrea Nardelli +Mail: nrd.nardelli@gmail.com + +------ + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + ********************************************************************PGR-GNU*/ + +#include "drivers/maxFlow_driver.hpp" + +#include +#include +#include +#include +#include + +#include "max_flow/maxflow.hpp" + +#include "c_types/flow_t.h" +#include "cpp_common/pgdata_getters.hpp" +#include "cpp_common/utilities.hpp" +#include "cpp_common/to_postgres.hpp" +#include "cpp_common/combinations.hpp" + +namespace pgrouting { +namespace drivers { + +void +do_maxFlow( + const std::string &edges_sql, + const std::string &combinations_sql, + ArrayType *starts, + ArrayType *ends, + + Which which, + Flow_t* &return_tuples, size_t &return_count, + std::ostringstream &log, + std::ostringstream ¬ice, + std::ostringstream &err) { + std::string hint = ""; + + try { + if (edges_sql.empty()) { + err << "Empty edges SQL"; + return; + } + + using pgget::get_flow_edges; + using utilities::get_combinations; + using to_postgres::get_tuples; + + hint = combinations_sql; + auto combinations = get_combinations(combinations_sql, starts, ends, true); + hint = ""; + + if (combinations.empty() && !combinations_sql.empty()) { + notice << "No (source, target) pairs found"; + log << combinations_sql; + return; + } + + std::set sources; + std::set targets; + for (const auto &c : combinations) { + sources.insert(c.first); + targets.insert(c.second.begin(), c.second.end()); + } + + std::set vertices(sources); + vertices.insert(targets.begin(), targets.end()); + + if (vertices.size() != (sources.size() + targets.size())) { + err << "A source found as sink"; + return; + } + + hint = edges_sql; + auto edges = get_flow_edges(edges_sql); + hint = ""; + + if (edges.empty()) { + notice << "No edges found"; + log << edges_sql; + return; + } + + + pgrouting::graph::PgrFlowGraph digraph(edges, sources, targets, which); + + int64_t max_flow = 0; + switch (which) { + case MAXFLOW: + case PUSHRELABEL: + max_flow = digraph.push_relabel(); + break; + case EDMONDSKARP: + max_flow = digraph.edmonds_karp(); + break; + case BOYKOV: + max_flow = digraph.boykov_kolmogorov(); + break; + default: + err << "Unknown flow function" << get_name(which); + return; + } + + auto flow_edges = which == MAXFLOW? only_maxFlow_result(max_flow) : digraph.get_flow_edges(); + + return_count = get_tuples(flow_edges, return_tuples); + } catch (AssertFailedException &except) { + err << except.what(); + } catch (const std::pair& ex) { + err << ex.first; + log << ex.second; + } catch (const std::string &ex) { + err << ex; + log << hint; + } catch (std::exception &except) { + err << except.what(); + } catch (...) { + err << "Caught unknown exception!"; + } +} + +} // namespace drivers +} // namespace pgrouting diff --git a/src/max_flow/maxFlow_process.cpp b/src/max_flow/maxFlow_process.cpp new file mode 100644 index 0000000000..1cf1de8444 --- /dev/null +++ b/src/max_flow/maxFlow_process.cpp @@ -0,0 +1,87 @@ +/*PGR-GNU***************************************************************** +File: maxFlow_process.cpp + +Generated with Template by: +Copyright (c) 2025-2026 pgRouting developers +Mail: project@pgrouting.org + +Function's developer: +Copyright (c) 2016 Andrea Nardelli +Mail: nrd.nardelli@gmail.com + +------ + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + + ********************************************************************PGR-GNU*/ + +#include "process/maxFlow_process.h" + +extern "C" { +#include "c_common/postgres_connection.h" +#include "c_common/e_report.h" +#include "c_common/time_msg.h" +} + +#include +#include + +#include "c_types/flow_t.h" +#include "cpp_common/report_messages.hpp" +#include "cpp_common/utilities.hpp" +#include "cpp_common/assert.hpp" +#include "cpp_common/alloc.hpp" + +#include "drivers/maxFlow_driver.hpp" + +void pgr_process_maxFlow( + const char *edges_sql, + const char *combinations_sql, + + ArrayType *starts, ArrayType *ends, + + enum Which which, + Flow_t **result_tuples, size_t *result_count) { + pgassert(edges_sql); + pgassert(!(*result_tuples)); + pgassert(*result_count == 0); + pgr_SPI_connect(); + + std::ostringstream log; + std::ostringstream err; + std::ostringstream notice; + + clock_t start_t = clock(); + pgrouting::drivers::do_maxFlow( + edges_sql? edges_sql : "", + combinations_sql? combinations_sql : "", + starts, ends, + + which, + (*result_tuples), (*result_count), + log, notice, err); + + auto name = std::string(" processing ") + pgrouting::get_name(which); + time_msg(name.c_str(), start_t, clock()); + + if (!err.str().empty() && (*result_tuples)) { + pfree(*result_tuples); + (*result_tuples) = nullptr; + (*result_count) = 0; + } + + pgrouting::report_messages(log, notice, err); + pgr_SPI_finish(); +} diff --git a/src/max_flow/max_flow.c b/src/max_flow/max_flow.c index 8756b764ad..1f01e07092 100644 --- a/src/max_flow/max_flow.c +++ b/src/max_flow/max_flow.c @@ -31,103 +31,37 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. #include "c_common/postgres_connection.h" -#include "c_common/debug_macro.h" -#include "c_common/e_report.h" -#include "c_common/time_msg.h" -#include "drivers/max_flow/max_flow_driver.h" - #include "c_types/flow_t.h" -PGDLLEXPORT Datum -_pgr_maxflow(PG_FUNCTION_ARGS); - -static -void -process( - char *edges_sql, - char *combinations_sql, - ArrayType *starts, - ArrayType *ends, - int algorithm, - bool only_flow, - Flow_t **result_tuples, - size_t *result_count) { - if (algorithm < 1 || algorithm > 3) { - elog(ERROR, "Unknown algorithm"); - } - - pgr_SPI_connect(); - char* log_msg = NULL; - char* notice_msg = NULL; - char* err_msg = NULL; - - clock_t start_t = clock(); - pgr_do_max_flow( - edges_sql, - combinations_sql, - starts, ends, - - algorithm, - only_flow, - - result_tuples, result_count, - - &log_msg, - ¬ice_msg, - &err_msg); - - if (only_flow) { - time_msg("pgr_maxFlow(many to many)", start_t, clock()); - } else if (algorithm == 1) { - time_msg("pgr_maxFlowPushRelabel(many to many)", start_t, clock()); - } else if (algorithm == 3) { - time_msg("pgr_maxFlowEdmondsKarp(many to many)", start_t, clock()); - } else { - time_msg("pgr_maxFlowBoykovKolmogorov(many to many)", start_t, clock()); - } - - if (err_msg && (*result_tuples)) { - pfree(*result_tuples); - (*result_tuples) = NULL; - (*result_count) = 0; - } +#include "process/maxFlow_process.h" - pgr_global_report(&log_msg, ¬ice_msg, &err_msg); - - pgr_SPI_finish(); -} +PGDLLEXPORT Datum _pgr_maxflow(PG_FUNCTION_ARGS); +PG_FUNCTION_INFO_V1(_pgr_maxflow); -PG_FUNCTION_INFO_V1(_pgr_maxflow); -PGDLLEXPORT Datum -_pgr_maxflow(PG_FUNCTION_ARGS) { - FuncCallContext *funcctx; - TupleDesc tuple_desc; +PGDLLEXPORT Datum _pgr_maxflow(PG_FUNCTION_ARGS) { + FuncCallContext *funcctx; + TupleDesc tuple_desc; - /**************************************************************************/ - Flow_t *result_tuples = 0; + Flow_t *result_tuples = NULL; size_t result_count = 0; - /**************************************************************************/ if (SRF_IS_FIRSTCALL()) { - MemoryContext oldcontext; + MemoryContext oldcontext; funcctx = SRF_FIRSTCALL_INIT(); oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); - - /**********************************************************************/ - if (PG_NARGS() == 5) { /* * many to many */ - process( + pgr_process_maxFlow( text_to_cstring(PG_GETARG_TEXT_P(0)), NULL, + PG_GETARG_ARRAYTYPE_P(1), PG_GETARG_ARRAYTYPE_P(2), - PG_GETARG_INT32(3), - PG_GETARG_BOOL(4), + PG_GETARG_BOOL(4)? MAXFLOW : MAXFLOW + PG_GETARG_UINT32(3), &result_tuples, &result_count); @@ -135,20 +69,18 @@ _pgr_maxflow(PG_FUNCTION_ARGS) { /* * combinations */ - process( + pgr_process_maxFlow( text_to_cstring(PG_GETARG_TEXT_P(0)), text_to_cstring(PG_GETARG_TEXT_P(1)), + NULL, NULL, - PG_GETARG_INT32(2), - PG_GETARG_BOOL(3), + + PG_GETARG_BOOL(3)? MAXFLOW : MAXFLOW + PG_GETARG_UINT32(2), &result_tuples, &result_count); } - /* */ - /**********************************************************************/ - funcctx->max_calls = result_count; funcctx->user_fctx = result_tuples; if (get_call_result_type(fcinfo, NULL, &tuple_desc) @@ -168,14 +100,13 @@ _pgr_maxflow(PG_FUNCTION_ARGS) { result_tuples = (Flow_t *) funcctx->user_fctx; if (funcctx->call_cntr < funcctx->max_calls) { - HeapTuple tuple; - Datum result; - Datum *values; - bool *nulls; + HeapTuple tuple; + Datum result; + Datum *values; + bool* nulls; + size_t call_cntr = funcctx->call_cntr; - /**********************************************************************/ - /* MODIFY AS NEEDED */ values = palloc(6 * sizeof(Datum)); nulls = palloc(6 * sizeof(bool)); @@ -190,7 +121,6 @@ _pgr_maxflow(PG_FUNCTION_ARGS) { values[3] = Int64GetDatum(result_tuples[call_cntr].target); values[4] = Int64GetDatum(result_tuples[call_cntr].flow); values[5] = Int64GetDatum(result_tuples[call_cntr].residual_capacity); - /**********************************************************************/ tuple = heap_form_tuple(tuple_desc, values, nulls); result = HeapTupleGetDatum(tuple); diff --git a/src/max_flow/max_flow_driver.cpp b/src/max_flow/max_flow_driver.cpp deleted file mode 100644 index fd8446a01f..0000000000 --- a/src/max_flow/max_flow_driver.cpp +++ /dev/null @@ -1,172 +0,0 @@ -/*PGR-GNU***************************************************************** -File: max_flow_driver.cpp - -Generated with Template by: -Copyright (c) 2015-2026 pgRouting developers -Mail: project@pgrouting.org - -Function's developer: -Copyright (c) 2016 Andrea Nardelli -Mail: nrd.nardelli@gmail.com - ------- - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -This program is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. - -You should have received a copy of the GNU General Public License -along with this program; if not, write to the Free Software -Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - - ********************************************************************PGR-GNU*/ - -#include "drivers/max_flow/max_flow_driver.h" - -#include -#include -#include -#include - -#include "max_flow/maxflow.hpp" - -#include "cpp_common/combinations.hpp" -#include "cpp_common/pgdata_getters.hpp" -#include "cpp_common/assert.hpp" -#include "cpp_common/alloc.hpp" - -#include "c_types/ii_t_rt.h" - -void -pgr_do_max_flow( - const char *edges_sql, - const char *combinations_sql, - ArrayType *starts, - ArrayType *ends, - - int algorithm, - bool only_flow, - - Flow_t **return_tuples, size_t *return_count, - char** log_msg, - char** notice_msg, - char **err_msg) { - using pgrouting::pgr_alloc; - using pgrouting::to_pg_msg; - using pgrouting::pgr_free; - using pgrouting::utilities::get_combinations; - - std::ostringstream log; - std::ostringstream notice; - std::ostringstream err; - const char *hint = nullptr; - - try { - pgassert(!(*log_msg)); - pgassert(!(*notice_msg)); - pgassert(!(*err_msg)); - pgassert(!(*return_tuples)); - pgassert(*return_count == 0); - - hint = combinations_sql; - auto combinations = get_combinations(combinations_sql, starts, ends, true); - hint = nullptr; - - if (combinations.empty() && combinations_sql) { - *notice_msg = to_pg_msg("No (source, target) pairs found"); - *log_msg = to_pg_msg(combinations_sql); - return; - } - - std::set sources; - std::set targets; - for (const auto &c : combinations) { - sources.insert(c.first); - targets.insert(c.second.begin(), c.second.end()); - } - - std::set vertices(sources); - vertices.insert(targets.begin(), targets.end()); - - if (vertices.size() != (sources.size() + targets.size())) { - *err_msg = to_pg_msg("A source found as sink"); - return; - } - - hint = edges_sql; - auto edges = pgrouting::pgget::get_flow_edges(std::string(edges_sql)); - hint = nullptr; - - if (edges.empty()) { - *notice_msg = to_pg_msg("No edges found"); - *log_msg = to_pg_msg(edges_sql); - return; - } - - - pgrouting::graph::PgrFlowGraph digraph( - edges, sources, targets, algorithm); - // digraph.create_flow_graph(edges, sources, targets, algorithm); - - int64_t max_flow = 0; - if (algorithm == 1) { - max_flow = digraph.push_relabel(); - } else if (algorithm == 3) { - max_flow = digraph.edmonds_karp(); - } else if (algorithm == 2) { - max_flow = digraph.boykov_kolmogorov(); - } else { - log << "Unspecified algorithm!\n"; - *err_msg = to_pg_msg(log); - (*return_tuples) = NULL; - (*return_count) = 0; - return; - } - - - std::vector flow_edges; - - if (only_flow) { - Flow_t edge = {-1, -1, -1, max_flow, -1, 0, 0}; - flow_edges.push_back(edge); - } else { - flow_edges = digraph.get_flow_edges(); - } - (*return_tuples) = pgr_alloc(flow_edges.size(), (*return_tuples)); - for (size_t i = 0; i < flow_edges.size(); ++i) { - (*return_tuples)[i] = flow_edges[i]; - } - *return_count = flow_edges.size(); - - - *log_msg = to_pg_msg(log); - *notice_msg = to_pg_msg(notice); - } catch (AssertFailedException &except) { - (*return_tuples) = pgr_free(*return_tuples); - (*return_count) = 0; - err << except.what(); - *err_msg = to_pg_msg(err); - *log_msg = to_pg_msg(log); - } catch (std::exception &except) { - (*return_tuples) = pgr_free(*return_tuples); - (*return_count) = 0; - err << except.what(); - *err_msg = to_pg_msg(err); - *log_msg = to_pg_msg(log); - } catch (const std::string &ex) { - *err_msg = to_pg_msg(ex); - *log_msg = hint? to_pg_msg(hint) : to_pg_msg(log); - } catch(...) { - (*return_tuples) = pgr_free(*return_tuples); - (*return_count) = 0; - err << "Caught unknown exception!"; - *err_msg = to_pg_msg(err); - *log_msg = to_pg_msg(log); - } -} diff --git a/src/max_flow/maxflow.cpp b/src/max_flow/maxflow.cpp index b466ba0ce2..46f48ff458 100644 --- a/src/max_flow/maxflow.cpp +++ b/src/max_flow/maxflow.cpp @@ -40,17 +40,25 @@ PgrFlowGraph::PgrFlowGraph( const std::vector &edges, const std::set &source_vertices, const std::set &sink_vertices, - int algorithm) { + Which algorithm) { add_vertices(edges, source_vertices, sink_vertices); capacity = get(boost::edge_capacity, graph); rev = get(boost::edge_reverse, graph); residual_capacity = get(boost::edge_residual_capacity, graph); - if (algorithm == 1) { - insert_edges_push_relabel(edges); - } else { - insert_edges(edges); + switch (algorithm) { + case MAXFLOW: + case PUSHRELABEL: + insert_edges_push_relabel(edges); + break; + case BOYKOV: + case EDMONDSKARP: + insert_edges(edges); + break; + default: + {}; + /* Maybe do a throw */ } } diff --git a/tools/scripts/code_checker.sh b/tools/scripts/code_checker.sh index 3f52522119..2f699ef0f9 100755 --- a/tools/scripts/code_checker.sh +++ b/tools/scripts/code_checker.sh @@ -27,6 +27,7 @@ INCLUDE_ORDER=" -build/include_order:src/metrics/metrics_process.cpp, -build/include_order:src/ordering/ordering_process.cpp, -build/include_order:src/astar/astar_process.cpp, +-build/include_order:src/max_flow/maxFlow_process.cpp, -build/include_order:src/spanningTree/spanningTree_process.cpp, -build/include_order:src/allpairs/allpairs_process.cpp"