| 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 |
|
|---|
| 33 | namespace 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 */
|
|---|