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