Skip to content

Commit 4b827a9

Browse files
committed
Fix pgRouting#2706: pgr_betweennessCentrality
1 parent e4cc807 commit 4b827a9

File tree

7 files changed

+139
-114
lines changed

7 files changed

+139
-114
lines changed

NEWS.md

+4-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,10 @@
1010

1111
### pgRouting 3.7.2 Release Notes
1212

13-
No Changes Yet
13+
**Bug fixes**
14+
15+
* [#2706](https://github.com/pgRouting/pgrouting/pull/2706) winnie crashing
16+
on pgr_betweennessCentrality
1417

1518
### pgRouting 3.7.1 Release Notes
1619

doc/src/release_notes.rst

+4-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,10 @@ pgRouting 3.7
4141
pgRouting 3.7.2 Release Notes
4242
-------------------------------------------------------------------------------
4343

44-
No Changes Yet
44+
.. rubric:: Bug fixes
45+
46+
* `#2706 <https://github.com/pgRouting/pgrouting/pull/2706>`__ winnie crashing
47+
on pgr_betweennessCentrality
4548

4649
pgRouting 3.7.1 Release Notes
4750
-------------------------------------------------------------------------------

include/cpp_common/to_postgres.hpp

+75
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
/*PGR-GNU*****************************************************************
2+
File: to_postgres.hpp
3+
4+
Copyright (c) 2015 pgRouting developers
5+
6+
7+
------
8+
9+
This program is free software; you can redistribute it and/or modify
10+
it under the terms of the GNU General Public License as published by
11+
the Free Software Foundation; either version 2 of the License, or
12+
(at your option) any later version.
13+
14+
This program is distributed in the hope that it will be useful,
15+
but WITHOUT ANY WARRANTY; without even the implied warranty of
16+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17+
GNU General Public License for more details.
18+
19+
You should have received a copy of the GNU General Public License
20+
along with this program; if not, write to the Free Software
21+
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22+
23+
********************************************************************PGR-GNU*/
24+
25+
#ifndef INCLUDE_CPP_COMMON_TO_POSTGRES_HPP_
26+
#define INCLUDE_CPP_COMMON_TO_POSTGRES_HPP_
27+
#pragma once
28+
29+
#include <vector>
30+
#include <cstddef>
31+
32+
#include "c_types/iid_t_rt.h"
33+
34+
#include "cpp_common/base_graph.hpp"
35+
#include "cpp_common/alloc.hpp"
36+
37+
namespace pgrouting {
38+
namespace to_postgres {
39+
40+
/** @brief Stored results on a vector are saved on a C array
41+
*
42+
* @param[in] graph Created graph with the base Graph
43+
* @param[in] results results[i] -> the ith element of the vector contains the results
44+
* @param[out] result_count The size of the vector
45+
* @param[out] result_tuples The C array of <bigint, bigint, float>
46+
*
47+
* <bigint, bigint, float> = < i , 0, results[i] >
48+
*
49+
* Currently works for pgr_betweennessCentrality
50+
*/
51+
template <class G>
52+
void vector_to_tuple(
53+
const G &graph,
54+
const std::vector<double> results,
55+
size_t &result_count,
56+
IID_t_rt **result_tuples) {
57+
result_count = results.size();
58+
*result_tuples = pgrouting::pgr_alloc(result_count, (*result_tuples));
59+
60+
size_t seq = 0;
61+
for (typename G::V v_i = 0; v_i < graph.num_vertices(); ++v_i) {
62+
(*result_tuples)[seq].from_vid = graph[v_i].id;
63+
/*
64+
* These 2 lines are specifically for pgr_betweennessCentrality
65+
*/
66+
(*result_tuples)[seq].to_vid = 0;
67+
(*result_tuples)[seq].cost = graph.is_directed()? results[v_i] / 2.0 : results[v_i];
68+
seq++;
69+
}
70+
}
71+
72+
} // namespace to_postgres
73+
} // namespace pgrouting
74+
75+
#endif // INCLUDE_CPP_COMMON_TO_POSTGRES_HPP_

include/metrics/betweennessCentrality.hpp

+30-92
Original file line numberDiff line numberDiff line change
@@ -30,115 +30,53 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
3030
#pragma once
3131

3232
#include <vector>
33-
#include <map>
34-
#include <type_traits>
3533

3634
#include <boost/config.hpp>
3735
#include <boost/graph/adjacency_list.hpp>
38-
#include <boost/property_map/property_map.hpp>
3936
#include <boost/graph/betweenness_centrality.hpp>
40-
#include <boost/graph/graph_traits.hpp>
4137

4238
#include "c_types/iid_t_rt.h"
43-
#include "cpp_common/basePath_SSEC.hpp"
4439
#include "cpp_common/base_graph.hpp"
4540
#include "cpp_common/interruption.hpp"
46-
#include "cpp_common/alloc.hpp"
4741

4842
namespace pgrouting {
49-
template <class G> class Pgr_metrics;
43+
namespace metrics {
5044

5145
template <class G>
52-
void
53-
pgr_betweennesscentrality(
54-
G &graph,
55-
size_t &result_tuple_count,
56-
IID_t_rt **postgres_rows) {
57-
Pgr_metrics<G> fn_centrality;
58-
fn_centrality.betweennessCentrality(graph, result_tuple_count, postgres_rows);
59-
}
60-
61-
template <class G>
62-
class Pgr_metrics {
63-
public:
64-
using Graph = typename G::B_G;
65-
using V = typename G::V;
66-
using E = typename G::E;
67-
typedef typename boost::graph_traits<Graph>::directed_category directed_category;
68-
69-
void betweennessCentrality(
70-
const G &graph,
71-
size_t &result_tuple_count,
72-
IID_t_rt **postgres_rows) {
73-
// required parameters
74-
std::vector<double> centrality(boost::num_vertices(graph.graph), 0.0);
75-
auto centrality_map = boost::make_iterator_property_map(centrality.begin(),
76-
boost::get(boost::vertex_index, graph.graph));
77-
std::vector<double> distance(boost::num_vertices(graph.graph), 0.0);
78-
auto distance_map = boost::make_iterator_property_map(distance.begin(),
79-
boost::get(boost::vertex_index, graph.graph));
80-
// dummy parameters
81-
std::vector<double> edge_centrality(boost::num_edges(graph.graph), 0.0);
82-
auto edge_centrality_map = boost::make_iterator_property_map(edge_centrality.begin(),
83-
boost::get(&pgrouting::Basic_edge::cost,
84-
graph.graph));
85-
std::vector<std::vector<E>> incoming(boost::num_vertices(graph.graph));
86-
auto incoming_map = boost::make_iterator_property_map(incoming.begin(),
87-
boost::get(boost::vertex_index, graph.graph),
88-
std::vector<E>());
89-
std::vector<double> dependency(boost::num_vertices(graph.graph), 0.0);
90-
auto dependency_map = boost::make_iterator_property_map(dependency.begin(),
91-
boost::get(boost::vertex_index, graph.graph));
92-
std::vector<std::size_t> path_count(boost::num_vertices(graph.graph), 0);
93-
auto path_count_map = boost::make_iterator_property_map(path_count.begin(),
94-
boost::get(boost::vertex_index, graph.graph));
95-
auto vertex_index = boost::get(boost::vertex_index, graph.graph);
96-
97-
/* abort in case of an interruption occurs (e.g. the query is being cancelled) */
98-
CHECK_FOR_INTERRUPTS();
99-
100-
boost::brandes_betweenness_centrality(
46+
std::vector<double> betweennessCentrality(
47+
const G &graph
48+
) {
49+
std::vector<double> centrality(boost::num_vertices(graph.graph), 0.0);
50+
auto centrality_map = boost::make_iterator_property_map(centrality.begin(),
51+
boost::get(boost::vertex_index, graph.graph));
52+
53+
CHECK_FOR_INTERRUPTS();
54+
55+
try {
56+
boost::brandes_betweenness_centrality(
57+
graph.graph,
58+
centrality_map);
59+
60+
if (boost::num_vertices(graph.graph) > 2) {
61+
boost::relative_betweenness_centrality(
10162
graph.graph,
102-
centrality_map,
103-
edge_centrality_map,
104-
incoming_map,
105-
distance_map,
106-
dependency_map,
107-
path_count_map,
108-
vertex_index,
109-
get(&pgrouting::Basic_edge::cost, graph.graph));
110-
111-
if (boost::num_vertices(graph.graph) > 2) {
112-
boost::relative_betweenness_centrality(
113-
graph.graph,
114-
centrality_map);
63+
centrality_map);
64+
}
65+
} catch (boost::exception const& ex) {
66+
(void)ex;
67+
throw;
68+
} catch (std::exception &e) {
69+
(void)e;
70+
throw;
71+
} catch (...) {
72+
throw;
11573
}
11674

117-
generate_results(graph, centrality, result_tuple_count, postgres_rows);
118-
}
75+
return centrality;
76+
}
11977

120-
private:
121-
void generate_results(
122-
const G &graph,
123-
const std::vector<double> centrality_results,
124-
size_t &result_tuple_count,
125-
IID_t_rt **postgres_rows) const {
126-
result_tuple_count = centrality_results.size();
127-
*postgres_rows = pgr_alloc(result_tuple_count, (*postgres_rows));
128-
129-
size_t seq = 0;
130-
for (typename G::V v_i = 0; v_i < graph.num_vertices(); ++v_i) {
131-
(*postgres_rows)[seq].from_vid = graph[v_i].id;
132-
(*postgres_rows)[seq].to_vid = 0;
133-
(*postgres_rows)[seq].cost = centrality_results[v_i];
134-
if (std::is_same<directed_category, boost::bidirectional_tag>::value) {
135-
(*postgres_rows)[seq].cost = centrality_results[v_i]/2.0;
136-
}
137-
seq++;
138-
}
139-
}
140-
};
14178

79+
} // namespace metrics
14280
} // namespace pgrouting
14381

14482
#endif // INCLUDE_METRICS_BETWEENNESSCENTRALITY_HPP_

pgtap/metrics/betweennessCentrality/edge_cases.pg

+19-16
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ RETURN QUERY
7575
SELECT lives_ok('idless4_q');
7676

7777
RETURN QUERY
78-
SELECT results_eq('idless4_q', 'idless4_r');
78+
SELECT results_eq('idless4_q', 'idless4_r', 'test 4');
7979

8080

8181
PREPARE idless3_q AS
@@ -95,7 +95,7 @@ RETURN QUERY
9595
SELECT lives_ok('idless3_q');
9696

9797
RETURN QUERY
98-
SELECT results_eq('idless3_q', 'idless3_r');
98+
SELECT results_eq('idless3_q', 'idless3_r', 'test 6');
9999

100100
PREPARE idless2_q AS
101101
SELECT * FROM pgr_betweennessCentrality(
@@ -120,7 +120,7 @@ SELECT results_eq('idless2_q', 'idless2_r');
120120
PREPARE idless5ud_q AS
121121
SELECT * FROM pgr_betweennessCentrality(
122122
'SELECT id, source, target, cost, reverse_cost
123-
FROM edges WHERE id < 5', directed => false ) ORDER BY vid;
123+
FROM edges WHERE id < 5', directed => false ) ORDER BY vid;
124124

125125
PREPARE idless5ud_r AS
126126
SELECT * FROM (VALUES
@@ -135,18 +135,20 @@ RETURN QUERY
135135
SELECT lives_ok('idless5ud_q');
136136

137137
RETURN QUERY
138-
SELECT results_eq('idless5ud_q', 'idless5ud_r');
138+
SELECT results_eq('idless5ud_q', 'idless5ud_r', 'test 10');
139+
139140

140141
PREPARE idless4ud_q AS
141142
SELECT * FROM pgr_betweennessCentrality(
142143
'SELECT id, source, target, cost, reverse_cost
143-
FROM edges WHERE id < 4', directed => false ) ORDER BY vid;
144+
FROM edges WHERE id < 4', directed => false) ORDER BY vid;
144145

145146
PREPARE idless4ud_r AS
146147
SELECT * FROM (VALUES
147148
(5::BIGINT , 0::FLOAT),
148149
(6 , 0.6666666666666666),
149-
(10 , 0.6666666666666666), (15 , 0))
150+
(10 , 0.6666666666666666),
151+
(15 , 0))
150152
AS t(vid, centrality);
151153

152154
RETURN QUERY
@@ -159,7 +161,7 @@ SELECT results_eq('idless4ud_q', 'idless4ud_r');
159161
PREPARE idless3ud_q AS
160162
SELECT * FROM pgr_betweennessCentrality(
161163
'SELECT id, source, target, cost, reverse_cost
162-
FROM edges WHERE id < 3', directed => false ) ORDER BY vid;
164+
FROM edges WHERE id < 3', directed => false) ORDER BY vid;
163165

164166
PREPARE idless3ud_r AS
165167
SELECT * FROM (VALUES
@@ -172,7 +174,7 @@ RETURN QUERY
172174
SELECT lives_ok('idless3ud_q');
173175

174176
RETURN QUERY
175-
SELECT results_eq('idless3ud_q', 'idless3ud_r');
177+
SELECT results_eq('idless3ud_q', 'idless3ud_r', 'test 14');
176178

177179
PREPARE idless2ud_q AS
178180
SELECT * FROM pgr_betweennessCentrality(
@@ -190,15 +192,15 @@ RETURN QUERY
190192
SELECT lives_ok('idless2ud_q');
191193

192194
RETURN QUERY
193-
SELECT results_eq('idless2ud_q', 'idless2ud_r');
195+
SELECT results_eq('idless2ud_q', 'idless2ud_r', 'test 16');
194196

195197
/* Explicit Directed Cases */
196198

197199

198200
PREPARE idless5d_q AS
199201
SELECT * FROM pgr_betweennessCentrality(
200202
'SELECT id, source, target, cost, reverse_cost
201-
FROM edges WHERE id < 5', directed => true ) ORDER BY vid;
203+
FROM edges WHERE id < 5', directed => true ) ORDER BY vid;
202204

203205
PREPARE idless5d_r AS
204206
SELECT * FROM (VALUES
@@ -213,13 +215,13 @@ RETURN QUERY
213215
SELECT lives_ok('idless5d_q');
214216

215217
RETURN QUERY
216-
SELECT results_eq('idless5d_q', 'idless5d_r');
218+
SELECT results_eq('idless5d_q', 'idless5d_r', 'test 18');
217219

218220

219221
PREPARE idless4d_q AS
220222
SELECT * FROM pgr_betweennessCentrality(
221223
'SELECT id, source, target, cost, reverse_cost
222-
FROM edges WHERE id < 4', directed => true ) ORDER BY vid;
224+
FROM edges WHERE id < 4', directed => true) ORDER BY vid;
223225

224226
PREPARE idless4d_r AS
225227
SELECT * FROM (VALUES
@@ -233,13 +235,13 @@ RETURN QUERY
233235
SELECT lives_ok('idless4d_q');
234236

235237
RETURN QUERY
236-
SELECT results_eq('idless4d_q', 'idless4d_r');
238+
SELECT results_eq('idless4d_q', 'idless4d_r', 'test 20');
237239

238240

239241
PREPARE idless3d_q AS
240242
SELECT * FROM pgr_betweennessCentrality(
241243
'SELECT id, source, target, cost, reverse_cost
242-
FROM edges WHERE id < 3', directed => true ) ORDER BY vid;
244+
FROM edges WHERE id < 3', directed => true) ORDER BY vid;
243245

244246
PREPARE idless3d_r AS
245247
SELECT * FROM (VALUES
@@ -252,7 +254,8 @@ RETURN QUERY
252254
SELECT lives_ok('idless3d_q');
253255

254256
RETURN QUERY
255-
SELECT results_eq('idless3d_q', 'idless3d_r');
257+
SELECT results_eq('idless3d_q', 'idless3d_r', 'test 22');
258+
256259

257260
PREPARE idless2d_q AS
258261
SELECT * FROM pgr_betweennessCentrality(
@@ -270,7 +273,7 @@ RETURN QUERY
270273
SELECT lives_ok('idless2d_q');
271274

272275
RETURN QUERY
273-
SELECT results_eq('idless2d_q', 'idless2d_r');
276+
SELECT results_eq('idless2d_q', 'idless2d_r', 'test 24');
274277

275278
END;
276279
$BODY$

src/metrics/betweennessCentrality.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ process(
6060
result_count,
6161
&log_msg,
6262
&err_msg);
63-
time_msg(" processing Centrality", start_t, clock());
63+
time_msg(" processing pgr_betweenessCentrality", start_t, clock());
6464

6565
if (err_msg && (*result_tuples)) {
6666
pfree(*result_tuples);

0 commit comments

Comments
 (0)