Ticket #11804: edge_disjoint_ksp.3.hpp

File edge_disjoint_ksp.3.hpp, 7.3 KB (added by Irek Szcześniak <irek@…>, 7 years ago)
Line 
1//=======================================================================
2// Copyright 2015 by Ireneusz Szcześniak
3// Authors: Ireneusz Szcześniak
4//
5// Distributed under the Boost Software License, Version 1.0. (See
6// accompanying file LICENSE_1_0.txt or copy at
7// http://www.boost.org/LICENSE_1_0.txt)
8//=======================================================================
9
10//=======================================================================
11// Function edge_disjoint_ksp finds the k-shortest paths which are
12// edge-disjoint, i.e. the paths do not have common edges. The graph
13// can have parallel edges. The algorithm employs the Dijkstra
14// algorithm to find the shortest path. Next the edges of the found
15// path are disabled, and Dijkstra finds the second shortest path.
16// This process is repeated until k paths are found or there are no
17// more paths to be found.
18// =======================================================================
19
20#ifndef BOOST_GRAPH_EDGE_DISJOINT_KSP
21#define BOOST_GRAPH_EDGE_DISJOINT_KSP
22
23#include <list>
24#include <set>
25
26#include <boost/graph/dijkstra_shortest_paths.hpp>
27#include <boost/graph/filtered_graph.hpp>
28#include <boost/graph/visitors.hpp>
29#include <boost/optional.hpp>
30#include <boost/property_map/vector_property_map.hpp>
31#include <boost/utility/value_init.hpp>
32
33namespace boost {
34
35 //========================================================================
36 // Exclude edge filter
37 //========================================================================
38
39 template <typename Graph>
40 struct edksp_filter
41 {
42 typedef typename Graph::edge_descriptor edge_descriptor;
43 typedef typename std::set<edge_descriptor> edge_set;
44
45 // The filter must be default-constructible, so it is.
46 edksp_filter(): m_excluded() {};
47
48 edksp_filter(const edge_set *excluded): m_excluded(excluded) {};
49
50 inline bool operator()(const edge_descriptor &e) const
51 {
52 return m_excluded->count(e) == 0;
53 }
54
55 const edge_set *m_excluded;
56 };
57
58 //========================================================================
59 // Finish the search when a given node is examined, i.e. when the
60 // shortest path to that node is found.
61 // ========================================================================
62
63 // The type of the exception thrown by the cdc_visitor.
64 struct cdc_exception {};
65
66 template <class Graph>
67 struct cdc_visitor
68 {
69 typedef typename Graph::vertex_descriptor vertex_descriptor;
70 typedef on_examine_vertex event_filter;
71 cdc_visitor(vertex_descriptor t): m_t(t) {}
72 void operator()(vertex_descriptor v, const Graph& g) {
73 if (v == m_t)
74 throw cdc_exception();
75 }
76 vertex_descriptor m_t;
77 };
78
79 //========================================================================
80 // The custom Dijkstra call, which returns the optional path as a
81 // list along with the cost of the path. The search is stopped when
82 // the destination node is reached.
83 //=======================================================================+
84
85 template <typename Graph, typename Weight>
86 optional<std::pair<typename Weight::value_type,
87 std::list<typename Graph::edge_descriptor>>>
88 custom_dijkstra_call(const Graph &g,
89 typename Graph::vertex_descriptor s,
90 typename Graph::vertex_descriptor t,
91 Weight wm)
92 {
93 typedef typename Graph::vertex_descriptor vertex_descriptor;
94 typedef typename Graph::edge_descriptor edge_descriptor;
95 typedef typename std::list<typename Graph::edge_descriptor> path_type;
96 typedef typename Weight::value_type weight_type;
97 typedef typename std::pair<weight_type, path_type> kr_type;
98
99 vector_property_map<edge_descriptor> pred(num_vertices(g));
100 auto rep = record_edge_predecessors(pred, on_edge_relaxed());
101 auto qat = cdc_visitor<Graph>(t);
102 auto dv = make_dijkstra_visitor(std::make_pair(rep, qat));
103
104 try
105 {
106 dijkstra_shortest_paths(g, s, weight_map(wm).visitor(dv));
107 }
108 catch (cdc_exception) {}
109
110 optional<kr_type> result;
111
112 // Was the solution found?
113 if (pred[t] != edge_descriptor())
114 {
115 // The cost of the shortest path.
116 value_initialized<weight_type> cost;
117 // The path found.
118 path_type path;
119
120 // Trace the solution to the source.
121 vertex_descriptor c = t;
122 while (c != s)
123 {
124 const edge_descriptor &e = pred[c];
125 // Build the path.
126 path.push_front(e);
127 // Calculate the cost of the path.
128 cost += get(wm, e);
129 // Find the predecessing vertex.
130 c = source(e, g);
131 }
132
133 result = std::make_pair(cost, path);
134 }
135
136 return result;
137 }
138
139 //========================================================================
140 // The implementation of the k-shortest paths algorithm.
141 // ========================================================================
142
143 template <typename Graph, typename Weight>
144 std::list<std::pair<typename Weight::value_type,
145 std::list<typename Graph::edge_descriptor>>>
146 edge_disjoint_ksp(const Graph& g,
147 typename Graph::vertex_descriptor s,
148 typename Graph::vertex_descriptor t,
149 Weight wm,
150 optional<unsigned int> K)
151 {
152 typedef typename Graph::vertex_descriptor vertex_descriptor;
153 typedef typename Graph::edge_descriptor edge_descriptor;
154 typedef typename std::list<typename Graph::edge_descriptor> path_type;
155 typedef typename Weight::value_type weight_type;
156 typedef typename std::pair<weight_type, path_type> kr_type;
157
158 // The result.
159 std::list<std::pair<weight_type, path_type>> result;
160
161 // The set of excluded edges.
162 std::set<edge_descriptor> excluded;
163 // The filter for excluding edges.
164 edksp_filter<Graph> f(&excluded);
165 // The filtered graph type.
166 typedef filtered_graph<Graph, edksp_filter<Graph> > fg_type;
167 // The filtered graph.
168 fg_type fg(g, f);
169
170 // In each iteration, we try to find a shortest path.
171 do
172 {
173 // If required, stop at the K-th shortest path.
174 if (K && result.size() == K.get())
175 break;
176
177 // This is the optional k-th result.
178 optional<kr_type> okr = custom_dijkstra_call(fg, s, t, wm);
179
180 if (!okr)
181 break;
182
183 // This is the k-th result.
184 const kr_type &kr = okr.get();
185
186 // Exclude the edges from the k-th result found.
187 for(auto const &e: kr.second)
188 excluded.insert(e);
189
190 result.push_back(kr);
191
192 } while(true);
193
194 return result;
195 }
196
197 //========================================================================
198 // A helper function to figure out the default weight map of the graph.
199 // ========================================================================
200
201 template <typename Graph>
202 std::list<std::pair<typename property_map<Graph, edge_weight_t>::value_type,
203 std::list<typename Graph::edge_descriptor>>>
204 edge_disjoint_ksp(const Graph& g,
205 typename Graph::vertex_descriptor s,
206 typename Graph::vertex_descriptor t,
207 optional<unsigned int> K = optional<unsigned int>())
208 {
209 return edge_disjoint_ksp(g, s, t, get(edge_weight_t(), g), K);
210 }
211
212} // boost
213
214#endif /* BOOST_GRAPH_EDGE_DISJOINT_KSP */