1 /*PGR-GNU*****************************************************************
2 File: basePath_SSEC.cpp
3
4 Copyright (c) 2015 Celia Virginia Vergara Castillo
5 vicky_vergara@hotmail.com
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 #include "cpp_common/basePath_SSEC.hpp"
26
27 #include <cmath>
28 #include <limits>
29 #include <deque>
30 #include <iostream>
31 #include <algorithm>
32 #include <utility>
33
34 #include "c_types/general_path_element_t.h"
35 #include "cpp_common/pgr_assert.h"
36
37
renumber_vertices(int64_t value)38 Path& Path::renumber_vertices(int64_t value) {
39 for (auto &r : path) {
40 r.node += value;
41 }
42 m_start_id += value;
43 m_end_id += value;
44 return *this;
45 }
46
push_front(Path_t data)47 void Path::push_front(Path_t data) {
48 path.push_front(data);
49 m_tot_cost += data.cost;
50 }
51
push_back(Path_t data)52 void Path::push_back(Path_t data) {
53 path.push_back(data);
54 m_tot_cost += data.cost;
55 }
56
reverse()57 void Path::reverse() {
58 std::swap(m_start_id, m_end_id);
59 if (path.size() <= 1) return;
60 std::deque< Path_t > newpath;
61 for (size_t i = 0; i < path.size(); ++i) {
62 newpath.push_front({
63 path[i].node,
64 (i == 0? -1 : path[i - 1].edge),
65 (i == 0? 0 : path[i - 1].cost),
66 0
67 });
68 }
69 for (size_t i = 0; i < newpath.size(); ++i) {
70 newpath[i].agg_cost = (i == 0)?
71 0 :
72 newpath[i - 1].agg_cost + newpath[i - 1].cost;
73 }
74 path = newpath;
75 }
76
recalculate_agg_cost()77 void Path::recalculate_agg_cost() {
78 m_tot_cost = 0;
79 for (auto &p : path) {
80 p.agg_cost = m_tot_cost;
81 m_tot_cost += p.cost;
82 }
83 }
84
85
86
clear()87 void Path::clear() {
88 path.clear();
89 m_tot_cost = 0;
90 m_start_id = 0;
91 m_end_id = 0;
92 }
93
find_restriction(const pgrouting::trsp::Rule & rule) const94 Path::ConstpthIt Path::find_restriction(
95 const pgrouting::trsp::Rule &rule) const {
96 return std::search(path.begin(), path.end(), rule.begin(), rule.end(),
97 [](Path_t p, int64_t e) {return p.edge == e;});
98 }
99
has_restriction(const pgrouting::trsp::Rule & rule) const100 bool Path::has_restriction(
101 const pgrouting::trsp::Rule &rule) const {
102 return find_restriction(rule) != path.end();
103 }
104
inf_cost_on_restriction(const pgrouting::trsp::Rule & rule)105 Path Path::inf_cost_on_restriction(
106 const pgrouting::trsp::Rule &rule) {
107 auto position = std::search(
108 path.begin(), path.end(), rule.begin(), rule.end(),
109 [](Path_t p, int64_t e) { return p.edge == e;});
110 if (position != path.end()) {
111 position->agg_cost = std::numeric_limits<double>::infinity();
112 }
113 return *this;
114 }
115
116
117
operator <<(std::ostream & log,const Path & path)118 std::ostream& operator<<(std::ostream &log, const Path &path) {
119 log << "Path: " << path.start_id() << " -> " << path.end_id() << "\n"
120 << "seq\tnode\tedge\tcost\tagg_cost\n";
121 int64_t i = 0;
122 for (const auto &e : path) {
123 log << i << "\t"
124 << e.node << "\t"
125 << e.edge << "\t"
126 << e.cost << "\t"
127 << e.agg_cost << "\n";
128 ++i;
129 }
130 return log;
131 }
132
countInfinityCost() const133 size_t Path::countInfinityCost() const {
134 return static_cast<size_t>(std::count_if(path.begin(), path.end(),
135 [](Path_t const&p) -> size_t {
136 return std::isinf(p.agg_cost);
137 }));
138 }
139
140
getSubpath(unsigned int j) const141 Path Path::getSubpath(unsigned int j) const {
142 Path result(start_id(), end_id());
143 if (j == 0) return result;
144 for (auto i = path.begin(); i != path.begin() + j; ++i) {
145 result.push_back((*i));
146 }
147 pgassert(result.tot_cost() != 0);
148 pgassert(this->tot_cost() != 0);
149 return result;
150 }
151
152
isEqual(const Path & subpath) const153 bool Path::isEqual(const Path &subpath) const {
154 if (subpath.empty()) return true;
155 if (subpath.size() >= path.size()) return false;
156 std::deque< Path_t >::const_iterator i, j;
157 for (i = path.begin(), j = subpath.begin();
158 j != subpath.end();
159 ++i, ++j)
160 if ((*i).node != (*j).node) return false;
161 return true;
162 }
163
appendPath(const Path & o_path)164 void Path::appendPath(const Path &o_path) {
165 path.insert(path.end(), o_path.path.begin(), o_path.path.end());
166 recalculate_agg_cost();
167 }
168
169
170 /*!
171 Path: 2 -> 9
172 seq node edge cost agg_cost
173 0 2 4 1 0
174 1 5 8 1 1
175 2 6 9 1 2
176 3 9 -1 0 3
177 Path: 9 -> 3
178 seq node edge cost agg_cost
179 0 9 16 1 0
180 1 4 3 1 1
181 2 3 -1 0 2
182 Path: 2 -> 3
183 seq node edge cost agg_cost
184 0 2 4 1 0
185 1 5 8 1 1
186 2 6 9 1 2
187 3 9 16 1 3
188 4 4 3 1 4
189 5 3 -1 0 5
190
191 */
append(const Path & other)192 void Path::append(const Path &other) {
193 pgassert(m_end_id == other.m_start_id);
194 if (other.m_start_id == other.m_end_id) {
195 pgassert(other.path.empty());
196 return;
197 }
198 if (m_start_id == m_end_id) {
199 pgassert(path.empty());
200 *this = other;
201 return;
202 }
203 #if 0
204 pgassert(path.back().cost == 0);
205 #endif
206 pgassert(path.back().edge == -1);
207 m_end_id = other.m_end_id;
208
209 auto last = path.back();
210 auto agg_cost = last.agg_cost;
211
212 path.pop_back();
213
214 for (auto item : other.path) {
215 item.agg_cost += agg_cost;
216 push_back(item);
217 }
218 }
219
220
generate_postgres_data(General_path_element_t ** postgres_data,size_t & sequence) const221 void Path::generate_postgres_data(
222 General_path_element_t **postgres_data,
223 size_t &sequence) const {
224 int i = 1;
225 for (const auto e : path) {
226 auto agg_cost = std::fabs(
227 e.agg_cost - (std::numeric_limits<double>::max)()) < 1?
228 std::numeric_limits<double>::infinity() : e.agg_cost;
229 auto cost = std::fabs(e.cost - (std::numeric_limits<double>::max)()) < 1?
230 std::numeric_limits<double>::infinity() : e.cost;
231
232 (*postgres_data)[sequence] = {i, start_id(), end_id(), e.node, e.edge, cost, agg_cost};
233 ++i;
234 ++sequence;
235 }
236 }
237
238 /* used by driving distance */
get_pg_dd_path(General_path_element_t ** ret_path,size_t & sequence) const239 void Path::get_pg_dd_path(
240 General_path_element_t **ret_path,
241 size_t &sequence) const {
242 for (unsigned int i = 0; i < path.size(); i++) {
243 (*ret_path)[sequence].seq = static_cast<int>(i);
244 (*ret_path)[sequence].start_id = start_id();
245 (*ret_path)[sequence].end_id = start_id();
246 (*ret_path)[sequence].node = path[i].node;
247 (*ret_path)[sequence].edge = path[i].edge;
248 (*ret_path)[sequence].cost = path[i].cost;
249 (*ret_path)[sequence].agg_cost = path[i].agg_cost;
250 sequence++;
251 }
252 }
253
254 /* used by ksp */
get_pg_ksp_path(General_path_element_t ** ret_path,size_t & sequence,int routeId) const255 void Path::get_pg_ksp_path(
256 General_path_element_t **ret_path,
257 size_t &sequence, int routeId) const {
258 for (unsigned int i = 0; i < path.size(); i++) {
259 (*ret_path)[sequence].seq = static_cast<int>(i + 1);
260 (*ret_path)[sequence].start_id = routeId;
261 (*ret_path)[sequence].end_id = end_id();
262 (*ret_path)[sequence].node = path[i].node;
263 (*ret_path)[sequence].edge = path[i].edge;
264 (*ret_path)[sequence].cost = path[i].cost;
265 (*ret_path)[sequence].agg_cost = (i == 0)?
266 0 :
267 (*ret_path)[sequence-1].agg_cost + path[i-1].cost;
268 sequence++;
269 }
270 }
271
272 /* used by turn restricted */
get_pg_turn_restricted_path(General_path_element_t ** ret_path,size_t & sequence,int routeId) const273 void Path::get_pg_turn_restricted_path(
274 General_path_element_t **ret_path,
275 size_t &sequence, int routeId) const {
276 for (unsigned int i = 0; i < path.size(); i++) {
277 (*ret_path)[sequence].seq = static_cast<int>(i + 1);
278 (*ret_path)[sequence].start_id = routeId;
279 (*ret_path)[sequence].end_id = end_id();
280 (*ret_path)[sequence].node = path[i].node;
281 (*ret_path)[sequence].edge = path[i].edge;
282 (*ret_path)[sequence].cost = path[i].cost;
283 (*ret_path)[sequence].agg_cost = path[i].agg_cost;
284 sequence++;
285 }
286 }
287
288
289 /** @brief Sorts a path by node, aggcost ascending
290 *
291 * nodes ASC
292 * agg_cost ASC
293 */
294 void
sort_by_node_agg_cost()295 Path::sort_by_node_agg_cost() {
296 std::sort(path.begin(), path.end(),
297 [](const Path_t &l, const Path_t &r)
298 {return l.node < r.node;});
299 std::stable_sort(path.begin(), path.end(),
300 [](const Path_t &l, const Path_t &r)
301 {return l.agg_cost < r.agg_cost;});
302 }
303
304 /*
305 * FRIENDS
306 */
307
308
309 size_t
collapse_paths(General_path_element_t ** ret_path,const std::deque<Path> & paths)310 collapse_paths(
311 General_path_element_t **ret_path,
312 const std::deque< Path > &paths) {
313 size_t sequence = 0;
314 for (const Path &path : paths) {
315 if (path.path.size() > 0)
316 path.generate_postgres_data(ret_path, sequence);
317 }
318 return sequence;
319 }
320
321 /*
322 * sort the paths by size from greater to smaller
323 * and sort each path by node
324 * all the nodes on p2 are going to be compared
325 * with the nodes of p1
326 *
327 * When both paths reach the node and p1.agg_cost > p2.agg_cost
328 * erase the node of p1
329 * (can't erase from p2 because we loose the iterators
330 * so in a future cycle it will be deleted)
331 *
332 * sort the paths by start_id,
333 */
334
335 void
equi_cost(std::deque<Path> & paths)336 equi_cost(std::deque< Path > &paths) {
337 /* sort paths by size: largest first */
338 std::sort(paths.begin(), paths.end(),
339 [](const Path &e1, const Path &e2)->bool {
340 return e2.size() < e1.size();
341 });
342
343 /* sort each path by node: smaller id first */
344 for (auto &p : paths) {
345 if (p.size() < 2) continue;
346 std::sort(p.begin(), p.end(),
347 [](const Path_t &e1, const Path_t &e2)->bool {
348 return e1.node < e2.node;
349 });
350 }
351
352 for (auto &p1 : paths) {
353 for (const auto &p2 : paths) {
354 if (p1.start_id() == p2.start_id()) continue;
355 for (const auto &stop : p2.path) {
356 /* find the node of p2 in p1 */
357 auto pos = lower_bound(p1.begin(), p1.end(), stop,
358 [](const Path_t &l, const Path_t &r)->bool {
359 return l.node < r.node;
360 });
361
362 if (pos != p1.end()
363 && (stop.node == pos->node)
364 && (stop.agg_cost < pos->agg_cost)) {
365 /* both share the same node &
366 * the second path has the smallest
367 * So erasing from the first path */
368 p1.erase(pos);
369 }
370 }
371 }
372 }
373 /* sort paths by start_id */
374 std::sort(paths.begin(), paths.end(),
375 [](const Path &e1, const Path &e2)->bool {
376 return e1.start_id() < e2.start_id();
377 });
378
379 /* sort each path by agg_cost, node */
380 for (auto &path : paths) {
381 path.sort_by_node_agg_cost();
382 }
383 }
384
385
386 size_t
count_tuples(const std::deque<Path> & paths)387 count_tuples(const std::deque< Path > &paths) {
388 size_t count(0);
389 for (const Path &e : paths) {
390 count += e.path.size();
391 }
392 return count;
393 }
394