From aa6b5ebc84b22c588e7d55a91d4b63574e09dd2a Mon Sep 17 00:00:00 2001 From: cvvergara Date: Sun, 1 Mar 2026 14:15:39 -0600 Subject: [PATCH 1/8] Preparing files to accomodate bellman ford --- include/c_common/enums.h | 1 + include/cpp_common/to_postgres.hpp | 6 ++++++ src/cpp_common/to_postgres.cpp | 17 +++++++++++++++++ src/cpp_common/utilities.cpp | 4 ++++ src/dijkstra/shortestPath_driver.cpp | 21 +++++++++++++++------ 5 files changed, 43 insertions(+), 6 deletions(-) diff --git a/include/c_common/enums.h b/include/c_common/enums.h index b2b5fced59..b98958672d 100644 --- a/include/c_common/enums.h +++ b/include/c_common/enums.h @@ -33,6 +33,7 @@ enum Which { /** shortest_paths */ DIJKSTRA = 21, WITHPOINTS, OLD_WITHPOINTS, BDDIJKSTRA, EDWARDMOORE, DAGSP, + BELLMANFORD, /** allpairs **/ FLOYD = 31, JOHNSON, /** metrics **/ diff --git a/include/cpp_common/to_postgres.hpp b/include/cpp_common/to_postgres.hpp index e36a0c0aab..33dba34686 100644 --- a/include/cpp_common/to_postgres.hpp +++ b/include/cpp_common/to_postgres.hpp @@ -74,6 +74,12 @@ size_t get_tuples(const std::deque&, MST_rt*&); */ size_t get_tuples(const std::vector&, Flow_t*&); +/* + * @brief get tuples for Path_rt + */ +size_t +get_tuples(const std::vector&, Path_rt*&); + /* * @brief get tuples for spanning tree driver */ diff --git a/src/cpp_common/to_postgres.cpp b/src/cpp_common/to_postgres.cpp index cdc6b853ba..a5a09ecbf4 100644 --- a/src/cpp_common/to_postgres.cpp +++ b/src/cpp_common/to_postgres.cpp @@ -302,5 +302,22 @@ get_tuples( return count; } +size_t +get_tuples( + const std::vector &paths, + Path_rt* &tuples) { + pgassert(!tuples); + + auto count = paths.size(); + if (count == 0) return 0; + + tuples = pgr_alloc(count, tuples); + + for (size_t i = 0; i < paths.size(); ++i) { + tuples[i] = paths[i]; + } + return count; +} + } // namespace to_postgres } // namespace pgrouting diff --git a/src/cpp_common/utilities.cpp b/src/cpp_common/utilities.cpp index 3a94081a9a..e45f48ef42 100644 --- a/src/cpp_common/utilities.cpp +++ b/src/cpp_common/utilities.cpp @@ -132,6 +132,9 @@ get_name(Which which, bool is_only_cost, bool is_near, bool is_matrix) { case DAGSP : base = "pgr_dagShortestPath"; break; + case BELLMANFORD : + base = "pgr_bellmanFord"; + break; case OLD_WITHPOINTS: case WITHPOINTS: base = "pgr_withPoints"; @@ -174,6 +177,7 @@ estimate_drivingSide(char driving_side, Which which) { case BDASTAR : case DAGSP : case EDWARDMOORE: + case BELLMANFORD : case BDDIJKSTRA: case DIJKSTRA: return ' '; diff --git a/src/dijkstra/shortestPath_driver.cpp b/src/dijkstra/shortestPath_driver.cpp index 9edf78cd1c..dc5bf69bf2 100644 --- a/src/dijkstra/shortestPath_driver.cpp +++ b/src/dijkstra/shortestPath_driver.cpp @@ -53,6 +53,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. #include "dijkstra/dijkstra.hpp" #include "bellman_ford/edwardMoore.hpp" #include "bdDijkstra/bdDijkstra.hpp" +#include "bellman_ford/bellman_ford.hpp" #include "withPoints/withPoints.hpp" #include "dagShortestPath/dagShortestPath.hpp" @@ -155,6 +156,7 @@ do_shortestPath( using pgrouting::algorithms::bdDijkstra; using pgrouting::algorithms::edwardMoore; using pgrouting::algorithms::dagShortestPath; + using pgrouting::functions::bellmanFord; hint = combinations_sql; auto combinations = get_combinations(combinations_sql, starts, ends, normal, is_matrix); @@ -225,6 +227,7 @@ do_shortestPath( UndirectedGraph undigraph; std::deque paths; + if (directed) { digraph.insert_edges(edges); switch (which) { @@ -235,14 +238,17 @@ do_shortestPath( post_process(paths, only_cost, normal, n, global); break; case BDDIJKSTRA: - paths = bdDijkstra(digraph, combinations, only_cost); - break; + paths = bdDijkstra(digraph, combinations, only_cost); + break; case EDWARDMOORE: - paths = edwardMoore(digraph, combinations); - break; + paths = edwardMoore(digraph, combinations); + break; case DAGSP: - paths = dagShortestPath(digraph, combinations, only_cost); - break; + paths = dagShortestPath(digraph, combinations, only_cost); + break; + case BELLMANFORD: + paths = bellmanFord(digraph, combinations, only_cost); + break; default: err << "INTERNAL: wrong function call: " << which; return; @@ -262,6 +268,9 @@ do_shortestPath( case EDWARDMOORE: paths = edwardMoore(undigraph, combinations); break; + case BELLMANFORD: + paths = bellmanFord(undigraph, combinations, only_cost); + break; default: err << "INTERNAL: wrong function call: " << which; return; From c0c36b3efe42d1d62dce17283e4653946479e3dd Mon Sep 17 00:00:00 2001 From: cvvergara Date: Sun, 1 Mar 2026 14:18:30 -0600 Subject: [PATCH 2/8] (bellmanFord) using the new shortestPath process & driver --- include/bellman_ford/bellman_ford.hpp | 19 ++++- src/bellman_ford/CMakeLists.txt | 3 - src/bellman_ford/bellman_ford.c | 102 ++++++++++---------------- 3 files changed, 56 insertions(+), 68 deletions(-) diff --git a/include/bellman_ford/bellman_ford.hpp b/include/bellman_ford/bellman_ford.hpp index ef6b32373b..9fbdcab446 100644 --- a/include/bellman_ford/bellman_ford.hpp +++ b/include/bellman_ford/bellman_ford.hpp @@ -50,6 +50,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. #include "c_types/ii_t_rt.h" namespace pgrouting { +namespace algorithms { template < class G > class Pgr_bellman_ford : public pgrouting::Pgr_messages { @@ -181,7 +182,23 @@ class Pgr_bellman_ford : public pgrouting::Pgr_messages { //@} }; - +} // namespace algorithms + +namespace functions { + +template +std::deque +bellmanFord( + G &graph, + const std::map> &combinations, + bool only_cost = false) { + algorithms::Pgr_bellman_ford fn_bellman_ford; + auto paths = fn_bellman_ford.bellman_ford(graph, combinations, only_cost); + for (auto &p : paths) p.recalculate_agg_cost(); + return paths; +} + +} // namespace functions } // namespace pgrouting #endif // INCLUDE_BELLMAN_FORD_BELLMAN_FORD_HPP_ diff --git a/src/bellman_ford/CMakeLists.txt b/src/bellman_ford/CMakeLists.txt index f8195257a2..d78ba48919 100644 --- a/src/bellman_ford/CMakeLists.txt +++ b/src/bellman_ford/CMakeLists.txt @@ -4,8 +4,5 @@ ADD_LIBRARY(bellman_ford OBJECT bellman_ford.c - bellman_ford_driver.cpp - #bellman_ford_neg.c - #bellman_ford_neg_driver.cpp edwardMoore.c ) diff --git a/src/bellman_ford/bellman_ford.c b/src/bellman_ford/bellman_ford.c index 37adecf2dc..b767c87ac5 100644 --- a/src/bellman_ford/bellman_ford.c +++ b/src/bellman_ford/bellman_ford.c @@ -35,59 +35,11 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. #include "c_common/debug_macro.h" #include "c_common/e_report.h" #include "c_common/time_msg.h" -#include "drivers/bellman_ford/bellman_ford_driver.h" +#include "process/shortestPath_process.h" PGDLLEXPORT Datum _pgr_bellmanford(PG_FUNCTION_ARGS); PG_FUNCTION_INFO_V1(_pgr_bellmanford); -static -void -process( - char* edges_sql, - char *combinations_sql, - ArrayType *starts, - ArrayType *ends, - bool directed, - bool only_cost, - - Path_rt **result_tuples, - size_t *result_count) { - pgr_SPI_connect(); - char* log_msg = NULL; - char* notice_msg = NULL; - char* err_msg = NULL; - (*result_tuples) = NULL; - (*result_count) = 0; - - clock_t start_t = clock(); - pgr_do_bellman_ford( - edges_sql, - combinations_sql, - starts, ends, - - directed, - only_cost, - - result_tuples, - result_count, - - &log_msg, - ¬ice_msg, - &err_msg); - - time_msg(" processing pgr_bellman_ford", start_t, clock()); - - if (err_msg && (*result_tuples)) { - pfree(*result_tuples); - (*result_tuples) = NULL; - (*result_count) = 0; - } - - pgr_global_report(&log_msg, ¬ice_msg, &err_msg); - - pgr_SPI_finish(); -} - PGDLLEXPORT Datum _pgr_bellmanford(PG_FUNCTION_ARGS) { FuncCallContext *funcctx; @@ -105,27 +57,48 @@ _pgr_bellmanford(PG_FUNCTION_ARGS) { /* * many to many */ - process( + pgr_process_shortestPath( text_to_cstring(PG_GETARG_TEXT_P(0)), NULL, + NULL, + PG_GETARG_ARRAYTYPE_P(1), PG_GETARG_ARRAYTYPE_P(2), + PG_GETARG_BOOL(3), PG_GETARG_BOOL(4), + true, + + 0, + true, + ' ', + true, + + BELLMANFORD, &result_tuples, &result_count); } else if (PG_NARGS() == 4) { /* - * combinations + * Combinations */ - process( + pgr_process_shortestPath( text_to_cstring(PG_GETARG_TEXT_P(0)), - text_to_cstring(PG_GETARG_TEXT_P(1)), - NULL, NULL, + text_to_cstring(PG_GETARG_TEXT_P(1)), + + NULL, NULL, + PG_GETARG_BOOL(2), PG_GETARG_BOOL(3), + true, + + 0, + true, + ' ', + true, + + BELLMANFORD, &result_tuples, &result_count); } @@ -153,6 +126,7 @@ _pgr_bellmanford(PG_FUNCTION_ARGS) { Datum result; Datum *values; bool* nulls; + size_t call_cntr = funcctx->call_cntr; size_t numb = 8; values = palloc(numb * sizeof(Datum)); @@ -163,18 +137,18 @@ _pgr_bellmanford(PG_FUNCTION_ARGS) { nulls[i] = false; } - int64_t seq = funcctx->call_cntr == 0? 1 : result_tuples[funcctx->call_cntr - 1].start_id; + int64_t seq = call_cntr == 0? 1 : result_tuples[call_cntr - 1].start_id; - values[0] = Int32GetDatum((int32_t)funcctx->call_cntr + 1); + values[0] = Int32GetDatum((int32_t)call_cntr + 1); values[1] = Int32GetDatum((int32_t)seq); - values[2] = Int64GetDatum(result_tuples[funcctx->call_cntr].start_id); - values[3] = Int64GetDatum(result_tuples[funcctx->call_cntr].end_id); - values[4] = Int64GetDatum(result_tuples[funcctx->call_cntr].node); - values[5] = Int64GetDatum(result_tuples[funcctx->call_cntr].edge); - values[6] = Float8GetDatum(result_tuples[funcctx->call_cntr].cost); - values[7] = Float8GetDatum(result_tuples[funcctx->call_cntr].agg_cost); - - result_tuples[funcctx->call_cntr].start_id = result_tuples[funcctx->call_cntr].edge < 0? 1 : seq + 1; + values[2] = Int64GetDatum(result_tuples[call_cntr].start_id); + values[3] = Int64GetDatum(result_tuples[call_cntr].end_id); + values[4] = Int64GetDatum(result_tuples[call_cntr].node); + values[5] = Int64GetDatum(result_tuples[call_cntr].edge); + values[6] = Float8GetDatum(result_tuples[call_cntr].cost); + values[7] = Float8GetDatum(result_tuples[call_cntr].agg_cost); + + result_tuples[call_cntr].start_id = result_tuples[call_cntr].edge < 0? 1 : seq + 1; tuple = heap_form_tuple(tuple_desc, values, nulls); result = HeapTupleGetDatum(tuple); From 51083ef4d07a7b11fad0d138b33721b85efa9c41 Mon Sep 17 00:00:00 2001 From: cvvergara Date: Sun, 1 Mar 2026 14:20:40 -0600 Subject: [PATCH 3/8] Removing unused code --- .../bellman_ford/bellman_ford_driver.h | 76 -------- .../bellman_ford/bellman_ford_neg_driver.h | 76 -------- src/bellman_ford/bellman_ford_driver.cpp | 163 ---------------- src/bellman_ford/bellman_ford_neg_driver.cpp | 177 ------------------ 4 files changed, 492 deletions(-) delete mode 100644 include/drivers/bellman_ford/bellman_ford_driver.h delete mode 100644 include/drivers/bellman_ford/bellman_ford_neg_driver.h delete mode 100644 src/bellman_ford/bellman_ford_driver.cpp delete mode 100644 src/bellman_ford/bellman_ford_neg_driver.cpp diff --git a/include/drivers/bellman_ford/bellman_ford_driver.h b/include/drivers/bellman_ford/bellman_ford_driver.h deleted file mode 100644 index f989f2ce32..0000000000 --- a/include/drivers/bellman_ford/bellman_ford_driver.h +++ /dev/null @@ -1,76 +0,0 @@ -/*PGR-GNU***************************************************************** -File: bellman_ford_driver.h - -Generated with Template by: -Copyright (c) 2007-2026 pgRouting developers -Mail: project@pgrouting.org - -Function's developer: -Copyright (c) 2018 Sourabh Garg -Mail: sourabh.garg.mat@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_BELLMAN_FORD_BELLMAN_FORD_DRIVER_H_ -#define INCLUDE_DRIVERS_BELLMAN_FORD_BELLMAN_FORD_DRIVER_H_ -#pragma once - - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include - -#ifdef __cplusplus -} -#endif - -#include "cpp_common/undefPostgresDefine.hpp" - -#ifdef __cplusplus -# include -# include -using Path_rt = struct Path_rt; -#else -# include -# include -typedef struct Path_rt Path_rt; -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -void pgr_do_bellman_ford( - const char*, - const char*, - ArrayType*, ArrayType*, - - bool, bool, - - Path_rt**, size_t*, - char**, char**, char**); - -#ifdef __cplusplus -} -#endif - -#endif // INCLUDE_DRIVERS_BELLMAN_FORD_BELLMAN_FORD_DRIVER_H_ diff --git a/include/drivers/bellman_ford/bellman_ford_neg_driver.h b/include/drivers/bellman_ford/bellman_ford_neg_driver.h deleted file mode 100644 index 206888664a..0000000000 --- a/include/drivers/bellman_ford/bellman_ford_neg_driver.h +++ /dev/null @@ -1,76 +0,0 @@ -/*PGR-GNU***************************************************************** -File: bellman_ford_neg_driver.h - -Generated with Template by: -Copyright (c) 2007-2026 pgRouting developers -Mail: project@pgrouting.org - -Function's developer: -Copyright (c) 2018 Sourabh Garg -Mail: sourabh.garg.mat@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_BELLMAN_FORD_BELLMAN_FORD_NEG_DRIVER_H_ -#define INCLUDE_DRIVERS_BELLMAN_FORD_BELLMAN_FORD_NEG_DRIVER_H_ -#pragma once - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include - -#ifdef __cplusplus -} -#endif - -#include "cpp_common/undefPostgresDefine.hpp" - -#ifdef __cplusplus -# include -# include -using Path_rt = struct Path_rt; -#else -# include -# include -typedef struct Path_rt Path_rt; -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -void pgr_do_bellman_ford_neg( - const char*, - const char*, - const char*, - ArrayType*, ArrayType*, - - bool, bool, - - Path_rt**, size_t*, - char**, char**, char**); - -#ifdef __cplusplus -} -#endif - -#endif // INCLUDE_DRIVERS_BELLMAN_FORD_BELLMAN_FORD_NEG_DRIVER_H_ diff --git a/src/bellman_ford/bellman_ford_driver.cpp b/src/bellman_ford/bellman_ford_driver.cpp deleted file mode 100644 index 003cf0dac7..0000000000 --- a/src/bellman_ford/bellman_ford_driver.cpp +++ /dev/null @@ -1,163 +0,0 @@ -/*PGR-GNU***************************************************************** -File: bellman_ford_driver.cpp - -Generated with Template by: -Copyright (c) 2015-2026 pgRouting developers -Mail: project@pgrouting.org - -Function's developer: -Copyright (c) 2018 Sourabh Garg -Mail: sourabh.garg.mat@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/bellman_ford/bellman_ford_driver.h" - -#include -#include -#include -#include -#include -#include -#include - -#include "bellman_ford/bellman_ford.hpp" - -#include "cpp_common/combinations.hpp" -#include "cpp_common/pgdata_getters.hpp" -#include "cpp_common/to_postgres.hpp" -#include "cpp_common/assert.hpp" - -#include "c_types/ii_t_rt.h" - -namespace { - - -template -std::deque -bellman_ford( - G &graph, - const std::map> &combinations, - bool only_cost = false) { - pgrouting::Pgr_bellman_ford fn_bellman_ford; - auto paths = fn_bellman_ford.bellman_ford(graph, combinations, only_cost); - for (auto &p : paths) p.recalculate_agg_cost(); - return paths; -} - -} // namespace - -void -pgr_do_bellman_ford( - const char *edges_sql, - const char *combinations_sql, - ArrayType *starts, - ArrayType *ends, - bool directed, - bool only_cost, - - Path_rt **return_tuples, - size_t *return_count, - char ** log_msg, - char ** notice_msg, - char ** err_msg) { - using pgrouting::Path; - using pgrouting::to_pg_msg; - using pgrouting::pgr_free; - using pgrouting::utilities::get_combinations; - using pgrouting::pgget::get_edges; - - std::ostringstream log; - std::ostringstream err; - std::ostringstream notice; - const char *hint = nullptr; - - try { - pgassert(!(*log_msg)); - pgassert(!(*notice_msg)); - pgassert(!(*err_msg)); - pgassert(!(*return_tuples)); - pgassert(*return_count == 0); - - using pgrouting::to_postgres::get_tuples; - - - 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; - } - - hint = edges_sql; - auto edges = get_edges(std::string(edges_sql), true, false); - - if (edges.empty()) { - *notice_msg = to_pg_msg("No edges found"); - *log_msg = hint? to_pg_msg(hint) : to_pg_msg(log); - return; - } - hint = nullptr; - - std::deque paths; - if (directed) { - pgrouting::DirectedGraph digraph; - digraph.insert_edges(edges); - paths = bellman_ford(digraph, combinations, only_cost); - } else { - pgrouting::UndirectedGraph undigraph; - undigraph.insert_edges(edges); - paths = bellman_ford(undigraph, combinations, only_cost); - } - - (*return_count) = get_tuples(paths, (*return_tuples)); - - if (*return_count == 0) { - *log_msg = to_pg_msg("No paths found"); - return; - } - - *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 (const std::string &ex) { - *err_msg = to_pg_msg(ex); - *log_msg = hint? to_pg_msg(hint) : 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(...) { - (*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/bellman_ford/bellman_ford_neg_driver.cpp b/src/bellman_ford/bellman_ford_neg_driver.cpp deleted file mode 100644 index f6e87e3e2a..0000000000 --- a/src/bellman_ford/bellman_ford_neg_driver.cpp +++ /dev/null @@ -1,177 +0,0 @@ -/*PGR-GNU***************************************************************** -File: bellman_ford_neg_driver.cpp - -Generated with Template by: -Copyright (c) 2015-2026 pgRouting developers -Mail: project@pgrouting.org - -Function's developer: -Copyright (c) 2018 Sourabh Garg -Mail: sourabh.garg.mat@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/bellman_ford/bellman_ford_neg_driver.h" - -#include -#include -#include -#include -#include -#include -#include - -#include "bellman_ford/bellman_ford.hpp" - -#include "cpp_common/combinations.hpp" -#include "cpp_common/pgdata_getters.hpp" -#include "cpp_common/alloc.hpp" -#include "cpp_common/assert.hpp" - -#include "c_types/ii_t_rt.h" - -namespace { - - -template -std::deque -bellman_ford( - G &graph, - const std::map> &combinations, - bool only_cost = false) { - pgrouting::Pgr_bellman_ford fn_bellman_ford; - auto paths = fn_bellman_ford.bellman_ford(graph, combinations, only_cost); - for (auto &p : paths) p.recalculate_agg_cost(); - return paths; -} - -} // namespace - -void -pgr_do_bellman_ford_neg( - const char *edges_sql, - const char *neg_edges_sql, - const char *combinations_sql, - ArrayType *starts, - ArrayType *ends, - - bool directed, - bool only_cost, - - Path_rt **return_tuples, - size_t *return_count, - char ** log_msg, - char ** notice_msg, - char ** err_msg) { - using pgrouting::Path; - using pgrouting::pgr_alloc; - using pgrouting::to_pg_msg; - using pgrouting::pgr_free; - using pgrouting::utilities::get_combinations; - using pgrouting::pgget::get_edges; - - std::ostringstream log; - std::ostringstream err; - std::ostringstream notice; - 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; - } - - hint = edges_sql; - auto edges = get_edges(std::string(edges_sql), true, false); - - hint = neg_edges_sql; - auto neg_edges = get_edges(std::string(neg_edges_sql), true, false); - - if (edges.empty() && neg_edges.empty()) { - *notice_msg = to_pg_msg("No edges found"); - *log_msg = hint? to_pg_msg(hint) : to_pg_msg(log); - return; - } - hint = nullptr; - - std::deque paths; - if (directed) { - pgrouting::DirectedGraph digraph; - digraph.insert_edges(edges); - digraph.insert_negative_edges(neg_edges); - paths = bellman_ford(digraph, combinations, only_cost); - } else { - pgrouting::UndirectedGraph undigraph; - undigraph.insert_edges(edges); - undigraph.insert_negative_edges(neg_edges); - paths = bellman_ford(undigraph, combinations, only_cost); - } - - size_t count(0); - count = count_tuples(paths); - - if (count == 0) { - (*return_tuples) = NULL; - (*return_count) = 0; - notice << "No paths found"; - *log_msg = to_pg_msg(notice); - return; - } - - (*return_tuples) = pgr_alloc(count, (*return_tuples)); - (*return_count) = (collapse_paths(return_tuples, paths)); - - *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 (const std::string &ex) { - *err_msg = to_pg_msg(ex); - *log_msg = hint? to_pg_msg(hint) : 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(...) { - (*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); - } -} From d3608f851116e342acf3c1ddb3e1d3115cc777ec Mon Sep 17 00:00:00 2001 From: cvvergara Date: Tue, 3 Mar 2026 09:26:18 -0600 Subject: [PATCH 4/8] Preparing files to accomodate edgeDisjointPaths --- include/c_common/enums.h | 1 + include/cpp_common/combinations.hpp | 7 +------ include/cpp_common/to_postgres.hpp | 2 +- src/cpp_common/combinations.cpp | 16 ++++------------ src/cpp_common/to_postgres.cpp | 24 +++++++++++++++++++----- src/cpp_common/utilities.cpp | 3 +++ src/dijkstra/shortestPath_driver.cpp | 18 ++++++++++++------ 7 files changed, 41 insertions(+), 30 deletions(-) diff --git a/include/c_common/enums.h b/include/c_common/enums.h index b98958672d..2d8598fcdc 100644 --- a/include/c_common/enums.h +++ b/include/c_common/enums.h @@ -34,6 +34,7 @@ enum Which { DIJKSTRA = 21, WITHPOINTS, OLD_WITHPOINTS, BDDIJKSTRA, EDWARDMOORE, DAGSP, BELLMANFORD, + EDGEDISJOINT, /** allpairs **/ FLOYD = 31, JOHNSON, /** metrics **/ diff --git a/include/cpp_common/combinations.hpp b/include/cpp_common/combinations.hpp index 500fc7bae5..9edcd7425d 100644 --- a/include/cpp_common/combinations.hpp +++ b/include/cpp_common/combinations.hpp @@ -52,12 +52,7 @@ namespace utilities { std::map> -get_combinations( - std::deque&, - const std::vector&); - -std::map> -get_combinations(const std::vector&); +get_combinations(std::deque&, const std::vector&); std::map> get_combinations(const std::string&, ArrayType*, ArrayType*, bool, bool&); diff --git a/include/cpp_common/to_postgres.hpp b/include/cpp_common/to_postgres.hpp index 33dba34686..7dd471c36b 100644 --- a/include/cpp_common/to_postgres.hpp +++ b/include/cpp_common/to_postgres.hpp @@ -78,7 +78,7 @@ size_t get_tuples(const std::vector&, Flow_t*&); * @brief get tuples for Path_rt */ size_t -get_tuples(const std::vector&, Path_rt*&); +get_tuples(std::vector&, const std::vector&, Path_rt*&); /* * @brief get tuples for spanning tree driver diff --git a/src/cpp_common/combinations.cpp b/src/cpp_common/combinations.cpp index c8e4fa3057..0544396f6f 100644 --- a/src/cpp_common/combinations.cpp +++ b/src/cpp_common/combinations.cpp @@ -85,16 +85,6 @@ get_combinations( return new_combinations; } -std::map> -get_combinations(const std::vector &combinations) { - std::map> result; - - for (const auto &row : combinations) { - result[row.d1.source].insert(row.d2.target); - } - return result; -} - /** @brief gets all the departures and destinations * @param[in] combinations_sql from the @b combinations signatures * @param[in] startsArr PostgreSQL array with the departures @@ -153,7 +143,8 @@ get_combinations( std::map> get_combinations( const std::string &combinations_sql, - ArrayType* startsArr, ArrayType* endsArr, bool normal, bool &is_matrix) { + ArrayType* startsArr, ArrayType* endsArr, + bool normal, bool &is_matrix) { using pgrouting::pgget::get_intSet; using pgrouting::pgget::get_combinations; std::map> result; @@ -185,7 +176,8 @@ get_combinations( std::map> get_combinations( const std::string &combinations_sql, - ArrayType* startsArr, ArrayType* endsArr, bool normal) { + ArrayType* startsArr, ArrayType* endsArr, + bool normal) { bool is_matrix = false; return get_combinations(combinations_sql, startsArr, endsArr, normal, is_matrix); } diff --git a/src/cpp_common/to_postgres.cpp b/src/cpp_common/to_postgres.cpp index a5a09ecbf4..33a6704b58 100644 --- a/src/cpp_common/to_postgres.cpp +++ b/src/cpp_common/to_postgres.cpp @@ -304,19 +304,33 @@ get_tuples( size_t get_tuples( - const std::vector &paths, + std::vector &paths, + const std::vector &edges, Path_rt* &tuples) { pgassert(!tuples); - auto count = paths.size(); - if (count == 0) return 0; + if (paths.empty()) return 0; - tuples = pgr_alloc(count, tuples); + /* + * Calculating the cost + */ + auto found = paths.size(); + for (const auto &e : edges) { + for (auto &r : paths) { + if (r.edge == e.id) { + r.cost = (r.node == e.source) ? e.cost : e.reverse_cost; + --found; + } + } + if (found == 0) break; + } + + tuples = pgr_alloc(paths.size(), tuples); for (size_t i = 0; i < paths.size(); ++i) { tuples[i] = paths[i]; } - return count; + return paths.size(); } } // namespace to_postgres diff --git a/src/cpp_common/utilities.cpp b/src/cpp_common/utilities.cpp index e45f48ef42..d0d223675e 100644 --- a/src/cpp_common/utilities.cpp +++ b/src/cpp_common/utilities.cpp @@ -135,6 +135,9 @@ get_name(Which which, bool is_only_cost, bool is_near, bool is_matrix) { case BELLMANFORD : base = "pgr_bellmanFord"; break; + case EDGEDISJOINT: + base = "pgr_edgeDisjointPaths"; + break; case OLD_WITHPOINTS: case WITHPOINTS: base = "pgr_withPoints"; diff --git a/src/dijkstra/shortestPath_driver.cpp b/src/dijkstra/shortestPath_driver.cpp index dc5bf69bf2..f941d4260e 100644 --- a/src/dijkstra/shortestPath_driver.cpp +++ b/src/dijkstra/shortestPath_driver.cpp @@ -53,9 +53,10 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. #include "dijkstra/dijkstra.hpp" #include "bellman_ford/edwardMoore.hpp" #include "bdDijkstra/bdDijkstra.hpp" -#include "bellman_ford/bellman_ford.hpp" #include "withPoints/withPoints.hpp" #include "dagShortestPath/dagShortestPath.hpp" +#include "bellman_ford/bellman_ford.hpp" +#include "max_flow/maxflow.hpp" namespace { @@ -157,6 +158,7 @@ do_shortestPath( using pgrouting::algorithms::edwardMoore; using pgrouting::algorithms::dagShortestPath; using pgrouting::functions::bellmanFord; + using pgrouting::functions::edgeDisjoint; hint = combinations_sql; auto combinations = get_combinations(combinations_sql, starts, ends, normal, is_matrix); @@ -228,26 +230,30 @@ do_shortestPath( std::deque paths; - if (directed) { + if (which == EDGEDISJOINT) { + auto results = edgeDisjoint(edges, combinations, directed); + return_count = get_tuples(results, edges, return_tuples); + return; + } else if (directed) { digraph.insert_edges(edges); switch (which) { case WITHPOINTS: case OLD_WITHPOINTS: case DIJKSTRA: - paths = dijkstra(digraph, combinations, only_cost, n); + paths = dijkstra(digraph, combinations, only_cost, n); post_process(paths, only_cost, normal, n, global); break; case BDDIJKSTRA: - paths = bdDijkstra(digraph, combinations, only_cost); + paths = bdDijkstra(digraph, combinations, only_cost); break; case EDWARDMOORE: - paths = edwardMoore(digraph, combinations); + paths = edwardMoore(digraph, combinations); break; case DAGSP: paths = dagShortestPath(digraph, combinations, only_cost); break; case BELLMANFORD: - paths = bellmanFord(digraph, combinations, only_cost); + paths = bellmanFord(digraph, combinations, only_cost); break; default: err << "INTERNAL: wrong function call: " << which; From 1454baacc4bca02a968551b013e8395bc411805e Mon Sep 17 00:00:00 2001 From: cvvergara Date: Tue, 3 Mar 2026 09:27:13 -0600 Subject: [PATCH 5/8] (edgeDisjointPaths) using the new shortestPath process & driver --- include/max_flow/maxflow.hpp | 6 ++ src/max_flow/CMakeLists.txt | 3 +- src/max_flow/edge_disjoint_paths.c | 154 ++++++++++++----------------- src/max_flow/maxflow.cpp | 51 +++++++++- 4 files changed, 121 insertions(+), 93 deletions(-) diff --git a/include/max_flow/maxflow.hpp b/include/max_flow/maxflow.hpp index 0443ebd5f3..3bf8301e58 100644 --- a/include/max_flow/maxflow.hpp +++ b/include/max_flow/maxflow.hpp @@ -198,6 +198,12 @@ class PgrFlowGraph { }; } // namespace graph + +namespace functions { + +std::vector edgeDisjoint(std::vector, const std::map>&, bool); + +} // namespace functions } // namespace pgrouting #endif // INCLUDE_MAX_FLOW_MAXFLOW_HPP_ diff --git a/src/max_flow/CMakeLists.txt b/src/max_flow/CMakeLists.txt index 47cd593645..57e1dd27ed 100644 --- a/src/max_flow/CMakeLists.txt +++ b/src/max_flow/CMakeLists.txt @@ -11,11 +11,10 @@ ADD_LIBRARY(max_flow OBJECT maxFlow_process.cpp maximum_cardinality_matching_driver.cpp - edge_disjoint_paths_driver.cpp minCostMaxFlow_driver.cpp maximumcardinalitymatching.cpp maxflow.cpp flowgraph.cpp minCostMaxFlow.cpp - ) +) diff --git a/src/max_flow/edge_disjoint_paths.c b/src/max_flow/edge_disjoint_paths.c index a5ff2d4af7..8d48509a15 100644 --- a/src/max_flow/edge_disjoint_paths.c +++ b/src/max_flow/edge_disjoint_paths.c @@ -28,102 +28,77 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ********************************************************************PGR-GNU*/ #include - #include "c_common/postgres_connection.h" - #include "c_types/path_rt.h" -#include "c_common/debug_macro.h" -#include "c_common/e_report.h" -#include "c_common/time_msg.h" -#include "drivers/max_flow/edge_disjoint_paths_driver.h" +#include "process/shortestPath_process.h" PGDLLEXPORT Datum _pgr_edgedisjointpaths(PG_FUNCTION_ARGS); - -static -void -process( - char *edges_sql, - char *combinations_sql, - ArrayType *starts, - ArrayType *ends, - - bool directed, - Path_rt **result_tuples, - size_t *result_count) { - pgr_SPI_connect(); - char* log_msg = NULL; - char* notice_msg = NULL; - char* err_msg = NULL; - - clock_t start_t = clock(); - pgr_do_edge_disjoint_paths( - edges_sql, - combinations_sql, - starts, ends, - directed, - - result_tuples, result_count, - - &log_msg, - ¬ice_msg, - &err_msg); - time_msg("pgr_edgeDisjointPaths(many to many)", start_t, clock()); - - if (err_msg && (*result_tuples)) { - pfree(*result_tuples); - (*result_tuples) = NULL; - (*result_count) = 0; - } - - pgr_global_report(&log_msg, ¬ice_msg, &err_msg); - - pgr_SPI_finish(); -} - PG_FUNCTION_INFO_V1(_pgr_edgedisjointpaths); + PGDLLEXPORT Datum _pgr_edgedisjointpaths(PG_FUNCTION_ARGS) { - FuncCallContext *funcctx; - TupleDesc tuple_desc; + FuncCallContext *funcctx; + TupleDesc tuple_desc; - Path_rt *result_tuples = NULL; + Path_rt *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() == 4) { /* * many to many */ - process( + pgr_process_shortestPath( text_to_cstring(PG_GETARG_TEXT_P(0)), NULL, + NULL, + PG_GETARG_ARRAYTYPE_P(1), PG_GETARG_ARRAYTYPE_P(2), + PG_GETARG_BOOL(3), + false, + true, + + 0, + true, + ' ', + true, + + EDGEDISJOINT, &result_tuples, &result_count); } else if (PG_NARGS() == 3) { /* - * combinations + * Combinations */ - process( + pgr_process_shortestPath( text_to_cstring(PG_GETARG_TEXT_P(0)), - text_to_cstring(PG_GETARG_TEXT_P(1)), - NULL, NULL, + text_to_cstring(PG_GETARG_TEXT_P(1)), + + NULL, NULL, + PG_GETARG_BOOL(2), + false, + true, + + 0, + true, + ' ', + true, + + EDGEDISJOINT, &result_tuples, &result_count); } - funcctx->max_calls = result_count; funcctx->user_fctx = result_tuples; if (get_call_result_type(fcinfo, NULL, &tuple_desc) @@ -140,50 +115,51 @@ _pgr_edgedisjointpaths(PG_FUNCTION_ARGS) { funcctx = SRF_PERCALL_SETUP(); tuple_desc = funcctx->tuple_desc; - result_tuples = (Path_rt *) funcctx->user_fctx; + result_tuples = (Path_rt*) 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; - values = palloc(9 * sizeof(Datum)); - nulls = palloc(9 * sizeof(bool)); + size_t numb = 9; + values = palloc(numb * sizeof(Datum)); + nulls = palloc(numb * sizeof(bool)); size_t i; - for (i = 0; i < 9; ++i) { + for (i = 0; i < numb; ++i) { nulls[i] = false; } - int64_t path_id = 1; - int64_t seq = 1; - if (funcctx->call_cntr != 0) { - if (result_tuples[funcctx->call_cntr - 1].edge == -1) { - path_id = result_tuples[funcctx->call_cntr - 1].start_id + 1; - seq = 1; - } else { - path_id = result_tuples[funcctx->call_cntr - 1].start_id; - seq = result_tuples[funcctx->call_cntr - 1].end_id + 1; - } - } - values[0] = Int32GetDatum((int32_t)funcctx->call_cntr + 1); + /* from previous record: + * end_id has the sequence of this record + * start_id has the path_id of this record + * cost has the agg_cost of this record + */ + int64_t path_id = call_cntr == 0? 1 : result_tuples[call_cntr - 1].start_id; + int64_t seq = call_cntr == 0? 1 : result_tuples[call_cntr - 1].end_id; + double agg_cost = call_cntr == 0? 0 : result_tuples[call_cntr - 1].cost; + + values[0] = Int32GetDatum((int32_t)call_cntr + 1); values[1] = Int32GetDatum((int32_t)path_id); values[2] = Int32GetDatum((int32_t)seq); - values[3] = Int64GetDatum(result_tuples[funcctx->call_cntr].start_id); - values[4] = Int64GetDatum(result_tuples[funcctx->call_cntr].end_id); - values[5] = Int64GetDatum(result_tuples[funcctx->call_cntr].node); - values[6] = Int64GetDatum(result_tuples[funcctx->call_cntr].edge); - values[7] = Float8GetDatum(result_tuples[funcctx->call_cntr].cost); - values[8] = Float8GetDatum(result_tuples[funcctx->call_cntr].agg_cost); + values[3] = Int64GetDatum(result_tuples[call_cntr].start_id); + values[4] = Int64GetDatum(result_tuples[call_cntr].end_id); + values[5] = Int64GetDatum(result_tuples[call_cntr].node); + values[6] = Int64GetDatum(result_tuples[call_cntr].edge); + values[7] = Float8GetDatum(result_tuples[call_cntr].cost); + values[8] = Float8GetDatum(agg_cost); /* - * storing in the previous record values to use on the next record + * storing in this record values to use on the next record */ - result_tuples[funcctx->call_cntr].start_id = path_id; - result_tuples[funcctx->call_cntr].end_id = seq; + result_tuples[call_cntr].start_id = result_tuples[call_cntr].edge == -1? path_id + 1 : path_id; + result_tuples[call_cntr].end_id = result_tuples[call_cntr].edge == -1? 1 : seq + 1; + result_tuples[call_cntr].cost = result_tuples[call_cntr].edge == -1? + 0 : agg_cost + result_tuples[call_cntr].cost; tuple = heap_form_tuple(tuple_desc, values, nulls); result = HeapTupleGetDatum(tuple); diff --git a/src/max_flow/maxflow.cpp b/src/max_flow/maxflow.cpp index 46f48ff458..2990c21b0b 100644 --- a/src/max_flow/maxflow.cpp +++ b/src/max_flow/maxflow.cpp @@ -31,6 +31,31 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. #include #include #include +#include + +namespace { + +std::vector +single_execution( + std::vector edges, + int64_t source, + int64_t target, + bool directed) { + std::set set_source_vertices; + std::set set_sink_vertices; + set_source_vertices.insert(source); + set_sink_vertices.insert(target); + pgrouting::graph::PgrFlowGraph G( + edges, + set_source_vertices, + set_sink_vertices, directed); + + /* + * boykov_kolmogorov is only for directed graphs + */ + return G.edge_disjoint_paths(); +} +} // namespace namespace pgrouting { namespace graph { @@ -309,8 +334,30 @@ PgrFlowGraph::get_edge_disjoint_paths( return path_elements; } +} // namespace graph +namespace functions { -} // namespace graph -} // namespace pgrouting +std::vector +edgeDisjoint( + std::vector edges, + const std::map> & combinations, + bool directed) { + std::vector results; + for (const auto &c : combinations) { + for (const auto &t : c.second) { + /* + * a source can not be a sink + * aka there is no path + */ + if (c.first == t) continue; + auto result = single_execution(edges, c.first, t, directed); + results.insert(results.end(), result.begin(), result.end()); + } + } + return results; +} + +} // namespace functions +} // namespace pgrouting From 2f683ba0a3ff5a48907fbd8c46a26803d320cc03 Mon Sep 17 00:00:00 2001 From: cvvergara Date: Tue, 3 Mar 2026 09:27:48 -0600 Subject: [PATCH 6/8] Removing unused code --- .../max_flow/edge_disjoint_paths_driver.h | 76 ------- src/max_flow/edge_disjoint_paths_driver.cpp | 211 ------------------ 2 files changed, 287 deletions(-) delete mode 100644 include/drivers/max_flow/edge_disjoint_paths_driver.h delete mode 100644 src/max_flow/edge_disjoint_paths_driver.cpp diff --git a/include/drivers/max_flow/edge_disjoint_paths_driver.h b/include/drivers/max_flow/edge_disjoint_paths_driver.h deleted file mode 100644 index bd8f90d776..0000000000 --- a/include/drivers/max_flow/edge_disjoint_paths_driver.h +++ /dev/null @@ -1,76 +0,0 @@ -/*PGR-GNU***************************************************************** -File: edge_disjoint_paths_driver.h - -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_MAX_FLOW_EDGE_DISJOINT_PATHS_DRIVER_H_ -#define INCLUDE_DRIVERS_MAX_FLOW_EDGE_DISJOINT_PATHS_DRIVER_H_ -#pragma once - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include - -#ifdef __cplusplus -} -#endif - -#include "cpp_common/undefPostgresDefine.hpp" - -#ifdef __cplusplus -# include -# include -using Path_rt = struct Path_rt; -#else -# include -# include -typedef struct Path_rt Path_rt; -#endif - - -#ifdef __cplusplus -extern "C" { -#endif - -void pgr_do_edge_disjoint_paths( - const char*, - const char*, - ArrayType*, ArrayType*, - - bool, - - Path_rt**, size_t *, - char**, char**, char**); - -#ifdef __cplusplus -} -#endif - -#endif // INCLUDE_DRIVERS_MAX_FLOW_EDGE_DISJOINT_PATHS_DRIVER_H_ diff --git a/src/max_flow/edge_disjoint_paths_driver.cpp b/src/max_flow/edge_disjoint_paths_driver.cpp deleted file mode 100644 index d22c727da5..0000000000 --- a/src/max_flow/edge_disjoint_paths_driver.cpp +++ /dev/null @@ -1,211 +0,0 @@ -/*PGR-GNU***************************************************************** -File: edge_disjoint_paths_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/edge_disjoint_paths_driver.h" - -#include -#include -#include -#include - -#include "max_flow/maxflow.hpp" - -#include "cpp_common/pgdata_getters.hpp" -#include "cpp_common/combinations.hpp" -#include "cpp_common/identifiers.hpp" -#include "cpp_common/assert.hpp" -#include "cpp_common/alloc.hpp" - -#include "c_types/ii_t_rt.h" - - -namespace { - -std::vector -single_execution( - std::vector edges, - int64_t source, - int64_t target, - bool directed) { - std::set set_source_vertices; - std::set set_sink_vertices; - set_source_vertices.insert(source); - set_sink_vertices.insert(target); - pgrouting::graph::PgrFlowGraph G( - edges, - set_source_vertices, - set_sink_vertices, directed); - - /* - * boykov_kolmogorov is only for directed graphs - */ - return G.edge_disjoint_paths(); -} - -} // namespace - -void -pgr_do_edge_disjoint_paths( - const char *edges_sql, - const char *combinations_sql, - ArrayType *starts, - ArrayType *ends, - bool directed, - Path_rt **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; - } - - hint = edges_sql; - auto edges = pgrouting::pgget::get_edges(std::string(edges_sql), true, false); - hint = nullptr; - - if (edges.empty()) { - *notice_msg = to_pg_msg("No edges found"); - *log_msg = to_pg_msg(edges_sql); - return; - } - - std::vector paths; - for (const auto &c : combinations) { - for (const auto &t : c.second) { - /* - * a source can not be a sink - * aka there is no path - */ - if (c.first == t) continue; - auto path = single_execution( - edges, - c.first, - t, - directed); - paths.insert(paths.end(), path.begin(), path.end()); - } - } - - if (paths.empty()) { - *return_tuples = nullptr; - *return_count = 0; - return; - } - - /* - * Initializing the cost - */ - for (auto &r : paths) { - r.agg_cost = r.cost = 0; - } - - /* - * Calculating the cost - */ - auto found = paths.size(); - for (const auto &e : edges) { - for (auto &r : paths) { - if (r.edge == e.id) { - r.cost = (r.node == e.source) ? - e.cost : e.reverse_cost; - --found; - } - } - if (found == 0) break; - } - - /* - * Calculating the agg_cost - */ - auto prev = paths[0]; - for (auto &r : paths) { - if (&r == &paths[0] || prev.edge < 0) { - r.agg_cost = 0; - } else { - r.agg_cost = prev.agg_cost + prev.cost; - } - prev = r; - } - - (*return_tuples) = pgr_alloc(paths.size(), (*return_tuples)); - for (size_t i = 0; i < paths.size(); ++i) { - (*return_tuples)[i] = paths[i]; - } - *return_count = paths.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); - } -} From c16de7c5b2de8d0b024bd8319cfe4a8b7debcfa4 Mon Sep 17 00:00:00 2001 From: cvvergara Date: Tue, 3 Mar 2026 18:24:08 -0600 Subject: [PATCH 7/8] Updating release notes and news --- NEWS.md | 2 ++ doc/src/release_notes.rst | 2 ++ 2 files changed, 4 insertions(+) diff --git a/NEWS.md b/NEWS.md index 591db40a52..4bf76bb6c6 100644 --- a/NEWS.md +++ b/NEWS.md @@ -22,6 +22,8 @@ To see all issues & pull requests closed by this release see the * [#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 +* [#3089](https://github.com/pgRouting/pgrouting/issues/3089): edgeDisjoint and bellmanFord use shortestPath driver and + process ## pgRouting 4.0 diff --git a/doc/src/release_notes.rst b/doc/src/release_notes.rst index 9104cc6b11..736eeb7778 100644 --- a/doc/src/release_notes.rst +++ b/doc/src/release_notes.rst @@ -47,6 +47,8 @@ To see all issues & pull requests closed by this release see the * :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 +* :issue:`3089`: edgeDisjoint and bellmanFord use shortestPath driver and + process pgRouting 4.0 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ From 5e217dd1a079e4b9ec9fa579384a76dbce37693d Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 4 Mar 2026 00:25:48 +0000 Subject: [PATCH 8/8] Update locale: commit c16de7c5b2 --- locale/en/LC_MESSAGES/pgrouting_doc_strings.po | 7 ++++++- locale/pot/pgrouting_doc_strings.pot | 5 ++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/locale/en/LC_MESSAGES/pgrouting_doc_strings.po b/locale/en/LC_MESSAGES/pgrouting_doc_strings.po index 8edb97b173..d7bae495fc 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-03-01 21:16+0000\n" +"POT-Creation-Date: 2026-03-04 00:25+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -3966,6 +3966,11 @@ msgid "" "create and use a process and driver" msgstr "" +msgid "" +"`#3089 `__: edgeDisjoint " +"and bellmanFord use shortestPath driver and process" +msgstr "" + msgid "All releases" msgstr "" diff --git a/locale/pot/pgrouting_doc_strings.pot b/locale/pot/pgrouting_doc_strings.pot index e4721ccc0b..816ae887c8 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-03-01 21:16+0000\n" +"POT-Creation-Date: 2026-03-04 00:25+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -3553,6 +3553,9 @@ msgstr "" msgid "`#3086 `__: MaxFlow: create and use a process and driver" msgstr "" +msgid "`#3089 `__: edgeDisjoint and bellmanFord use shortestPath driver and process" +msgstr "" + msgid "All releases" msgstr ""