1 /*PGR-GNU*****************************************************************
2  *
3 Copyright (c) 2015 Celia Virginia Vergara Castillo
4 vicky_vergara@hotmail.com
5 ------
6 
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11 
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
20 
21  ********************************************************************PGR-GNU*/
22 
23 /*! @file */
24 
25 #ifndef INCLUDE_CPP_COMMON_PGR_BASE_GRAPH_HPP_
26 #define INCLUDE_CPP_COMMON_PGR_BASE_GRAPH_HPP_
27 #pragma once
28 
29 #include <boost/graph/iteration_macros.hpp>
30 #include <boost/config.hpp>
31 #include <boost/graph/adjacency_list.hpp>
32 #include <boost/graph/graph_utility.hpp>
33 
34 #include <deque>
35 #include <vector>
36 #include <set>
37 #include <map>
38 #include <limits>
39 
40 #include "c_types/graph_enum.h"
41 
42 #include "cpp_common/basic_vertex.h"
43 #include "cpp_common/xy_vertex.h"
44 #include "cpp_common/basic_edge.h"
45 
46 #include "cpp_common/pgr_assert.h"
47 
48 namespace pgrouting {
49 
50 /*! @brief boost::graph simplified to pgRouting needs
51   This class gives the handling basics of a boost::graph of kind G
52   where G:
53   can be an undirected graph or a directed graph.
54 Requiremets:
55 ============
56 A vertex class T_V
57 ------------------
58 Current Available vertex classes:
59 - Basic_vertex
60 - XY_vertex
61 An edge class T_E
62 -----------------
63 Current Available edge classes:
64 - Basic_edge
65 extract_vertices function
66 -------------------------
67 Data obtained from postgresql is stored in
68 A C array of pgr_edge_t type.
69 ~~~~{.c}
70 std::vector< T_V >
71 extract_vertices(pgr_edge_t *, size_t)
72 ~~~~
73 Data obtained from postgresql is stored in
74 o a vector container.
75 ~~~~{.c}
76 std::vector< T_V >
77 extract_vertices(std::vector< pgr_edge_t >)
78 ~~~~
79 Boost Graph
80 -------------
81 The code is prepared to be used for:
82 - boost::adjacency_list graph type
83 - boost::undirectedS when the graph is UNDIRECTED
84 - boost::bidirectionalS when the graph is DIRECTED
85 ~~~~{.c}
86 boost::adjacency_list
87 < boost::vecS,  // not tested with other values
88 boost::vecS,  // not tested with other values
89 boost::undirectedS,  // USinG UNDIRECTED
90 Basic_vertex,  // the vertex class
91 Basic_edge >   // the edge class
92 ~~~~
93 Example Usage:
94 =============
95 For this example we will use:
96 - Basic_vertex
97 - Basic_edge
98 - pgr_edge_t
99 Create Graph type
100 -----------------
101 ~~~~{.c}
102 typedef typename
103 graph::Pgr_base_graph <
104 boost::adjacency_list <
105 boost::vecS,
106     boost::vecS,
107     boost::bidirectionalS,
108     Basic_vertex,
109     Basic_edge >,
110     Basic_vertex,
111     Basic_edge >
112     DirectedGraph;
113 ~~~~
114 Initializing the graph
115 ------------------------------
116 Graph initialization is for seting the Vertices of the graph.
117 //TODO discuss if also the edges
118 Vector of unique vertices of the graph
119 ~~~~{.c}
120 size_t total_edges;
121 pgr_edge_t *my_edges = NULL;
122 pgr_get_edges(edges_sql, &my_edges, &total_tuples);
123 std::vector< Basic_Vertex > vertices(pgrouting::extract_vertices(my_edges));
124 ~~~~
125 There are several ways to initialize the graph
126 ~~~~{.c}
127 // 1. Initializes an empty graph
128 pgrouting::DirectedGraph digraph(gType);
129 // 2. Initializes a graph based on the vertices
130 pgrouting::DirectedGraph digraph(
131     verices,
132     gType);
133 vertices.clear();
134 3. Initializes a graph based on the extracted vertices
135 pgrouting::DirectedGraph digraph(
136     pgrouting::extract_vertices(my_edges, total_edges);
137     gType);
138 4. Initializes a graph based on the extracted vertices
139 pgrouting::DirectedGraph digraph(
140     pgrouting::extract_vertices(my_edges);
141     gType);
142 ~~~~
143 1. Initializes an empty graph
144   - vertices vector size is 0
145 2. Initializes a graph based on the vertices:
146   - vertices vector size is vertices.size()
147   - the vertices are inserted
148   - vertices container can be clared to free memory
149 3. Initializes a graph based on the vertices extracted
150   - from edges stored on a C array
151   - the vertices are inserted
152 4. Initializes a graph based on the vertices extracted
153   - from edges stored on a vector
154   - the vertices are inserted
155 Fill the graph
156 ---------------------
157 After initializing the graph with the vertices, the edges can be added.
158 ~~~~{.c}
159 // inserting edges from a C array
160 digraph.insert_edges(my_edges, total_edges);
161 // adding more edges to the graph from a vector container
162 digraph.insert_edges(new_edges);
163 ~~~~
164 */
165 
166 namespace graph {
167 template <class G, typename Vertex, typename Edge>
168 class Pgr_base_graph;
169 
170 }  // namespace graph
171 
172 
173 /** @name Graph types
174   Type      |   pgRouting
175   :---------: | :---------------------
176   UndirectedGraph | Basic undirected graph
177   DirectedGraph | Basic directed graph
178   xyUndirectedGraph | X & Y values stored on the vertex
179   xyDirectedGraph | X & Y values stored on the vertex
180   */
181 //@{
182 typedef graph::Pgr_base_graph <
183 boost::adjacency_list < boost::vecS, boost::vecS,
184     boost::undirectedS,
185     Basic_vertex, Basic_edge >,
186     Basic_vertex, Basic_edge > UndirectedGraph;
187 
188 typedef graph::Pgr_base_graph <
189 boost::adjacency_list < boost::vecS, boost::vecS,
190     boost::bidirectionalS,
191     Basic_vertex, Basic_edge >,
192     Basic_vertex, Basic_edge > DirectedGraph;
193 
194 typedef graph::Pgr_base_graph <
195 boost::adjacency_list < boost::listS, boost::vecS,
196     boost::undirectedS,
197     XY_vertex, Basic_edge >,
198     XY_vertex, Basic_edge > xyUndirectedGraph;
199 
200 typedef graph::Pgr_base_graph <
201 boost::adjacency_list < boost::listS, boost::vecS,
202     boost::bidirectionalS,
203     XY_vertex, Basic_edge >,
204     XY_vertex, Basic_edge > xyDirectedGraph;
205 
206 //@}
207 
208 
209 namespace graph {
210 
211 template <typename G, typename T_V, typename T_E>
212 class Pgr_base_graph {
213  public:
214      /** @name Graph related types
215        Type      |     boost meaning     |   pgRouting meaning
216        :---------: | :-------------------- | :----------------------
217        G        | boost::adjacency_list |   Graph
218        V        | vertex_descriptor     |   Think of it as local ID of a vertex
219        E        | edge_descriptor       |   Think of it as local ID of an edge
220        V_i      | vertex_iterator       |   To cycle the vertices of the Graph
221        E_i      | edge_iterator         |   To cycle the edges of the Graph
222        EO_i     | out_edge_iterator     |   To cycle the out going edges of a vertex
223        EI_i     | in_edge_iterator      |   To cycle the in coming edges of a vertex (only in bidirectional graphs)
224        */
225      //@{
226      typedef G B_G;
227      typedef T_E G_T_E;
228      typedef T_V G_T_V;
229      typedef typename boost::graph_traits < G >::vertex_descriptor V;
230      typedef typename boost::graph_traits < G >::edge_descriptor E;
231      typedef typename boost::graph_traits < G >::vertex_iterator V_i;
232      typedef typename boost::graph_traits < G >::edge_iterator E_i;
233      typedef typename boost::graph_traits < G >::out_edge_iterator EO_i;
234      typedef typename boost::graph_traits < G >::in_edge_iterator EI_i;
235 
236      typedef typename boost::graph_traits < G >::vertices_size_type
237          vertices_size_type;
238      typedef typename boost::graph_traits < G >::edges_size_type
239          edges_size_type;
240      typedef typename boost::graph_traits < G >::degree_size_type
241          degree_size_type;
242 
243      //@}
244 
245      /** @name Id handling related types
246        Type      |  Meaning       |   pgRouting Meaning
247        :---------: | :------------- | :----------------------
248        id_to_V  | maps id -> V   | given an id store the V
249        LI       | Left Iterator  | iterates over id_to_V
250        */
251      //@{
252 
253      typedef typename std::map< int64_t, V > id_to_V;
254      typedef typename id_to_V::const_iterator LI;
255 
256      //@}
257 
258      //! @name The Graph
259      //@{
260      G graph;                //!< The graph
261      graphType m_gType;      //!< type (DIRECTED or UNDIRECTED)
262      //@}
263 
264      //! @name Id mapping handling
265      //@{
266 
267      id_to_V  vertices_map;   //!< id -> graph id
268 
269      typename boost::property_map<G, boost::vertex_index_t>::type vertIndex;
270 
271      typedef std::map<V, size_t> IndexMap;
272      IndexMap mapIndex;
273      boost::associative_property_map<IndexMap> propmapIndex;
274 
275      //@}
276 
277      //! @name Graph Modification
278      //@{
279      //! Used for storing the removed_edges
280 
281      std::deque< T_E > removed_edges;
282 
283      //@}
284 
285 
286 
287      //! @name The Graph
288      //@{
289      //! @brief Constructor
290      /*!
291        - Prepares the graph to be of type gtype
292        - inserts the vertices
293        - The vertices must be checked (if necessary)  before calling the constructor
294        */
295      Pgr_base_graph< G , T_V, T_E >(
296              const std::vector< T_V > &vertices, graphType gtype)
297          : graph(vertices.size()),
298 #if 0
299          m_num_vertices(vertices.size()),
300 #endif
301          m_gType(gtype),
302          vertIndex(boost::get(boost::vertex_index, graph)),
303          propmapIndex(mapIndex) {
304              // add_vertices(vertices);
305              // This code does not work with contraction
306 #if 0
307              pgassert(pgrouting::check_vertices(vertices) == 0);
308 #endif
309              size_t i = 0;
310              for (auto vi = boost::vertices(graph).first;
311                      vi != boost::vertices(graph).second; ++vi) {
312                  vertices_map[vertices[i].id] = (*vi);
313                  graph[(*vi)].cp_members(vertices[i]);
314                  // put(propmapIndex, *vi, num_vertices());
315                  pgassert(vertIndex[*vi] == i);
316                  ++i;
317              }
318 
319              std::ostringstream log;
320              for (auto iter = vertices_map.begin();
321                      iter != vertices_map.end();
322                      iter++) {
323                  log << "Key: "
324                      << iter->first <<"\tValue:" << iter->second << "\n";
325              }
326              for (const auto vertex : vertices) {
327                  pgassert(has_vertex(vertex.id));
328              }
329              // pgassert(mapIndex.size() == vertices.size());
330          }
331 
332      /*!
333        Prepares the _graph_ to be of type gtype with 0 vertices
334        */
335      explicit Pgr_base_graph< G , T_V, T_E >(graphType gtype)
336          : graph(0),
337 #if 0
338          m_num_vertices(0),
339 #endif
340          m_gType(gtype),
341          vertIndex(boost::get(boost::vertex_index, graph)),
342          propmapIndex(mapIndex) {
343          }
344 
345 
346      //! @name Insert edges
347      //@{
348      /*! @brief Inserts *count* edges of type *T* into the graph
349       *
350       *  Converts the edges to a std::vector<T> & calls the overloaded
351       *  twin function.
352       *
353       *  @param edges
354       *  @param count
355       */
356      template < typename T >
insert_edges(const T * edges,size_t count)357          void insert_edges(const T *edges, size_t count) {
358              insert_edges(std::vector < T >(edges, edges + count));
359          }
360 
361      template < typename T >
insert_edges_neg(const T * edges,size_t count)362          void insert_edges_neg(const T *edges, size_t count) {
363              insert_edges(std::vector < T >(edges, edges + count), false);
364          }
365 
366      template < typename T>
insert_edges(T * edges,size_t count,bool)367          void insert_edges(T *edges, size_t count, bool) {
368              for (size_t i = 0; i < count; ++i) {
369                  pgassert(has_vertex(edges[i].source));
370                  pgassert(has_vertex(edges[i].target));
371                  graph_add_edge_no_create_vertex(edges[i]);
372              }
373          }
374 
375       template < typename T >
insert_negative_edges(const T * edges,int64_t count)376          void insert_negative_edges(const T *edges, int64_t count) {
377              insert_negative_edges(std::vector < T >(edges, edges + count));
378          }
379 
380      /*! @brief Inserts *count* edges of type *pgr_edge_t* into the graph
381         The set of edges should not have an illegal vertex defined
382         When the graph is empty calls:
383         - @b extract_vertices
384         and throws an exception if there are illegal vertices.
385         When developing:
386           - if an illegal vertex is found an exception is thrown
387           - That means that the set of vertices should be checked in the
388             code that is being developed
389         No edge is inserted when there is an error on the vertices
390         @param edges
391         @param normal
392       */
393      template <typename T>
394      void
insert_edges(const std::vector<T> & edges,bool normal=true)395      insert_edges(const std::vector<T> &edges, bool normal = true) {
396 #if 0
397          // This code does not work with contraction
398          if (num_vertices() == 0) {
399              auto vertices = pgrouting::extract_vertices(edges);
400              pgassert(pgrouting::check_vertices(vertices) == 0);
401              add_vertices(vertices);
402          }
403 #endif
404          for (const auto edge : edges) {
405              graph_add_edge(edge, normal);
406          }
407      }
408 
409      template <typename T>
insert_min_edges_no_parallel(const T * edges,size_t count)410      void insert_min_edges_no_parallel(const T *edges, size_t count) {
411          insert_edges(std::vector<T>(edges, edges + count));
412      }
413 
414      template <typename T>
415      void
insert_min_edges_no_parallel(const std::vector<T> & edges)416      insert_min_edges_no_parallel(const std::vector<T> &edges) {
417          for (const auto edge : edges) {
418              graph_add_min_edge_no_parallel(edge);
419          }
420      }
421 
422      template < typename T >
insert_negative_edges(const std::vector<T> & edges,bool normal=true)423      void insert_negative_edges(
424              const std::vector<T> &edges,
425              bool normal = true) {
426          for (const auto edge : edges) {
427              graph_add_neg_edge(edge, normal);
428          }
429      }
430      //@}
431 
432  private:
433      /*! @brief adds the vertices into the graph
434       *
435       * PRECONDITIONS:
436       * - The graph has not being initialized before
437       * - There are no dupicated vertices
438       *
439       * ~~~~~{.c}
440       * precondition(boost::num_vertices(graph) == 0);
441       * for (vertex : vertices)
442       *    precondition(!has_vertex(vertex.id));
443       * ~~~~~
444       *
445       *
446       * POSTCONDITIONS:
447       * ~~~~~{.c}
448       * postcondition(boost::num_vertices(graph) == vertices.size());
449       * for (vertex : vertices)
450       *    postcondition(has_vertex(vertex.id));
451       * ~~~~~
452       *
453       * Example use:
454       *
455       * ~~~~~{.c}
456       * pgrouting::DirectedGraph digraph(gType);
457       * auto vertices(pgrouting::extract_vertices(data_edges, total_edges));
458       * digraph.add_vertices(vertices);
459       * ~~~~~
460       *
461       */
add_vertices(std::vector<T_V> vertices)462      void add_vertices(
463              std::vector< T_V > vertices) {
464          pgassert(num_vertices() == 0);
465          for (const auto vertex : vertices) {
466              pgassert(!has_vertex(vertex.id));
467 
468              auto v =  add_vertex(graph);
469              vertices_map[vertex.id] =  v;
470              graph[v].cp_members(vertex);
471              // put(propmapIndex, v, num_vertices());
472 
473              pgassert(has_vertex(vertex.id));
474          }
475          // pgassert(mapIndex.size() == vertices.size());
476          pgassert(num_vertices() == vertices.size());
477      }
478 
479 
480  public:
481      //! @name boost wrappers with original id
482      //@{
483      //! @brief get the out-degree  of a vertex
484 
485      /*!
486        @returns 0: The out degree of a vertex that its not in the graph
487        @param [in] vertex_id original vertex id
488        */
out_degree(int64_t vertex_id) const489      degree_size_type out_degree(int64_t vertex_id) const {
490          if (!has_vertex(vertex_id)) {
491              return 0;
492          }
493          auto v = get_V(vertex_id);
494          auto d = out_degree(v);
495          return d;
496      }
in_degree(int64_t vertex_id) const497      degree_size_type in_degree(int64_t vertex_id) const {
498          if (!has_vertex(vertex_id)) {
499              return 0;
500          }
501          return is_directed()?
502              in_degree(get_V(vertex_id))
503              :  out_degree(get_V(vertex_id));
504      }
505 
506 
507      /*! @brief get the vertex descriptor of the vertex
508        When the vertex does not exist
509        - creates a new vetex
510        @return V: The vertex descriptor of the vertex
511        */
get_V(const T_V & vertex)512      V get_V(const T_V &vertex) {
513          auto vm_s(vertices_map.find(vertex.id));
514          if (vm_s == vertices_map.end()) {
515              auto v =  add_vertex(graph);
516              graph[v].cp_members(vertex);
517              vertices_map[vertex.id] =  v;
518              put(propmapIndex, v, num_vertices());
519              return v;
520          }
521          return vm_s->second;
522      }
523 
524      /*! @brief get the vertex descriptor of the vid
525        Call has_vertex(vid) before calling this function
526        @return V: The vertex descriptor of the vertex
527        */
get_V(int64_t vid) const528      V get_V(int64_t vid) const {
529          pgassert(has_vertex(vid));
530          return vertices_map.find(vid)->second;
531      }
532 
533      //! @brief True when vid is in the graph
has_vertex(int64_t vid) const534      bool has_vertex(int64_t vid) const {
535          return vertices_map.find(vid) != vertices_map.end();
536      }
537 
538 
539 
540      //! @name to be or not to be
541      //@{
542 
is_directed() const543      bool is_directed() const {return m_gType == DIRECTED;}
is_undirected() const544      bool is_undirected() const {return m_gType == UNDIRECTED;}
is_source(V v_idx,E e_idx) const545      bool is_source(V v_idx, E e_idx) const {return v_idx == source(e_idx);}
is_target(V v_idx,E e_idx) const546      bool is_target(V v_idx, E e_idx) const {return v_idx == target(e_idx);}
547 
548      //@}
549 
550      //! @name boost wrappers with V
551      //@{
552 
553 
operator [](E e_idx)554      T_E& operator[](E e_idx) {return graph[e_idx];}
operator [](E e_idx) const555      const T_E& operator[](E e_idx) const {return graph[e_idx];}
556 
operator [](V v_idx)557      T_V& operator[](V v_idx) {return graph[v_idx];}
operator [](V v_idx) const558      const T_V& operator[](V v_idx) const {return graph[v_idx];}
559 
source(E e_idx) const560      V source(E e_idx) const {return boost::source(e_idx, graph);}
target(E e_idx) const561      V target(E e_idx) const {return boost::target(e_idx, graph);}
adjacent(V v_idx,E e_idx) const562      V adjacent(V v_idx, E e_idx) const {
563          pgassert(is_source(v_idx, e_idx) || is_target(v_idx, e_idx));
564          return is_source(v_idx, e_idx)?
565              target(e_idx) :
566              source(e_idx);
567      }
568 
569 
570      /*! @brief in degree of a vertex
571       *
572       * - when its undirected there is no "concept" of in degree
573       *   - out degree is returned
574       * - on directed in degree of vertex is returned
575       */
in_degree(V & v) const576      degree_size_type in_degree(V &v) const {
577          return is_directed()?
578              boost::in_degree(v, graph) :
579              boost::out_degree(v, graph);
580      }
581 
582      /*! @brief out degree of a vertex
583       *
584       * regardles of undirected or directed graph
585       * - out degree is returned
586       */
out_degree(V & v) const587      degree_size_type out_degree(V &v) const {
588          return boost::out_degree(v, graph);
589      }
590 
591      //@}
592 
593 
594      //! @name edge disconection/reconnection
595      //@{
596      //! @brief Disconnects all edges from p_from to p_to
597      /*!
598        - No edge is disconnected if the vertices id's do not exist in the graph
599        - All removed edges are stored for future reinsertion
600        - All parallel edges are disconnected (automatically by boost)
601        ![disconnect_edge(2,3) on an UNDIRECTED graph](disconnectEdgeUndirected.png)
602        ![disconnect_edge(2,3) on a DIRECTED graph](disconnectEdgeDirected.png)
603        @param [in] p_from original vertex id of the starting point of the edge
604        @param [in] p_to   original vertex id of the ending point of the edge
605        */
606      void disconnect_edge(int64_t p_from, int64_t p_to);
607 
608 
609      //! @brief Disconnects the outgoing edges of a vertex
610      /*!
611        - No edge is disconnected if it doesn't exist in the graph
612        - Removed edges are stored for future reinsertion
613        - all outgoing edges with the edge_id are removed if they exist
614        @param [in] vertex_id original vertex
615        @param [in] edge_id original edge_id
616        */
617      void disconnect_out_going_edge(int64_t vertex_id, int64_t edge_id);
618 
619 
620 
621 
622      //! @brief Disconnects all incoming and outgoing edges from the vertex
623      /*!
624        boost::graph doesn't recommend th to insert/remove vertices, so a vertex removal is
625        simulated by disconnecting the vertex from the graph
626        - No edge is disconnected if the vertices id's do not exist in the graph
627        - All removed edges are stored for future reinsertion
628        - All parallel edges are disconnected (automatically by boost)
629        ![disconnect_vertex(2) on an UNDIRECTED graph](disconnectVertexUndirected.png)
630        ![disconnect_vertex(2) on a DIRECTED graph](disconnectVertexDirected.png)
631        @param [in] p_vertex original vertex id of the starting point of the edge
632        */
633      void disconnect_vertex(int64_t p_vertex);
634      void disconnect_vertex(V vertex);
635 
636 
637      //! @brief Reconnects all edges that were removed
638      void restore_graph();
639 
640      //@}
641 
642      //! @name only for stand by program
643      //@{
644 
operator <<(std::ostream & log,const Pgr_base_graph<G,T_V,T_E> & g)645      friend std::ostream& operator<<(
646              std::ostream &log, const Pgr_base_graph< G, T_V, T_E > &g) {
647          typename Pgr_base_graph< G, T_V, T_E >::EO_i out, out_end;
648 
649          for (auto vi = vertices(g.graph).first;
650                  vi != vertices(g.graph).second; ++vi) {
651              if ((*vi) >= g.num_vertices()) break;
652              log << (*vi) << ": " << " out_edges_of(" << g.graph[(*vi)] << "):";
653              for (boost::tie(out, out_end) = out_edges(*vi, g.graph);
654                      out != out_end; ++out) {
655                  log << ' '
656                      << g.graph[*out].id << "=("
657                      << g[g.source(*out)].id << ", "
658                      << g[g.target(*out)].id << ") = "
659                      << g.graph[*out].cost <<"\t";
660              }
661              log << std::endl;
662          }
663          return log;
664      }
665 
666      //@}
667 
668 
669      int64_t get_edge_id(V from, V to, double &distance) const;
670 
get_edge(V from,V to,double & distance) const671      E get_edge(
672              V from,
673              V to,
674              double &distance) const {
675          E e;
676          EO_i out_i, out_end;
677          V v_source, v_target;
678          double minCost =  (std::numeric_limits<double>::max)();
679          E minEdge;
680          bool valid = false;
681          for (boost::tie(out_i, out_end) = boost::out_edges(from, graph);
682                  out_i != out_end; ++out_i) {
683              e = *out_i;
684              if (!valid) {
685                  minEdge = e;
686                  valid = true;
687              }
688              v_target = target(e);
689              v_source = source(e);
690              if ((from == v_source) && (to == v_target)
691                      && (distance == graph[e].cost)) {
692                  return e;
693              }
694              if ((from == v_source) && (to == v_target)
695                      && (minCost > graph[e].cost)) {
696                  minCost = graph[e].cost;
697                  minEdge = e;
698              }
699          }
700          return minEdge;
701      }
702 
num_vertices() const703      size_t num_vertices() const { return boost::num_vertices(graph);}
num_edges() const704      size_t num_edges() const { return boost::num_edges(graph);}
705 
706 
707      void graph_add_edge(const T_E &edge);
708 
709      template < typename T >
710          void graph_add_edge(const T &edge, bool normal = true);
711 
712      template < typename T >
713          void graph_add_min_edge_no_parallel(const T &edge);
714 
715       template < typename T >
716          void graph_add_neg_edge(const T &edge, bool normal = true);
717      /**
718       *  Use this function when the vertices are already inserted in the graph
719       */
720      template < typename T>
graph_add_edge_no_create_vertex(const T & edge)721      void graph_add_edge_no_create_vertex(const T &edge) {
722          bool inserted;
723          E e;
724          if ((edge.cost < 0) && (edge.reverse_cost < 0))
725              return;
726 
727 #if 0
728          std::ostringstream log;
729          for (auto iter = vertices_map.begin();
730                  iter != vertices_map.end();
731                  iter++) {
732              log << "Key: " << iter->first <<"\tValue:" << iter->second << "\n";
733          }
734          pgassertwm(has_vertex(edge.source), log.str().c_str());
735          pgassert(has_vertex(edge.target));
736 #endif
737 
738          auto vm_s = get_V(edge.source);
739          auto vm_t = get_V(edge.target);
740 
741 
742          if (edge.cost >= 0) {
743              boost::tie(e, inserted) =
744                  boost::add_edge(vm_s, vm_t, graph);
745              graph[e].cost = edge.cost;
746              graph[e].id = edge.id;
747          }
748 
749 
750          if (edge.reverse_cost >= 0 && (is_directed()
751                      || (is_undirected() && edge.cost != edge.reverse_cost))) {
752              boost::tie(e, inserted) =
753                  boost::add_edge(vm_t, vm_s, graph);
754              graph[e].cost = edge.reverse_cost;
755              graph[e].id = edge.id;
756          }
757      }
758 };
759 
760 
761 
762 
763 template < class G, typename T_V, typename T_E >
764 void
disconnect_edge(int64_t p_from,int64_t p_to)765 Pgr_base_graph< G, T_V, T_E >::disconnect_edge(int64_t p_from, int64_t p_to) {
766     T_E d_edge;
767 
768     // nothing to do, the vertex doesn't exist
769     if (!has_vertex(p_from) || !has_vertex(p_to)) return;
770 
771     EO_i out, out_end;
772     V g_from(get_V(p_from));
773     V g_to(get_V(p_to));
774 
775     // store the edges that are going to be removed
776     for (boost::tie(out, out_end) = out_edges(g_from, graph);
777             out != out_end; ++out) {
778         if (target(*out) == g_to) {
779             d_edge.id = graph[*out].id;
780             d_edge.source = graph[source(*out)].id;
781             d_edge.target = graph[target(*out)].id;
782             d_edge.cost = graph[*out].cost;
783             removed_edges.push_back(d_edge);
784         }
785     }
786     // the actual removal
787     boost::remove_edge(g_from, g_to, graph);
788 }
789 
790 
791 
792 template < class G, typename T_V, typename T_E >
793 void
disconnect_out_going_edge(int64_t vertex_id,int64_t edge_id)794 Pgr_base_graph< G, T_V, T_E >::disconnect_out_going_edge(
795         int64_t vertex_id, int64_t edge_id) {
796     T_E d_edge;
797 
798     // nothing to do, the vertex doesn't exist
799     if (!has_vertex(vertex_id)) return;
800     auto v_from(get_V(vertex_id));
801 
802     EO_i out, out_end;
803     bool change = true;
804     // store the edge that are going to be removed
805     while (change) {
806         change = false;
807         for (boost::tie(out, out_end) = out_edges(v_from, graph);
808                 out != out_end; ++out) {
809             if (graph[*out].id  == edge_id) {
810                 d_edge.id = graph[*out].id;
811                 d_edge.source = graph[source(*out)].id;
812                 d_edge.target = graph[target(*out)].id;
813                 d_edge.cost = graph[*out].cost;
814                 removed_edges.push_back(d_edge);
815                 boost::remove_edge((*out), graph);
816                 change = true;
817                 break;
818             }
819         }
820     }
821 }
822 
823 
824 template < class G, typename T_V, typename T_E >
825 void
disconnect_vertex(int64_t vertex)826 Pgr_base_graph< G, T_V, T_E >::disconnect_vertex(int64_t vertex) {
827     if (!has_vertex(vertex)) return;
828     disconnect_vertex(get_V(vertex));
829 }
830 
831 template < class G, typename T_V, typename T_E >
832 void
disconnect_vertex(V vertex)833 Pgr_base_graph< G, T_V, T_E >::disconnect_vertex(V vertex) {
834     T_E d_edge;
835 
836     EO_i out, out_end;
837     // store the edges that are going to be removed
838     for (boost::tie(out, out_end) = out_edges(vertex, graph);
839             out != out_end; ++out) {
840         d_edge.id = graph[*out].id;
841         d_edge.source = graph[source(*out)].id;
842         d_edge.target = graph[target(*out)].id;
843         d_edge.cost = graph[*out].cost;
844         removed_edges.push_back(d_edge);
845     }
846 
847     // special case
848     if (m_gType == DIRECTED) {
849         EI_i in, in_end;
850         for (boost::tie(in, in_end) = in_edges(vertex, graph);
851                 in != in_end; ++in) {
852             d_edge.id = graph[*in].id;
853             d_edge.source = graph[source(*in)].id;
854             d_edge.target = graph[target(*in)].id;
855             d_edge.cost = graph[*in].cost;
856             removed_edges.push_back(d_edge);
857         }
858     }
859 
860     // delete incoming and outgoing edges from the vertex
861     boost::clear_vertex(vertex, graph);
862 }
863 
864 template < class G, typename T_V, typename T_E >
865 void
restore_graph()866 Pgr_base_graph< G, T_V, T_E >::restore_graph() {
867     while (removed_edges.size() != 0) {
868         graph_add_edge(removed_edges[0]);
869         removed_edges.pop_front();
870     }
871 }
872 
873 
874 
875 
876 template < class G, typename T_V, typename T_E >
877 int64_t
get_edge_id(V from,V to,double & distance) const878 Pgr_base_graph< G, T_V, T_E >::get_edge_id(
879         V from,
880         V to,
881         double &distance) const {
882     E e;
883     EO_i out_i, out_end;
884     V v_source, v_target;
885     double minCost =  (std::numeric_limits<double>::max)();
886     int64_t minEdge = -1;
887     for (boost::tie(out_i, out_end) = boost::out_edges(from, graph);
888             out_i != out_end; ++out_i) {
889         e = *out_i;
890         v_target = target(e);
891         v_source = source(e);
892         if ((from == v_source) && (to == v_target)
893                 && (distance == graph[e].cost))
894             return graph[e].id;
895         if ((from == v_source) && (to == v_target)
896                 && (minCost > graph[e].cost)) {
897             minCost = graph[e].cost;
898             minEdge = graph[e].id;
899         }
900     }
901     distance = minEdge == -1? 0: minCost;
902     return minEdge;
903 }
904 
905 
906 template < class G, typename T_V, typename T_E >
907 void
graph_add_edge(const T_E & edge)908 Pgr_base_graph< G, T_V, T_E >::graph_add_edge(const T_E &edge ) {
909     typename Pgr_base_graph< G, T_V, T_E >::LI vm_s, vm_t;
910     typename Pgr_base_graph< G, T_V, T_E >::E e;
911 
912     vm_s = vertices_map.find(edge.source);
913     if (vm_s == vertices_map.end()) {
914         vertices_map[edge.source]=  num_vertices();
915         vm_s = vertices_map.find(edge.source);
916     }
917 
918     vm_t = vertices_map.find(edge.target);
919     if (vm_t == vertices_map.end()) {
920         vertices_map[edge.target]=  num_vertices();
921         vm_t = vertices_map.find(edge.target);
922     }
923 
924     if (edge.cost >= 0) {
925         bool inserted;
926         boost::tie(e, inserted) =
927             boost::add_edge(vm_s->second, vm_t->second, graph);
928         graph[e].cp_members(edge);
929     }
930 }
931 
932 
933 template < class G, typename T_V, typename T_E >
934 template < typename T>
935 void
graph_add_edge(const T & edge,bool normal)936 Pgr_base_graph< G, T_V, T_E >::graph_add_edge(const T &edge, bool normal) {
937     bool inserted;
938     typename Pgr_base_graph< G, T_V, T_E >::E e;
939     if ((edge.cost < 0) && (edge.reverse_cost < 0))
940         return;
941 
942     /*
943      * true: for source
944      * false: for target
945      */
946     auto vm_s = get_V(T_V(edge, true));
947     auto vm_t = get_V(T_V(edge, false));
948 
949     pgassert(vertices_map.find(edge.source) != vertices_map.end());
950     pgassert(vertices_map.find(edge.target) != vertices_map.end());
951     if (edge.cost >= 0) {
952         boost::tie(e, inserted) =
953             boost::add_edge(vm_s, vm_t, graph);
954         graph[e].cost = edge.cost;
955         graph[e].id = edge.id;
956     }
957 
958     if (edge.reverse_cost >= 0
959             && (m_gType == DIRECTED
960                 || (m_gType == UNDIRECTED && edge.cost != edge.reverse_cost))) {
961         boost::tie(e, inserted) =
962             boost::add_edge(vm_t, vm_s, graph);
963 
964         graph[e].cost = edge.reverse_cost;
965         graph[e].id = normal? edge.id : -edge.id;
966     }
967 }
968 
969 template < class G, typename T_V, typename T_E >
970 template < typename T>
971 void
graph_add_min_edge_no_parallel(const T & edge)972 Pgr_base_graph< G, T_V, T_E >::graph_add_min_edge_no_parallel(const T &edge) {
973     bool inserted;
974     typename Pgr_base_graph< G, T_V, T_E >::E e;
975     if ((edge.cost < 0) && (edge.reverse_cost < 0))
976         return;
977 
978     /*
979      * true: for source
980      * false: for target
981      */
982     auto vm_s = get_V(T_V(edge, true));
983     auto vm_t = get_V(T_V(edge, false));
984 
985     pgassert(vertices_map.find(edge.source) != vertices_map.end());
986     pgassert(vertices_map.find(edge.target) != vertices_map.end());
987     if (edge.cost >= 0) {
988         E e1;
989         bool found;
990         boost::tie(e1, found) = edge(vm_s, vm_t, graph);
991         if (found) {
992             if (edge.cost < graph[e1].cost) {
993                 graph[e1].cost = edge.cost;
994                 graph[e1].id = edge.id;
995             }
996         } else {
997             boost::tie(e, inserted) =
998                 boost::add_edge(vm_s, vm_t, graph);
999             graph[e].cost = edge.cost;
1000             graph[e].id = edge.id;
1001         }
1002     }
1003 
1004     if (edge.reverse_cost >= 0
1005             && (m_gType == DIRECTED
1006                 || (m_gType == UNDIRECTED && edge.cost != edge.reverse_cost))) {
1007         E e1;
1008         bool found;
1009         boost::tie(e1, found) = edge(vm_t, vm_s, graph);
1010         if (found) {
1011             if (edge.reverse_cost < graph[e1].cost) {
1012                 graph[e1].cost = edge.reverse_cost;
1013                 graph[e1].id = edge.id;
1014             }
1015         } else {
1016             boost::tie(e, inserted) =
1017                 boost::add_edge(vm_t, vm_s, graph);
1018 
1019             graph[e].cost = edge.reverse_cost;
1020             graph[e].id = edge.id;
1021         }
1022     }
1023 }
1024 
1025 #if 1
1026 /*
1027 Add edges with negative cost(either cost or reverse_cost or both)
1028 Reading them into graph as positive cost ( edge_cost = (-1)* edge_negative_cost) [L931 & L941]
1029 To Do: Read and apply edges with negative cost in function as it is
1030 */
1031 
1032 template < class G, typename T_V, typename T_E >
1033 template < typename T>
1034 void
graph_add_neg_edge(const T & edge,bool normal)1035 Pgr_base_graph< G, T_V, T_E >::graph_add_neg_edge(const T &edge, bool normal) {
1036     bool inserted;
1037     typename Pgr_base_graph< G, T_V, T_E >::E e;
1038 
1039     auto vm_s = get_V(T_V(edge, true));
1040     auto vm_t = get_V(T_V(edge, false));
1041 
1042     pgassert(vertices_map.find(edge.source) != vertices_map.end());
1043     pgassert(vertices_map.find(edge.target) != vertices_map.end());
1044 
1045     boost::tie(e, inserted) =
1046             boost::add_edge(vm_s, vm_t, graph);
1047         if (edge.cost < 0) {
1048             // reading negative edges as positive
1049             graph[e].cost = (-0.5)*edge.cost;
1050         } else {
1051             graph[e].cost = edge.cost;
1052         }
1053         graph[e].id = edge.id;
1054 
1055     if (m_gType == DIRECTED
1056               || (m_gType == UNDIRECTED && edge.cost > edge.reverse_cost)) {
1057         boost::tie(e, inserted) =
1058             boost::add_edge(vm_t, vm_s, graph);
1059         if (edge.reverse_cost < 0) {
1060             // reading negative edges as positive
1061             graph[e].cost = (-0.5)*edge.reverse_cost;
1062         } else {
1063             graph[e].cost = edge.reverse_cost;
1064         }
1065 
1066         graph[e].id = normal? edge.id : -edge.id;
1067       }
1068 }
1069 #endif
1070 
1071 /******************  PRIVATE *******************/
1072 
1073 }  // namespace graph
1074 }  // namespace pgrouting
1075 #endif  // INCLUDE_CPP_COMMON_PGR_BASE_GRAPH_HPP_
1076