1 | //=======================================================================
|
---|
2 | // Copyright 2015 by Ireneusz Szcześniak
|
---|
3 | // Authors: Ireneusz Szcześniak <www.irkos.org>
|
---|
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 | // This is the implementation of the Yen algorithm:
|
---|
12 | //
|
---|
13 | // Jin Y. Yen, Finding the k shortest loopless paths in a network,
|
---|
14 | // Management Science, vol. 17, no. 11, July 1971, pages 712-716
|
---|
15 | //
|
---|
16 | // But actually, I found the following explanation better:
|
---|
17 | //
|
---|
18 | // https://en.wikipedia.org/wiki/Yen%27s_algorithm
|
---|
19 | //=======================================================================
|
---|
20 |
|
---|
21 | #ifndef BOOST_GRAPH_YEN_KSP
|
---|
22 | #define BOOST_GRAPH_YEN_KSP
|
---|
23 |
|
---|
24 | #include <list>
|
---|
25 | #include <set>
|
---|
26 | #include <map>
|
---|
27 |
|
---|
28 | #include <boost/graph/dijkstra_shortest_paths.hpp>
|
---|
29 | #include <boost/graph/filtered_graph.hpp>
|
---|
30 | #include <boost/optional.hpp>
|
---|
31 | #include <boost/range/adaptor/reversed.hpp>
|
---|
32 | #include <boost/utility/value_init.hpp>
|
---|
33 |
|
---|
34 | #include "custom_dijkstra_call.hpp"
|
---|
35 |
|
---|
36 | namespace boost {
|
---|
37 |
|
---|
38 | template <typename Graph, typename WeightMap, typename IndexMap>
|
---|
39 | std::list<std::pair<typename WeightMap::value_type,
|
---|
40 | std::list<typename Graph::edge_descriptor>>>
|
---|
41 | yen_ksp(const Graph& g,
|
---|
42 | typename Graph::vertex_descriptor s,
|
---|
43 | typename Graph::vertex_descriptor t,
|
---|
44 | WeightMap wm, IndexMap im, optional<unsigned> K)
|
---|
45 | {
|
---|
46 | typedef typename Graph::vertex_descriptor vertex_descriptor;
|
---|
47 | typedef typename Graph::edge_descriptor edge_descriptor;
|
---|
48 | typedef typename WeightMap::value_type weight_type;
|
---|
49 | typedef std::set<edge_descriptor> es_type;
|
---|
50 | typedef std::set<vertex_descriptor> vs_type;
|
---|
51 | typedef filtered_graph<Graph, is_not_in_subset<es_type>,
|
---|
52 | is_not_in_subset<vs_type>> fg_type;
|
---|
53 | typedef std::list<edge_descriptor> path_type;
|
---|
54 | typedef std::pair<weight_type, path_type> kr_type;
|
---|
55 |
|
---|
56 | // The results.
|
---|
57 | std::list<kr_type> A;
|
---|
58 | // The tentative results.
|
---|
59 | std::multimap<weight_type, path_type> B;
|
---|
60 |
|
---|
61 | // The set of excluded edges.
|
---|
62 | es_type exe;
|
---|
63 | // The set of excluded vertexes.
|
---|
64 | vs_type exv;
|
---|
65 |
|
---|
66 | // The edge predicate.
|
---|
67 | is_not_in_subset<es_type> ep(exe);
|
---|
68 | // The vertex predicate.
|
---|
69 | is_not_in_subset<vs_type> vp(exv);
|
---|
70 |
|
---|
71 | // The filtered graph.
|
---|
72 | fg_type fg(g, ep, vp);
|
---|
73 |
|
---|
74 | optional<kr_type> okr = custom_dijkstra_call(g, s, t, wm, im);
|
---|
75 |
|
---|
76 | if (okr)
|
---|
77 | {
|
---|
78 | A.push_back(okr.get());
|
---|
79 |
|
---|
80 | for (int k = 1; !K || k < K.get(); ++k)
|
---|
81 | {
|
---|
82 | // The previous shortest result.
|
---|
83 | const kr_type &psr = A.back();
|
---|
84 | const path_type &psp = psr.second;
|
---|
85 |
|
---|
86 | // Iterate over the edges of the previous shortest path.
|
---|
87 | for(auto i = psp.begin(); i != psp.end(); ++i)
|
---|
88 | {
|
---|
89 | // The spur vertex.
|
---|
90 | vertex_descriptor sv = source(*i, g);
|
---|
91 | // The root path.
|
---|
92 | path_type rp = path_type(psp.begin(), i);
|
---|
93 |
|
---|
94 | // Iterate over the previous shortest paths.
|
---|
95 | for(const auto &kr: A)
|
---|
96 | {
|
---|
97 | const path_type &kp = kr.second;
|
---|
98 | typename path_type::const_iterator i1, i2;
|
---|
99 |
|
---|
100 | // Iterate as long as possible, and as long as
|
---|
101 | // paths are equal.
|
---|
102 | for(tie(i1, i2) = std::make_pair(kp.begin(), rp.begin());
|
---|
103 | i1 != kp.end() && i2 != rp.end() && *i1 == *i2;
|
---|
104 | ++i1, ++i2);
|
---|
105 |
|
---|
106 | // Make sure we didn't reach the end of kp. If we
|
---|
107 | // did, there is no next edge in kp, which we
|
---|
108 | // could exclude. Also, make sure we reached the
|
---|
109 | // end of rp, i.e., the kp begins with rp.
|
---|
110 | if (i1 != kp.end() && i2 == rp.end())
|
---|
111 | exe.insert(*i1);
|
---|
112 | }
|
---|
113 |
|
---|
114 | // Remove the vertexes that belong to the root path,
|
---|
115 | // except the last vertex, i.e., the spur node.
|
---|
116 | for (const auto &e: rp)
|
---|
117 | exv.insert(source(e, g));
|
---|
118 |
|
---|
119 | // Optional spur result.
|
---|
120 | optional<kr_type> osr = custom_dijkstra_call(fg, sv, t, wm, im);
|
---|
121 |
|
---|
122 | if (osr)
|
---|
123 | {
|
---|
124 | // The tentative result.
|
---|
125 | kr_type tr = osr.get();
|
---|
126 | for(const auto &e: boost::adaptors::reverse(rp))
|
---|
127 | {
|
---|
128 | tr.second.push_front(e);
|
---|
129 | tr.first += get(wm, e);
|
---|
130 | }
|
---|
131 | B.insert(tr);
|
---|
132 | }
|
---|
133 |
|
---|
134 | // Clear the excluded edges and vertexes.
|
---|
135 | exe.clear();
|
---|
136 | exv.clear();
|
---|
137 | }
|
---|
138 |
|
---|
139 | // Stop searching when there are no tentative paths.
|
---|
140 | if (B.empty())
|
---|
141 | break;
|
---|
142 |
|
---|
143 | // Take the shortest tentative path and make it the next
|
---|
144 | // shortest path.
|
---|
145 | A.push_back(*B.begin());
|
---|
146 | B.erase(B.begin());
|
---|
147 | }
|
---|
148 | }
|
---|
149 |
|
---|
150 | return A;
|
---|
151 | }
|
---|
152 |
|
---|
153 | template <typename Graph>
|
---|
154 | std::list<std::pair<typename property_map<Graph, edge_weight_t>::value_type,
|
---|
155 | std::list<typename Graph::edge_descriptor>>>
|
---|
156 | yen_ksp(Graph& g,
|
---|
157 | typename Graph::vertex_descriptor s,
|
---|
158 | typename Graph::vertex_descriptor t,
|
---|
159 | optional<unsigned> K = optional<unsigned>())
|
---|
160 | {
|
---|
161 | return yen_ksp(g, s, t, get(edge_weight_t(), g),
|
---|
162 | get(vertex_index_t(), g), K);
|
---|
163 | }
|
---|
164 |
|
---|
165 | } // boost
|
---|
166 |
|
---|
167 | #endif /* BOOST_GRAPH_YEN_KSP */
|
---|