Ticket #11838: yen_ksp.hpp

File yen_ksp.hpp, 5.7 KB (added by Irek Szcześniak <irek@…>, 7 years ago)

the implementation

Line 
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#include "exclude_filter.hpp"
36
37namespace boost {
38
39 template <typename Graph, typename WeightMap, typename IndexMap>
40 std::list<std::pair<typename WeightMap::value_type,
41 std::list<typename Graph::edge_descriptor>>>
42 yen_ksp(const Graph& g,
43 typename Graph::vertex_descriptor s,
44 typename Graph::vertex_descriptor t,
45 WeightMap wm, IndexMap im, optional<unsigned> K)
46 {
47 typedef typename Graph::vertex_descriptor vertex_descriptor;
48 typedef typename Graph::edge_descriptor edge_descriptor;
49 typedef typename WeightMap::value_type weight_type;
50 typedef exclude_filter<vertex_descriptor> evf_type;
51 typedef exclude_filter<edge_descriptor> eef_type;
52 typedef std::list<edge_descriptor> path_type;
53 typedef std::pair<weight_type, path_type> kr_type;
54
55 // The results.
56 std::list<kr_type> A;
57 // The tentative results.
58 std::multimap<weight_type, path_type> B;
59
60 // The set of excluded edges.
61 std::set<edge_descriptor> exe;
62 // The set of excluded vertexes.
63 std::set<vertex_descriptor> exv;
64
65 // The filter which excludes edges.
66 eef_type ef(&exe);
67 // The filter which excludes vertexes.
68 evf_type vf(&exv);
69
70 // The filtered graph type.
71 typedef boost::filtered_graph<Graph, eef_type, evf_type> fg_type;
72
73 // The filtered graph.
74 fg_type fg(g, ef, vf);
75
76 optional<kr_type> okr = custom_dijkstra_call(g, s, t, wm, im);
77
78 if (okr)
79 {
80 A.push_back(okr.get());
81
82 for (int k = 1; !K || k < K.get(); ++k)
83 {
84 // The previous shortest result.
85 const kr_type &psr = A.back();
86 const path_type &psp = psr.second;
87
88 // Iterate over the edges of the previous shortest path.
89 for(auto i = psp.begin(); i != psp.end(); ++i)
90 {
91 // The spur vertex.
92 vertex_descriptor sv = source(*i, g);
93 // The root path.
94 path_type rp = path_type(psp.begin(), i);
95
96 // Iterate over the previous shortest paths.
97 for(const auto &kr: A)
98 {
99 const path_type &kp = kr.second;
100 typename path_type::const_iterator i1, i2;
101
102 // Iterate as long as possible, and as long as
103 // paths are equal.
104 for(tie(i1, i2) = std::make_pair(kp.begin(), rp.begin());
105 i1 != kp.end() && i2 != rp.end() && *i1 == *i2;
106 ++i1, ++i2);
107
108 // Make sure we didn't reach the end of kp. If we
109 // did, there is no next edge in kp, which we
110 // could exclude. Also, make sure we reached the
111 // end of rp, i.e., the kp begins with rp.
112 if (i1 != kp.end() && i2 == rp.end())
113 exe.insert(*i1);
114 }
115
116 // Remove the vertexes that belong to the root path,
117 // except the last vertex, i.e., the spur node.
118 for (const auto &e: rp)
119 exv.insert(source(e, g));
120
121 // Optional spur result.
122 optional<kr_type> osr = custom_dijkstra_call(fg, sv, t, wm, im);
123
124 if (osr)
125 {
126 // The tentative result.
127 kr_type tr = osr.get();
128 for(const auto &e: boost::adaptors::reverse(rp))
129 {
130 tr.second.push_front(e);
131 tr.first += get(wm, e);
132 }
133 B.insert(tr);
134 }
135
136 // Clear the excluded edges and vertexes.
137 exe.clear();
138 exv.clear();
139 }
140
141 // Stop searching when there are no tentative paths.
142 if (B.empty())
143 break;
144
145 // Take the shortest tentative path and make it the next
146 // shortest path.
147 A.push_back(*B.begin());
148 B.erase(B.begin());
149 }
150 }
151
152 return A;
153 }
154
155 template <typename Graph>
156 std::list<std::pair<typename property_map<Graph, edge_weight_t>::value_type,
157 std::list<typename Graph::edge_descriptor>>>
158 yen_ksp(Graph& g,
159 typename Graph::vertex_descriptor s,
160 typename Graph::vertex_descriptor t,
161 optional<unsigned> K = optional<unsigned>())
162 {
163 return yen_ksp(g, s, t, get(edge_weight_t(), g),
164 get(vertex_index_t(), g), K);
165 }
166
167} // boost
168
169#endif /* BOOST_GRAPH_YEN_KSP */