PGROUTING  3.2
pgr_chinesePostman.hpp
Go to the documentation of this file.
1 /*PGR-GNU*****************************************************************
2 
3 Copyright (c) 2015 pgRouting developers
5 
6 Copyright (c) 2018 Maoguang Wang
8 
9 ------
10 
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
15 
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
20 
21 You should have received a copy of the GNU General Public License
22 along with this program; if not, write to the Free Software
23 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 
25  ********************************************************************PGR-GNU*/
26 
27 #ifndef INCLUDE_CHINESE_PGR_CHINESEPOSTMAN_HPP_
28 #define INCLUDE_CHINESE_PGR_CHINESEPOSTMAN_HPP_
29 #pragma once
30 
31 #include <map>
32 #include <vector>
33 #include <utility>
34 #include <set>
35 #include <limits>
36 #include <stack>
37 
40 #include "c_types/pgr_edge_t.h"
41 #include "c_types/pgr_flow_t.h"
42 #include "cpp_common/pgr_assert.h"
44 
45 
46 namespace pgrouting {
47 namespace graph {
48 
50  public:
52  const pgr_edge_t *dataEdges,
53  const size_t totalEdges);
54 
55  double DirectedChPP() const {
56  return m_cost;
57  }
58 
59  std::vector<General_path_element_t> GetPathEdges() const {
60  return resultPath;
61  }
62 
64 
65 
66  private:
67  bool EulerCircuitDFS(int64_t p);
68  void BuildResultGraph();
69  void BuildResultPath();
70  void setPathEdges(graph::PgrCostFlowGraph &flowGraph);
71 
72  private:
73  int64_t totalDeg;
74  double totalCost;
76  int64_t startPoint;
77  double m_cost;
79 
83  std::map<std::pair<int64_t, int64_t>, const pgr_edge_t*> edgeToIdx;
84  std::map<std::pair<int64_t, int64_t>, // source, target
85  size_t> edgeToId; // index in resultEdges
86 
87  std::vector<pgr_edge_t> originalEdges;
88  std::vector<pgr_edge_t> resultEdges;
89 
91  std::vector<std::pair<int64_t, std::vector<size_t>>> resultGraph;
92  std::map<int64_t, size_t> VToVecid;
95 
96  std::stack<int64_t> pathStack; // node stack
97  std::vector<General_path_element_t> resultPath;
98 
99  /* for the flow graph */
100  std::vector<pgr_costFlow_t> edges;
101  std::set<int64_t> sources;
102  std::set<int64_t> targets;
103 };
104 
106  edgeToIdx.clear();
107 }
109  const pgr_edge_t *dataEdges,
110  const size_t totalEdges) :
111  totalDeg(0), totalCost(0), vertices(),
112  edgeToIdx(), originalEdges(),
113  resultGraph(), VToVecid(), edgeVisited(),
114  pathStack(), resultPath(),
115  edges(), sources(), targets() {
116  pgassert(totalEdges > 0);
117  pgassert(pathStack.empty());
118 
119  pgassert(originalEdges.empty());
120  startPoint = dataEdges[0].source;
121  for (size_t i = 0; i < totalEdges; ++i) {
122  if (dataEdges[i].cost > 0) {
123  auto edge(dataEdges[i]);
124  edge.reverse_cost = -1.0;
125  totalCost += edge.cost;
126  originalEdges.push_back(edge);
127  vertices += dataEdges[i].source;
128  vertices += dataEdges[i].target;
129  }
130  if (dataEdges[i].reverse_cost > 0) {
131  auto edge(dataEdges[i]);
132  std::swap(edge.source, edge.target);
133  std::swap(edge.cost, edge.reverse_cost);
134  edge.reverse_cost = -1.0;
135  totalCost += edge.cost;
136  originalEdges.push_back(edge);
137  vertices += dataEdges[i].source;
138  vertices += dataEdges[i].target;
139  pgassert(dataEdges[i].source == edge.target);
140  pgassert(dataEdges[i].target == edge.source);
141  }
142  }
143 
144  // calcu deg & build part of edges
145  std::map<int64_t, int> deg;
146  size_t i(0);
147  for (const auto &e : originalEdges) {
148  pgassert(e.cost > 0);
149  /* has out going edge */
150  deg[e.source]++;
151  /* has out incoming edge */
152  deg[e.target]--;
153 
154  auto current_edge(std::make_pair(e.source, e.target));
155  if (edgeToIdx.find(current_edge) == edgeToIdx.end()) {
156  edgeToIdx[current_edge] = &e;
157  } else {
158  if (edgeToIdx[current_edge]->cost > e.cost) {
159  edgeToIdx[current_edge] = &e;
160  }
161  }
162 
164  edge.edge_id = e.id;
165  edge.reverse_capacity = -1;
166  edge.reverse_cost = -1.0;
167  edge.source = e.source;
168  edge.target = e.target;
169  edge.capacity = (std::numeric_limits<int32_t>::max)();
170  edge.cost = e.cost;
171  edges.push_back(edge);
172  ++i;
173  }
174 
175  superSource = deg.rbegin()->first + 1;
176  superTarget = deg.rbegin()->first + 2;
177 
178  sources.insert(superSource);
179  targets.insert(superTarget);
180 
181  // build full edges
182  std::map<int64_t, int>::iterator iter;
183  totalDeg = 0;
184  for (iter = deg.begin(); iter != deg.end(); ++iter) {
185  int64_t p = iter->first;
186  int d = iter->second;
187  if (d == 0)
188  continue;
189  if (d > 0)
190  totalDeg += d;
192  edge.reverse_capacity = -1;
193  edge.reverse_cost = -1.0;
194  edge.cost = 0.0;
195  if (d > 0)
196  edge.capacity = d;
197  else
198  edge.capacity = -d;
199  edge.edge_id = 0;
200  if (d > 0)
202  if (d < 0)
204  edges.push_back(edge);
205  }
206 
207  PgrCostFlowGraph flowGraph(edges, sources, targets);
208  pgassert(pathStack.empty());
209  try {
211  auto minAddedCost = digraph1.MinCostMaxFlow();
212  auto maxFlow = digraph1.GetMaxFlow();
213  m_cost = (maxFlow == totalDeg)? minAddedCost + totalCost : -1.0;
214  } catch (...) {
215  m_cost = -1;
216  }
217  setPathEdges(flowGraph);
218 }
219 
220 
221 void
223  pgassert(pathStack.empty());
224  resultPath.clear();
225  if (m_cost == -1) return;
226  // catch new edges
227  try {
228  flowGraph.MinCostMaxFlow();
229  flowGraph.GetMaxFlow();
230  std::vector<pgr_flow_t> addedEdges = flowGraph.GetFlowEdges();
232  for (auto &flow_t : addedEdges) {
233  if (flow_t.source != superSource && flow_t.source != superTarget
234  && flow_t.target != superSource && flow_t.target != superTarget) {
235  auto current_edge(std::make_pair(flow_t.source, flow_t.target));
236  pgr_edge_t newEdge = *edgeToIdx[current_edge];
237  /* adding edges that need to be traversed twice */
238  while (flow_t.flow--) resultEdges.push_back(newEdge);
239  }
240  }
241  } catch (...) {
242  resultPath.clear();
243  return;
244  }
245 
246  pgassert(pathStack.empty());
248 
249  pgassert(pathStack.empty());
251 
252 
254 
255  if (!(vertices - vertexVisited).empty()) {
256  resultPath.clear();
257  return;
258  }
259  pgassert(!pathStack.empty());
260 
261  BuildResultPath();
262 
263 
264  return;
265 }
266 
267 void
269  if (pathStack.empty()) return;
270  pgassert(resultPath.empty());
271 
272  int64_t preNode = pathStack.top();
273  pathStack.pop();
274 
275  General_path_element_t newElement;
276  while (!pathStack.empty()) {
277  int64_t nowNode = pathStack.top();
278  pathStack.pop();
279 
280  auto edge_t = *edgeToIdx[std::make_pair(preNode, nowNode)];
281  newElement.node = edge_t.source;
282  newElement.edge = edge_t.id;
283  newElement.cost = edge_t.cost;
284  if (resultPath.empty()) {
285  /* adding the first row because is a cycle */
286  newElement.seq = 1;
287  newElement.agg_cost = 0.0;
288  } else {
289  newElement.seq = resultPath.back().seq + 1;
290  newElement.agg_cost = resultPath.back().agg_cost + resultPath.back().cost;
291  }
292  resultPath.push_back(newElement);
293  preNode = nowNode;
294  }
295  newElement.node = preNode;
296  newElement.edge = -1;
297  newElement.cost = 0;
298  if (resultPath.empty()) {
299  newElement.seq = 1;
300  newElement.agg_cost = 0.0;
301  } else {
302  newElement.seq = resultPath.back().seq + 1;
303  newElement.agg_cost =
304  resultPath.back().agg_cost + resultPath.back().cost;
305  }
306  resultPath.push_back(newElement);
307 }
308 
309 // perform DFS approach to generate Euler circuit
310 // TODO(mg) find suitable API in BGL, maybe DfsVisitor will work.
311 // Implement DFS without BGL for now
312 bool
314  for (const auto e : resultGraph[VToVecid[vertex]].second) {
315  if (!edgeVisited.has(e)) {
316  edgeVisited += e;
317  EulerCircuitDFS(resultEdges[e].target);
318  }
319  }
320  pathStack.push(vertex);
321  vertexVisited += vertex;
322  return true;
323 }
324 
325 void
327  pgassert(resultGraph.empty());
328  pgassert(VToVecid.empty());
329  resultGraph.clear();
330  VToVecid.clear();
331  size_t e_id(0);
332  for (const auto &edge_t : resultEdges) {
333  if (VToVecid.find(edge_t.source) == VToVecid.end()) {
334  VToVecid[edge_t.source] = resultGraph.size();
335  resultGraph.resize(resultGraph.size() + 1);
336  }
337  size_t vid = VToVecid[edge_t.source];
338  resultGraph[vid].second.push_back(e_id);
339  resultGraph[vid].first = edge_t.source;
340  ++e_id;
341  }
342 }
343 
344 
345 } // namespace graph
346 } // namespace pgrouting
347 
348 #endif // INCLUDE_CHINESE_PGR_CHINESEPOSTMAN_HPP_
pgrouting::graph::PgrDirectedChPPGraph::vertexVisited
Identifiers< int64_t > vertexVisited
Definition: pgr_chinesePostman.hpp:94
edge::reverse_cost
float8 reverse_cost
Definition: trsp.h:46
pgrouting::graph::PgrCostFlowGraph
Definition: pgr_minCostMaxFlow.hpp:51
pgrouting::graph::PgrDirectedChPPGraph::sources
std::set< int64_t > sources
Definition: pgr_chinesePostman.hpp:101
General_path_element_t::edge
int64_t edge
Definition: general_path_element_t.h:42
edge::cost
float8 cost
Definition: trsp.h:45
pgrouting::graph::PgrDirectedChPPGraph::BuildResultGraph
void BuildResultGraph()
Definition: pgr_chinesePostman.hpp:326
pgrouting::graph::PgrDirectedChPPGraph::m_cost
double m_cost
Definition: pgr_chinesePostman.hpp:77
edge_t::source
int64_t source
Definition: trsp_types.h:39
edge::target
int64 target
Definition: trsp.h:44
pgr_edge_t
Definition: pgr_edge_t.h:37
General_path_element_t::seq
int seq
Definition: general_path_element_t.h:38
edge_t
Definition: trsp_types.h:37
pgrouting::graph::PgrDirectedChPPGraph::originalEdges
std::vector< pgr_edge_t > originalEdges
Definition: pgr_chinesePostman.hpp:87
pgr_edge_t::source
int64_t source
Definition: pgr_edge_t.h:39
pgrouting::graph::PgrDirectedChPPGraph::vertices
Identifiers< int64_t > vertices
Definition: pgr_chinesePostman.hpp:78
pgrouting::graph::PgrDirectedChPPGraph::DirectedChPP
double DirectedChPP() const
Definition: pgr_chinesePostman.hpp:55
pgrouting::graph::PgrDirectedChPPGraph::edgeVisited
Identifiers< size_t > edgeVisited
Definition: pgr_chinesePostman.hpp:93
pgrouting::graph::PgrDirectedChPPGraph::resultPath
std::vector< General_path_element_t > resultPath
Definition: pgr_chinesePostman.hpp:97
pgr_edge_t::target
int64_t target
Definition: pgr_edge_t.h:40
pgrouting::graph::PgrDirectedChPPGraph::PgrDirectedChPPGraph
PgrDirectedChPPGraph(const pgr_edge_t *dataEdges, const size_t totalEdges)
Definition: pgr_chinesePostman.hpp:108
pgrouting::graph::PgrCostFlowGraph::MinCostMaxFlow
double MinCostMaxFlow()
Definition: pgr_minCostMaxFlow.hpp:63
pgrouting::graph::PgrDirectedChPPGraph::edgeToIdx
std::map< std::pair< int64_t, int64_t >, const pgr_edge_t * > edgeToIdx
(source, target) -> idx to originalEdges; Only the one with the lower cost is kept
Definition: pgr_chinesePostman.hpp:83
edge
Definition: trsp.h:41
pgassert
#define pgassert(expr)
Uses the standard assert syntax.
Definition: pgr_assert.h:94
pgrouting::graph::PgrDirectedChPPGraph::GetPathEdges
std::vector< General_path_element_t > GetPathEdges() const
Definition: pgr_chinesePostman.hpp:59
pgrouting::graph::PgrDirectedChPPGraph::edges
std::vector< pgr_costFlow_t > edges
Definition: pgr_chinesePostman.hpp:100
pgr_minCostMaxFlow.hpp
pgrouting::graph::PgrDirectedChPPGraph::BuildResultPath
void BuildResultPath()
Definition: pgr_chinesePostman.hpp:268
pgrouting::graph::PgrCostFlowGraph::GetMaxFlow
int64_t GetMaxFlow() const
Definition: pgr_minCostMaxFlow.cpp:128
pgr_flow_t.h
edge::source
int64 source
Definition: trsp.h:43
pgrouting::graph::PgrDirectedChPPGraph::pathStack
std::stack< int64_t > pathStack
Definition: pgr_chinesePostman.hpp:96
Identifiers::empty
bool empty() const
Definition: identifiers.hpp:79
pgrouting::graph::PgrDirectedChPPGraph::resultEdges
std::vector< pgr_edge_t > resultEdges
Definition: pgr_chinesePostman.hpp:88
pgr_assert.h
An assert functionality that uses C++ throw().
General_path_element_t::node
int64_t node
Definition: general_path_element_t.h:41
pgrouting::graph::PgrDirectedChPPGraph::EulerCircuitDFS
bool EulerCircuitDFS(int64_t p)
Definition: pgr_chinesePostman.hpp:313
edge_t::id
int64_t id
Definition: trsp_types.h:38
pgrouting::graph::PgrDirectedChPPGraph::resultGraph
std::vector< std::pair< int64_t, std::vector< size_t > > > resultGraph
vector of vertex -> vector of edges
Definition: pgr_chinesePostman.hpp:91
General_path_element_t
Definition: general_path_element_t.h:37
pgrouting::graph::PgrCostFlowGraph::GetFlowEdges
std::vector< pgr_flow_t > GetFlowEdges() const
Definition: pgr_minCostMaxFlow.cpp:141
pgrouting::graph::PgrDirectedChPPGraph::targets
std::set< int64_t > targets
Definition: pgr_chinesePostman.hpp:102
pgrouting::graph::PgrDirectedChPPGraph::startPoint
int64_t startPoint
Definition: pgr_chinesePostman.hpp:76
pgrouting::graph::PgrDirectedChPPGraph::~PgrDirectedChPPGraph
~PgrDirectedChPPGraph()
Definition: pgr_chinesePostman.hpp:105
pgrouting::graph::PgrDirectedChPPGraph::totalDeg
int64_t totalDeg
Definition: pgr_chinesePostman.hpp:73
pgrouting::graph::PgrDirectedChPPGraph::VToVecid
std::map< int64_t, size_t > VToVecid
Definition: pgr_chinesePostman.hpp:92
pgrouting::graph::PgrDirectedChPPGraph::superSource
int64_t superSource
Definition: pgr_chinesePostman.hpp:75
Identifiers::has
bool has(const T other) const
true ids() has element
Definition: identifiers.hpp:98
pgr_costFlow_t
Definition: pgr_costFlow_t.h:38
edge::id
int64 id
Definition: trsp.h:42
pgrouting::graph::PgrDirectedChPPGraph::totalCost
double totalCost
Definition: pgr_chinesePostman.hpp:74
general_path_element_t.h
pgrouting::graph::PgrDirectedChPPGraph::setPathEdges
void setPathEdges(graph::PgrCostFlowGraph &flowGraph)
Definition: pgr_chinesePostman.hpp:222
pgrouting::graph::PgrDirectedChPPGraph
Definition: pgr_chinesePostman.hpp:49
pgrouting::graph::PgrDirectedChPPGraph::edgeToId
std::map< std::pair< int64_t, int64_t >, size_t > edgeToId
Definition: pgr_chinesePostman.hpp:85
pgr_edge_t.h
General_path_element_t::cost
double cost
Definition: general_path_element_t.h:43
pgrouting
Book keeping class for swapping orders between vehicles.
Definition: pgr_alphaShape.cpp:56
pgrouting::graph::PgrDirectedChPPGraph::superTarget
int64_t superTarget
Definition: pgr_chinesePostman.hpp:75
General_path_element_t::agg_cost
double agg_cost
Definition: general_path_element_t.h:44
identifiers.hpp
Identifiers< int64_t >
edge_t::cost
double cost
Definition: trsp_types.h:41