diff --git a/NEWS b/NEWS index 7926cb298c2..143bdae7e19 100644 --- a/NEWS +++ b/NEWS @@ -1,4 +1,12 @@ +pgRouting 3.1.0 Release Notes +------------------------------------------------------------------------------- + +*New proposed functions* + +* pgr_dijkstra(combinations) + + pgRouting 3.0.0 Release Notes ------------------------------------------------------------------------------- diff --git a/doc/dijkstra/pgr_dijkstra.rst b/doc/dijkstra/pgr_dijkstra.rst index 20a4afb70a3..1d3206a6205 100644 --- a/doc/dijkstra/pgr_dijkstra.rst +++ b/doc/dijkstra/pgr_dijkstra.rst @@ -20,6 +20,12 @@ In particular, the Dijkstra algorithm implemented by Boost.Graph. .. rubric:: Availability +* Version 3.1.0 + + * New **Proposed** functions: + + * pgr_dijkstra(combinations sql) + * Version 3.0.0 * **Official** functions @@ -96,6 +102,7 @@ Signatures pgr_dijkstra(edges_sql, start_vid, end_vids [, directed]) pgr_dijkstra(edges_sql, start_vids, end_vid [, directed]) pgr_dijkstra(edges_sql, start_vids, end_vids [, directed]) + pgr_dijkstra(edges_sql, combinations_sql [, directed]) RETURNS SET OF (seq, path_seq [, start_vid] [, end_vid], node, edge, cost, agg_cost) OR EMPTY SET @@ -188,22 +195,42 @@ Many to Many :start-after: -- q5 :end-before: -- q6 +.. index:: + single: dijkstra(Combinations) + +Combinations SQL +............................................................................... + +.. code-block:: none + + pgr_dijkstra(TEXT edges_sql, TEXT combination_sql, BOOLEAN directed:=true); + RETURNS SET OF (seq, path_seq, start_vid, end_vid, node, edge, cost, agg_cost) + OR EMPTY SET + +:Example: Three (source, target) vertex combinaitons: (from :math:`1` to :math:`2`), (form :math:`1` to :math:`17` -no route-), and (form :math:`2` to :math:`12`) on an **undirected** graph + + +.. literalinclude:: doc-pgr_dijkstra.queries + :start-after: -- q19 + :end-before: -- q20 + Parameters ------------------------------------------------------------------------------- .. pgr_dijkstra_parameters_start -============== ================== ======== ================================================= -Parameter Type Default Description -============== ================== ======== ================================================= -**edges_sql** ``TEXT`` Inner SQL query as described below. -**start_vid** ``BIGINT`` Identifier of the starting vertex of the path. -**start_vids** ``ARRAY[BIGINT]`` Array of identifiers of starting vertices. -**end_vid** ``BIGINT`` Identifier of the ending vertex of the path. -**end_vids** ``ARRAY[BIGINT]`` Array of identifiers of ending vertices. -**directed** ``BOOLEAN`` ``true`` - When ``true`` Graph is considered `Directed` - - When ``false`` the graph is considered as `Undirected`. -============== ================== ======== ================================================= +====================== ================== ======== ================================================= +Parameter Type Default Description +====================== ================== ======== ================================================= +**edges_sql** ``TEXT`` Inner SQL query as described below. +**start_vid** ``BIGINT`` Identifier of the starting vertex of the path. +**start_vids** ``ARRAY[BIGINT]`` Array of identifiers of starting vertices. +**end_vid** ``BIGINT`` Identifier of the ending vertex of the path. +**end_vids** ``ARRAY[BIGINT]`` Array of identifiers of ending vertices. +**combinations_sql** ``TEXT`` Inner SQL query producing pairs of starting and ending vertices as described below. +**directed** ``BOOLEAN`` ``true`` - When ``true`` Graph is considered `Directed` + - When ``false`` the graph is considered as `Undirected`. +====================== ================== ======== ================================================= .. pgr_dijkstra_parameters_end @@ -216,6 +243,12 @@ Inner query :start-after: basic_edges_sql_start :end-before: basic_edges_sql_end +.. rubric::combinations_sql + +.. include:: pgRouting-concepts.rst + :start-after: basic_combinations_sql_start + :end-before: basic_combinations_sql_end + Return Columns ------------------------------------------------------------------------------- diff --git a/doc/src/pgRouting-concepts.rst b/doc/src/pgRouting-concepts.rst index 5cbe84bf228..10a10477a21 100644 --- a/doc/src/pgRouting-concepts.rst +++ b/doc/src/pgRouting-concepts.rst @@ -143,6 +143,7 @@ Across this documentation, to indicate which overload we use the following terms * `One to Many`_ * `Many to One`_ * `Many to Many`_ +* `Combinations SQL`_ Depending on the overload are the parameters used, keeping consistency across all functions. @@ -179,6 +180,15 @@ When routing from: * From **many** starting vertices * to **many** ending vertices +Combinations SQL +............................................................................... + +When routing from: + +* From **many** different starting vertices +* to **many** different ending vertices +* Every tuple specifies a pair of a start vertex and an end vertex +* Users can define the combinations as desired. @@ -365,6 +375,25 @@ Where: .. points_sql_end +Description of the combinations_sql query for dijkstra like functions +............................................................................... + +.. basic_combinations_sql_start + +================= =================== ======== ================================================= +Column Type Default Description +================= =================== ======== ================================================= +**source** ``ANY-INTEGER`` Identifier of the first end point vertex of the edge. +**target** ``ANY-INTEGER`` Identifier of the second end point vertex of the edge. + +================= =================== ======== ================================================= + +Where: + +:ANY-INTEGER: SMALLINT, INTEGER, BIGINT + +.. basic_combinations_sql_end + .. _return_values: diff --git a/doc/src/pgRouting-introduction.rst b/doc/src/pgRouting-introduction.rst index b77f104ebee..4b6d41e782b 100644 --- a/doc/src/pgRouting-introduction.rst +++ b/doc/src/pgRouting-introduction.rst @@ -53,10 +53,12 @@ Cayetano Benavent, Gudesa Venkata Sai Akhil, Hang Wu, Maoguang Wang, Martha Vergara, +Mahmoud SAKR, Esteban Zimanyi Regina Obe, Rohith Reddy, Sourabh Garg, Virginia Vergara + And all the people that give us a little of their time making comments, finding issues, making pull requests etc. in any of our products: osm2pgrouting, pgRouting, pgRoutingLayer. @@ -87,6 +89,7 @@ Gerald Fenoy, Gudesa Venkata Sai Akhil, Hang Wu, Jay Mahadeokar, Jinfu Leng, Kai Behncke, Kishore Kumar, Ko Nagase, +Mahmoud SAKR, Esteban Zimanyi Manikata Kondeti, Mario Basa, Martin Wiesenhaan, Maxim Dubinin, Maoguang Wang, Mohamed Zia, Mukul Priya, Razequl Islam, Regina Obe, Rohith Reddy, diff --git a/doc/src/release_notes.rst b/doc/src/release_notes.rst index f0b59ead665..ee9bfa31770 100644 --- a/doc/src/release_notes.rst +++ b/doc/src/release_notes.rst @@ -53,7 +53,9 @@ To see the full list of changes check the list of `Git commits +#include "c_types/pgr_combination_t.h" + + +/*! @brief combinations_sql + +~~~~{.c} +SELECT source, target +FROM combinations_table; +~~~~ + + +@param[in] combinations_sql +@param[out] combinations +@param[out] combinations_edges +*/ +void pgr_get_combinations( + char *combinations_sql, + pgr_combination_t **combinations, + size_t *total_combinations); + +#endif // INCLUDE_C_COMMON_COMBINATIONS_INPUT_H_ diff --git a/include/c_types/pgr_combination_t.h b/include/c_types/pgr_combination_t.h new file mode 100644 index 00000000000..0bb4ce39576 --- /dev/null +++ b/include/c_types/pgr_combination_t.h @@ -0,0 +1,49 @@ +/*PGR-GNU***************************************************************** +File: pgr_combination_t.h + + +Generated with Template by: +Copyright (c) 2015 pgRouting developers +Mail: project@pgrouting.org + +Function's developer: +Copyright (c) 2020 Mahmoud SAKR and Esteban ZIMANYI +mail: m_attia_sakr@yahoo.com, estebanzimanyi@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*/ +/*! @file */ + +#ifndef INCLUDE_C_TYPES_PGR_COMBINATION_T_H_ +#define INCLUDE_C_TYPES_PGR_COMBINATION_T_H_ +#pragma once + +/* for int64_t */ +#ifdef __cplusplus +# include +#else +# include +#endif + +typedef struct { + int64_t source; + int64_t target; +} pgr_combination_t; + + +#endif // INCLUDE_C_TYPES_PGR_COMBINATION_T_H_ diff --git a/include/c_types/pgr_edge_t.h b/include/c_types/pgr_edge_t.h index 9acce633756..b8bebc83281 100644 --- a/include/c_types/pgr_edge_t.h +++ b/include/c_types/pgr_edge_t.h @@ -42,4 +42,4 @@ typedef struct { double reverse_cost; } pgr_edge_t; -#endif // INCLUDE_C_TYPES_PGR_EDGE_T_H_ +#endif // INCLUDE_C_TYPES_PGR_COMBINATION_T_H_ diff --git a/include/dijkstra/pgr_dijkstra.hpp b/include/dijkstra/pgr_dijkstra.hpp index 4343713cefb..eee32a6e0fb 100644 --- a/include/dijkstra/pgr_dijkstra.hpp +++ b/include/dijkstra/pgr_dijkstra.hpp @@ -6,6 +6,10 @@ Mail: project@pgrouting.org Copyright (c) 2015 Celia Virginia Vergara Castillo vicky_vergara@hotmail.com +Copyright (c) 2020 The combinations_sql signature is added by Mahmoud SAKR +and Esteban ZIMANYI +mail: m_attia_sakr@yahoo.com, estebanzimanyi@gmail.com + ------ This program is free software; you can redistribute it and/or modify @@ -30,6 +34,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. #include #include +#include "c_types/pgr_combination_t.h" #if BOOST_VERSION_OK #include @@ -299,6 +304,47 @@ class Pgr_dijkstra { return paths; } + // preparation for parallel arrays + std::deque dijkstra( + G &graph, + const std::vector< pgr_combination_t > &combinations, + bool only_cost, + size_t n_goals = std::numeric_limits::max()) { + // a call to 1 to many is faster for each of the sources + std::deque paths; + + // group targets per distinct source + std::map > vertex_map; + for (const pgr_combination_t &comb : combinations){ + std::map< int64_t , std::vector >::iterator it= vertex_map.find(comb.source); + if (it != vertex_map.end()) { + it->second.push_back(comb.target); + } else { + std::vector targets{comb.target}; + vertex_map[comb.source] = targets; + } + } + + for (const auto &start_ends : vertex_map) { + auto r_paths = dijkstra( + graph, + start_ends.first, start_ends.second, + only_cost, n_goals); + paths.insert(paths.begin(), r_paths.begin(), r_paths.end()); + } + vertex_map.clear(); + std::sort(paths.begin(), paths.end(), + [](const Path &e1, const Path &e2)->bool { + return e1.end_id() < e2.end_id(); + }); + std::stable_sort(paths.begin(), paths.end(), + [](const Path &e1, const Path &e2)->bool { + return e1.start_id() < e2.start_id(); + }); + + return paths; + } + //@} private: diff --git a/include/drivers/dijkstra/dijkstra_driver.h b/include/drivers/dijkstra/dijkstra_driver.h index b1ea059e0d5..1414b2542b0 100644 --- a/include/drivers/dijkstra/dijkstra_driver.h +++ b/include/drivers/dijkstra/dijkstra_driver.h @@ -10,6 +10,10 @@ Function's developer: Copyright (c) 2015 Celia Virginia Vergara Castillo Mail: vicky_vergara@hotmail.com +Copyright (c) 2020 The combinations_sql signature is added by Mahmoud SAKR +and Esteban ZIMANYI +mail: m_attia_sakr@yahoo.com, estebanzimanyi@gmail.com + ------ This program is free software; you can redistribute it and/or modify @@ -39,6 +43,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. #endif #include "c_types/pgr_edge_t.h" +#include "c_types/pgr_combination_t.h" #include "c_types/general_path_element_t.h" @@ -70,6 +75,26 @@ extern "C" { char** notice_msg, char** err_msg); + + // CREATE OR REPLACE FUNCTION pgr_dijkstra( + // sql text, + // combinations_sql text, + // directed boolean default true, + void do_pgr_combinations_dijkstra( + pgr_edge_t *data_edges, + size_t total_tuples, + pgr_combination_t *combinations, + size_t total_combinations, + bool directed, + bool only_cost, + bool normal, + + General_path_element_t **return_tuples, + size_t *return_count, + + char** log_msg, + char** notice_msg, + char** err_msg); #ifdef __cplusplus } #endif diff --git a/pgtap/dijkstra/dijkstra_empty_combinations_empty_result.test.sql b/pgtap/dijkstra/dijkstra_empty_combinations_empty_result.test.sql new file mode 100644 index 00000000000..1769c23ef5e --- /dev/null +++ b/pgtap/dijkstra/dijkstra_empty_combinations_empty_result.test.sql @@ -0,0 +1,26 @@ + +\i setup.sql + +SELECT plan(1); + +create or REPLACE FUNCTION foo() +RETURNS SETOF TEXT AS +$BODY$ +BEGIN + + RETURN query SELECT is_empty( + 'SELECT path_seq, start_vid, end_vid, node, edge, cost, agg_cost FROM pgr_dijkstra( + ''SELECT id, source, target, cost, reverse_cost FROM edge_table'', + ''SELECT * FROM combinations_table WHERE source=-1'' ) ' + ); + RETURN; +END +$BODY$ +language plpgsql; + +select * from foo(); + +-- Finish the tests and clean up. +SELECT * FROM finish(); +ROLLBACK; + diff --git a/pgtap/dijkstra/manyToMany_equiv_combinations.test.sql b/pgtap/dijkstra/manyToMany_equiv_combinations.test.sql new file mode 100644 index 00000000000..f9a9929c8a6 --- /dev/null +++ b/pgtap/dijkstra/manyToMany_equiv_combinations.test.sql @@ -0,0 +1,58 @@ + +\i setup.sql + +SELECT plan(1); + +UPDATE edge_table SET cost = cost + 0.001 * id * id, reverse_cost = reverse_cost + 0.001 * id * id; + +create or REPLACE FUNCTION foo(cant INTEGER default 18 ) +RETURNS SETOF TEXT AS +$BODY$ +DECLARE +sql_Combinations TEXT; +sql_Many TEXT; +BEGIN + + sql_Combinations := ''; + sql_Many := ''; + FOR i IN 1.. cant LOOP + IF (i > 1) THEN + sql_Many := sql_Many ||', '; + END IF; + sql_Many := sql_Many || i ; + END LOOP; + + FOR i IN 1.. cant LOOP + FOR j IN 1..cant LOOP + IF NOT (i = j) THEN + sql_Combinations := sql_Combinations || '(' || i || ',' || j || '),' ; + END IF; + END LOOP; + END LOOP; + sql_Combinations := trim(trailing ',' from sql_Combinations); + + sql_Many := + ' SELECT path_seq, start_vid, end_vid, node, edge, cost, agg_cost FROM pgr_dijkstra( + ''SELECT id, source, target, cost, reverse_cost FROM edge_table'', ' + || ' ARRAY[' || sql_Many ||'], ARRAY[' || sql_Many || + '] ) '; + + sql_Combinations := + ' SELECT path_seq, start_vid, end_vid, node, edge, cost, agg_cost FROM pgr_dijkstra( + ''SELECT id, source, target, cost, reverse_cost FROM edge_table'', + ''SELECT * FROM (VALUES' || sql_Combinations ||') AS combinations (source, target)'' ) '; + + RETURN query SELECT set_eq( sql_Many, sql_Combinations ); + RETURN; +END +$BODY$ +language plpgsql; + + +select * from foo(); + + +-- Finish the tests and clean up. +SELECT * FROM finish(); +ROLLBACK; + diff --git a/sql/dijkstra/_dijkstra.sql b/sql/dijkstra/_dijkstra.sql index 01bbc27be54..7de0b047c41 100644 --- a/sql/dijkstra/_dijkstra.sql +++ b/sql/dijkstra/_dijkstra.sql @@ -6,6 +6,10 @@ Mail: project@pgrouting.org Copyright (c) 2015 Celia Virginia Vergara Castillo mail: vicky_vergara@hotmail.com +Copyright (c) 2020 The combinations_sql signature is added by Mahmoud SAKR +and Esteban ZIMANYI +mail: m_attia_sakr@yahoo.com, estebanzimanyi@gmail.com + ------ This program is free software; you can redistribute it and/or modify @@ -51,7 +55,30 @@ RETURNS SETOF RECORD AS 'MODULE_PATHNAME' LANGUAGE C VOLATILE STRICT; + +CREATE OR REPLACE FUNCTION _pgr_dijkstra( + edges_sql TEXT, + combinations_sql TEXT, + directed BOOLEAN DEFAULT true, + only_cost BOOLEAN DEFAULT false, + normal BOOLEAN DEFAULT true, + + OUT seq INTEGER, + OUT path_seq INTEGER, + OUT start_vid BIGINT, + OUT end_vid BIGINT, + OUT node BIGINT, + OUT edge BIGINT, + OUT cost FLOAT, + OUT agg_cost FLOAT) +RETURNS SETOF RECORD AS +'MODULE_PATHNAME' +LANGUAGE C VOLATILE STRICT; + -- COMMENTS COMMENT ON FUNCTION _pgr_dijkstra(TEXT, ANYARRAY, ANYARRAY, BOOLEAN, BOOLEAN, BOOLEAN, BIGINT) IS 'pgRouting internal function'; + +COMMENT ON FUNCTION _pgr_dijkstra(TEXT, TEXT, BOOLEAN, BOOLEAN, BOOLEAN) +IS 'pgRouting internal function'; diff --git a/sql/dijkstra/dijkstra.sql b/sql/dijkstra/dijkstra.sql index c15eeb6c551..e6918a4f81a 100644 --- a/sql/dijkstra/dijkstra.sql +++ b/sql/dijkstra/dijkstra.sql @@ -6,6 +6,10 @@ Mail: project@pgrouting.org Copyright (c) 2015 Celia Virginia Vergara Castillo mail: vicky_vergara@hotmail.com +Copyright (c) 2020 The combinations_sql signature is added by Mahmoud SAKR +and Esteban ZIMANYI +mail: m_attia_sakr@yahoo.com, estebanzimanyi@gmail.com + ------ This program is free software; you can redistribute it and/or modify @@ -51,7 +55,6 @@ LANGUAGE sql VOLATILE STRICT COST 100 ROWS 1000; - -- ONE to MANY CREATE OR REPLACE FUNCTION pgr_dijkstra( TEXT, -- edges_sql (required) @@ -76,7 +79,6 @@ LANGUAGE sql VOLATILE STRICT COST 100 ROWS 1000; - -- MANY to ONE CREATE OR REPLACE FUNCTION pgr_dijkstra( TEXT, -- edges_sql (required) @@ -101,7 +103,6 @@ LANGUAGE sql VOLATILE STRICT COST 100 ROWS 1000; - -- MANY to MANY CREATE OR REPLACE FUNCTION pgr_dijkstra( TEXT, -- edges_sql (required) @@ -127,6 +128,31 @@ LANGUAGE sql VOLATILE STRICT COST 100 ROWS 1000; +-- Combinations SQL signature +CREATE OR REPLACE FUNCTION pgr_dijkstra( + TEXT, -- edges_sql (required) + TEXT, -- combinations_sql (required) + + directed BOOLEAN DEFAULT true, + + OUT seq INTEGER, + OUT path_seq INTEGER, + OUT start_vid BIGINT, + OUT end_vid BIGINT, + OUT node BIGINT, + OUT edge BIGINT, + OUT cost FLOAT, + OUT agg_cost FLOAT) +RETURNS SETOF RECORD AS +$BODY$ + SELECT a.seq, a.path_seq, a.start_vid, a.end_vid, a.node, a.edge, a.cost, a.agg_cost + FROM _pgr_dijkstra(_pgr_get_statement($1), _pgr_get_statement($2), $3, false, true) AS a; +$BODY$ +LANGUAGE sql VOLATILE STRICT +COST 100 +ROWS 1000; + + -- COMMENTS COMMENT ON FUNCTION pgr_dijkstra(TEXT, BIGINT, BIGINT, BOOLEAN) @@ -176,3 +202,14 @@ IS 'pgr_dijkstra(Many to Many) - Documentation: - ${PGROUTING_DOC_LINK}/pgr_dijkstra.html '; + +COMMENT ON FUNCTION pgr_dijkstra(TEXT, TEXT, BOOLEAN) +IS 'pgr_dijkstra(One to One) +- Parameters: + - Edges SQL with columns: id, source, target, cost [,reverse_cost] + - Combinations SQL with columns: source, target +- Optional Parameters + - directed := true +- Documentation: + - ${PGROUTING_DOC_LINK}/pgr_dijkstra.html +'; diff --git a/sql/sigs/pgrouting--3.1.0.sig b/sql/sigs/pgrouting--3.1.0.sig index 8022f36a1bc..48df5a42eea 100644 --- a/sql/sigs/pgrouting--3.1.0.sig +++ b/sql/sigs/pgrouting--3.1.0.sig @@ -93,6 +93,8 @@ _pgr_dijkstra(text,anyarray,anyarray,boolean,boolean,boolean,bigint) pgr_dijkstra(text,anyarray,bigint,boolean) pgr_dijkstra(text,bigint,anyarray,boolean) pgr_dijkstra(text,bigint,bigint,boolean) +pgr_dijkstra(text,text,boolean) +_pgr_dijkstra(text,text,boolean,boolean,boolean) _pgr_dijkstravia(text,anyarray,boolean,boolean,boolean) pgr_dijkstravia(text,anyarray,boolean,boolean,boolean) _pgr_drivingdistance(text,anyarray,double precision,boolean,boolean) diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index be65f75dea5..9b2a073b29e 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -8,6 +8,7 @@ ADD_LIBRARY(common OBJECT matrixRows_input.c get_check_data.c edges_input.c + combinations_input.c orders_input.c orders_input.c vehicles_input.c diff --git a/src/common/combinations_input.c b/src/common/combinations_input.c new file mode 100644 index 00000000000..9fc1f26215c --- /dev/null +++ b/src/common/combinations_input.c @@ -0,0 +1,152 @@ +/*PGR-GNU***************************************************************** +File: combinations_input.c + +Generated with Template by: +Copyright (c) 2015 pgRouting developers +Mail: project@pgrouting.org + +Function's developer: +Copyright (c) 2020 Mahmoud SAKR and Esteban ZIMANYI +mail: m_attia_sakr@yahoo.com, estebanzimanyi@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 "c_common/combinations_input.h" + +#include +#include +#include +/* for size-t */ +#ifdef __cplusplus +# include +#else +# include +#endif + +#include "c_types/column_info_t.h" +#include "c_types/pgr_combination_t.h" +#include "c_common/debug_macro.h" +#include "c_common/get_check_data.h" +#include "c_common/time_msg.h" + + +static +void fetch_combination( + HeapTuple *tuple, + TupleDesc *tupdesc, + Column_info_t info[2], + pgr_combination_t *combination, + size_t *valid_combinations) { + combination->source = pgr_SPI_getBigInt(tuple, tupdesc, info[0]); + combination->target = pgr_SPI_getBigInt(tuple, tupdesc, info[1]); + + *valid_combinations = *valid_combinations + 1; +} + + + +static +void +get_combinations_2_columns( + char *sql, + pgr_combination_t **combinations, + size_t *totalTuples) { + clock_t start_t = clock(); + + const int tuple_limit = 1000000; + + size_t total_tuples; + size_t valid_combinations; + + Column_info_t info[2]; + + int i; + for (i = 0; i < 2; ++i) { + info[i].colNumber = -1; + info[i].type = 0; + info[i].strict = true; + info[i].eType = ANY_INTEGER; + } + info[0].name = "source"; + info[1].name = "target"; + + void *SPIplan; + SPIplan = pgr_SPI_prepare(sql); + + Portal SPIportal; + SPIportal = pgr_SPI_cursor_open(SPIplan); + + + bool moredata = true; + (*totalTuples) = total_tuples = valid_combinations = 0; + + while (moredata == true) { + SPI_cursor_fetch(SPIportal, true, tuple_limit); + if (total_tuples == 0) + pgr_fetch_column_info(info, 2); + + size_t ntuples = SPI_processed; + total_tuples += ntuples; + + if (ntuples > 0) { + if ((*combinations) == NULL) + (*combinations) = (pgr_combination_t *) + palloc0(total_tuples * sizeof(pgr_combination_t)); + else + (*combinations) = (pgr_combination_t *) + repalloc((*combinations), total_tuples * sizeof(pgr_combination_t)); + + if ((*combinations) == NULL) { + elog(ERROR, "Out of memory"); + } + + size_t t; + SPITupleTable *tuptable = SPI_tuptable; + TupleDesc tupdesc = SPI_tuptable->tupdesc; + for (t = 0; t < ntuples; t++) { + HeapTuple tuple = tuptable->vals[t]; + fetch_combination(&tuple, &tupdesc, info, + &(*combinations)[total_tuples - ntuples + t], + &valid_combinations); + } + SPI_freetuptable(tuptable); + } else { + moredata = false; + } + } + + SPI_cursor_close(SPIportal); + + if (total_tuples == 0 || valid_combinations == 0) { + PGR_DBG("No combinations found"); + } + + (*totalTuples) = total_tuples; + PGR_DBG("Reading %ld combinations", total_tuples); + time_msg("reading combinations", start_t, clock()); +} + +/* select source, target */ +void +pgr_get_combinations( + char *combinations_sql, + pgr_combination_t **combinations, + size_t *total_combinations) { + get_combinations_2_columns(combinations_sql, combinations, total_combinations); +} diff --git a/src/dijkstra/dijkstra.c b/src/dijkstra/dijkstra.c index a18bc515803..59874f94e89 100644 --- a/src/dijkstra/dijkstra.c +++ b/src/dijkstra/dijkstra.c @@ -10,6 +10,10 @@ Function's developer: Copyright (c) 2015 Celia Virginia Vergara Castillo Mail: vicky_vergara@hotmail.com +Copyright (c) 2020 The combinations_sql signature is added by Mahmoud SAKR +and Esteban ZIMANYI +mail: m_attia_sakr@yahoo.com, estebanzimanyi@gmail.com + ------ This program is free software; you can redistribute it and/or modify @@ -39,6 +43,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. #include "c_common/time_msg.h" #include "c_common/edges_input.h" #include "c_common/arrays_input.h" +#include "c_common/combinations_input.h" #include "drivers/dijkstra/dijkstra_driver.h" PG_MODULE_MAGIC; @@ -135,6 +140,89 @@ process( pgr_SPI_finish(); } + + +static +void +process_combinations( + char* edges_sql, + char* combinations_sql, + bool directed, + bool only_cost, + bool normal, + General_path_element_t **result_tuples, + size_t *result_count) { + pgr_SPI_connect(); + + pgr_edge_t *edges = NULL; + size_t total_edges = 0; + + pgr_combination_t *combinations = NULL; + size_t total_combinations = 0; + + if (normal) { + pgr_get_edges(edges_sql, &edges, &total_edges); + } else { + pgr_get_edges_reversed(edges_sql, &edges, &total_edges); + } + + if (total_edges == 0) { + pgr_SPI_finish(); + return; + } else { + pgr_get_combinations(combinations_sql, &combinations, &total_combinations); + if (total_combinations == 0) { + if (edges) pfree(edges); + pgr_SPI_finish(); + return; + } + } + + PGR_DBG("Starting timer"); + clock_t start_t = clock(); + char* log_msg = NULL; + char* notice_msg = NULL; + char* err_msg = NULL; + do_pgr_combinations_dijkstra( + edges, total_edges, + combinations, total_combinations, + directed, + only_cost, + normal, + + result_tuples, + result_count, + + &log_msg, + ¬ice_msg, + &err_msg); + + if (only_cost) { + time_msg("processing pgr_dijkstraCost", start_t, clock()); + } else { + time_msg("processing pgr_dijkstra", start_t, clock()); + } + + + if (err_msg && (*result_tuples)) { + pfree(*result_tuples); + (*result_tuples) = NULL; + (*result_count) = 0; + } + + pgr_global_report(log_msg, notice_msg, err_msg); + + if (log_msg) pfree(log_msg); + if (notice_msg) pfree(notice_msg); + if (err_msg) pfree(err_msg); + if (edges) pfree(edges); + if (combinations) pfree(combinations); + pgr_SPI_finish(); +} + + + + PGDLLEXPORT Datum _pgr_dijkstra(PG_FUNCTION_ARGS) { FuncCallContext *funcctx; @@ -150,29 +238,47 @@ _pgr_dijkstra(PG_FUNCTION_ARGS) { funcctx = SRF_FIRSTCALL_INIT(); oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); - - /**********************************************************************/ - // pgr_dijkstra( - // sql TEXT, - // start_vids ANYARRAY, - // end_vids ANYARRAY, - // directed BOOLEAN default true, - // only_cost BOOLEAN default false - // normal BOOLEAN default true - - process( - text_to_cstring(PG_GETARG_TEXT_P(0)), - PG_GETARG_ARRAYTYPE_P(1), - PG_GETARG_ARRAYTYPE_P(2), - PG_GETARG_BOOL(3), - PG_GETARG_BOOL(4), - PG_GETARG_BOOL(5), - PG_GETARG_INT64(6), - &result_tuples, - &result_count); - - /**********************************************************************/ - + if (PG_NARGS() == 7) { + /**********************************************************************/ + // pgr_dijkstra( + // sql TEXT, + // start_vids ANYARRAY, + // end_vids ANYARRAY, + // directed BOOLEAN default true, + // only_cost BOOLEAN default false + // normal BOOLEAN default true + + process( + text_to_cstring(PG_GETARG_TEXT_P(0)), + PG_GETARG_ARRAYTYPE_P(1), + PG_GETARG_ARRAYTYPE_P(2), + PG_GETARG_BOOL(3), + PG_GETARG_BOOL(4), + PG_GETARG_BOOL(5), + PG_GETARG_INT64(6), + &result_tuples, + &result_count); + + /**********************************************************************/ + } else if (PG_NARGS() == 5) { + /**********************************************************************/ + // pgr_dijkstra( + // edge_sql TEXT, + // combinations_sql TEXT, + // directed BOOLEAN default true, + // only_cost BOOLEAN default false + + process_combinations( + text_to_cstring(PG_GETARG_TEXT_P(0)), + text_to_cstring(PG_GETARG_TEXT_P(1)), + PG_GETARG_BOOL(2), + PG_GETARG_BOOL(3), + PG_GETARG_BOOL(4), + &result_tuples, + &result_count); + + /**********************************************************************/ + } #if PGSQL_VERSION > 95 funcctx->max_calls = result_count; #else diff --git a/src/dijkstra/dijkstra_driver.cpp b/src/dijkstra/dijkstra_driver.cpp index c71cf4d994a..d3a4b6bf09a 100644 --- a/src/dijkstra/dijkstra_driver.cpp +++ b/src/dijkstra/dijkstra_driver.cpp @@ -9,6 +9,10 @@ Function's developer: Copyright (c) 2015 Celia Virginia Vergara Castillo Mail: vicky_vergara@hotmail.com +Copyright (c) 2020 The combinations_sql signature is added by Mahmoud SAKR +and Esteban ZIMANYI +mail: m_attia_sakr@yahoo.com, estebanzimanyi@gmail.com + ------ This program is free software; you can redistribute it and/or modify @@ -28,6 +32,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ********************************************************************PGR-GNU*/ #include "drivers/dijkstra/dijkstra_driver.h" +#include #include #include @@ -74,6 +79,28 @@ pgr_dijkstra( } +template < class G > +std::deque< Path > +pgr_dijkstra( + G &graph, + std::vector < pgr_combination_t > &combinations, + bool only_cost, + bool normal) { + pgrouting::Pgr_dijkstra< G > fn_dijkstra; + auto paths = fn_dijkstra.dijkstra( + graph, + combinations, + only_cost); + + if (!normal) { + for (auto &path : paths) { + path.reverse(); + } + } + return paths; +} + + // CREATE OR REPLACE FUNCTION pgr_dijkstra( // sql text, @@ -181,3 +208,107 @@ do_pgr_many_to_many_dijkstra( *log_msg = pgr_msg(log.str().c_str()); } } + + +// CREATE OR REPLACE FUNCTION pgr_dijkstra( +// sql text, +// combinations sql text, +// directed boolean default true, +void +do_pgr_combinations_dijkstra( + pgr_edge_t *data_edges, + size_t total_edges, + pgr_combination_t *combinations, + size_t total_combinations, + bool directed, + bool only_cost, + bool normal, + + General_path_element_t **return_tuples, + size_t *return_count, + char ** log_msg, + char ** notice_msg, + char ** err_msg) { + std::ostringstream log; + std::ostringstream err; + std::ostringstream notice; + + try { + pgassert(total_edges != 0); + pgassert(total_combinations != 0); + pgassert(!(*log_msg)); + pgassert(!(*notice_msg)); + pgassert(!(*err_msg)); + pgassert(!(*return_tuples)); + pgassert(*return_count == 0); + + graphType gType = directed? DIRECTED: UNDIRECTED; + + + log << "Inserting combinations into a c++ vector structure"; + std::vector + combinations_vector(combinations, combinations + total_combinations); + + std::deque< Path >paths; + if (directed) { + log << "\nWorking with directed Graph"; + pgrouting::DirectedGraph digraph(gType); + digraph.insert_edges(data_edges, total_edges); + paths = pgr_dijkstra( + digraph, + combinations_vector, + only_cost, normal); + } else { + log << "\nWorking with Undirected Graph"; + pgrouting::UndirectedGraph undigraph(gType); + undigraph.insert_edges(data_edges, total_edges); + paths = pgr_dijkstra( + undigraph, + combinations_vector, + only_cost, normal); + } + combinations_vector.clear(); + size_t count(0); + count = count_tuples(paths); + + if (count == 0) { + (*return_tuples) = NULL; + (*return_count) = 0; + notice << + "No paths found"; + *log_msg = pgr_msg(notice.str().c_str()); + return; + } + + (*return_tuples) = pgr_alloc(count, (*return_tuples)); + log << "\nConverting a set of paths into the tuples"; + (*return_count) = (collapse_paths(return_tuples, paths)); + + *log_msg = log.str().empty()? + *log_msg : + pgr_msg(log.str().c_str()); + *notice_msg = notice.str().empty()? + *notice_msg : + pgr_msg(notice.str().c_str()); + } catch (AssertFailedException &except) { + (*return_tuples) = pgr_free(*return_tuples); + (*return_count) = 0; + err << except.what(); + *err_msg = pgr_msg(err.str().c_str()); + *log_msg = pgr_msg(log.str().c_str()); + } catch (std::exception &except) { + (*return_tuples) = pgr_free(*return_tuples); + (*return_count) = 0; + err << except.what(); + *err_msg = pgr_msg(err.str().c_str()); + *log_msg = pgr_msg(log.str().c_str()); + } catch(...) { + (*return_tuples) = pgr_free(*return_tuples); + (*return_count) = 0; + err << "Caught unknown exception!"; + *err_msg = pgr_msg(err.str().c_str()); + *log_msg = pgr_msg(log.str().c_str()); + } +} + + diff --git a/tools/testers/sampledata.sql b/tools/testers/sampledata.sql index ea2d15df908..2eeb83e8686 100644 --- a/tools/testers/sampledata.sql +++ b/tools/testers/sampledata.sql @@ -197,3 +197,19 @@ INSERT INTO orders --ORDERS TABLE END + +--COMBINATIONS CREATE start +CREATE TABLE combinations_table ( + source BIGINT, + target BIGINT +); + +INSERT INTO combinations_table ( + source, target) VALUES +(1, 2), +(1, 4), +(2, 1), +(2, 4), +(2, 17); + +--COMBINATIONS CREATE end