annotate DEPENDENCIES/generic/include/boost/graph/metric_tsp_approx.hpp @ 133:4acb5d8d80b6 tip

Don't fail environmental check if README.md exists (but .txt and no-suffix don't)
author Chris Cannam
date Tue, 30 Jul 2019 12:25:44 +0100
parents 2665513ce2d3
children
rev   line source
Chris@16 1
Chris@16 2 //=======================================================================
Chris@16 3 // Copyright 2008
Chris@16 4 // Author: Matyas W Egyhazy
Chris@16 5 //
Chris@16 6 // Distributed under the Boost Software License, Version 1.0. (See
Chris@16 7 // accompanying file LICENSE_1_0.txt or copy at
Chris@16 8 // http://www.boost.org/LICENSE_1_0.txt)
Chris@16 9 //=======================================================================
Chris@16 10
Chris@16 11 #ifndef BOOST_GRAPH_METRIC_TSP_APPROX_HPP
Chris@16 12 #define BOOST_GRAPH_METRIC_TSP_APPROX_HPP
Chris@16 13
Chris@16 14 // metric_tsp_approx
Chris@16 15 // Generates an approximate tour solution for the traveling salesperson
Chris@16 16 // problem in polynomial time. The current algorithm guarantees a tour with a
Chris@16 17 // length at most as long as 2x optimal solution. The graph should have
Chris@16 18 // 'natural' (metric) weights such that the triangle inequality is maintained.
Chris@16 19 // Graphs must be fully interconnected.
Chris@16 20
Chris@16 21 // TODO:
Chris@16 22 // There are a couple of improvements that could be made.
Chris@16 23 // 1) Change implementation to lower uppper bound Christofides heuristic
Chris@16 24 // 2) Implement a less restrictive TSP heuristic (one that does not rely on
Chris@16 25 // triangle inequality).
Chris@16 26 // 3) Determine if the algorithm can be implemented without creating a new
Chris@16 27 // graph.
Chris@16 28
Chris@16 29 #include <vector>
Chris@16 30
Chris@16 31 #include <boost/shared_ptr.hpp>
Chris@16 32 #include <boost/concept_check.hpp>
Chris@16 33 #include <boost/graph/graph_traits.hpp>
Chris@16 34 #include <boost/graph/graph_as_tree.hpp>
Chris@16 35 #include <boost/graph/adjacency_list.hpp>
Chris@16 36 #include <boost/graph/prim_minimum_spanning_tree.hpp>
Chris@16 37 #include <boost/graph/lookup_edge.hpp>
Chris@16 38 #include <boost/throw_exception.hpp>
Chris@16 39
Chris@16 40 namespace boost
Chris@16 41 {
Chris@16 42 // Define a concept for the concept-checking library.
Chris@16 43 template <typename Visitor, typename Graph>
Chris@16 44 struct TSPVertexVisitorConcept
Chris@16 45 {
Chris@16 46 private:
Chris@16 47 Visitor vis_;
Chris@16 48 public:
Chris@16 49 typedef typename graph_traits<Graph>::vertex_descriptor Vertex;
Chris@16 50
Chris@16 51 BOOST_CONCEPT_USAGE(TSPVertexVisitorConcept)
Chris@16 52 {
Chris@16 53 Visitor vis(vis_); // require copy construction
Chris@16 54 Graph g(1);
Chris@16 55 Vertex v(*vertices(g).first);
Chris@16 56 vis_.visit_vertex(v, g); // require visit_vertex
Chris@16 57 }
Chris@16 58 };
Chris@16 59
Chris@16 60 // Tree visitor that keeps track of a preorder traversal of a tree
Chris@16 61 // TODO: Consider migrating this to the graph_as_tree header.
Chris@16 62 // TODO: Parameterize the underlying stores o it doesn't have to be a vector.
Chris@16 63 template<typename Node, typename Tree> class PreorderTraverser
Chris@16 64 {
Chris@16 65 private:
Chris@16 66 std::vector<Node>& path_;
Chris@16 67 public:
Chris@16 68 typedef typename std::vector<Node>::const_iterator const_iterator;
Chris@16 69
Chris@16 70 PreorderTraverser(std::vector<Node>& p) : path_(p) {}
Chris@16 71
Chris@16 72 void preorder(Node n, const Tree&)
Chris@16 73 { path_.push_back(n); }
Chris@16 74
Chris@16 75 void inorder(Node, const Tree&) const {}
Chris@16 76 void postorder(Node, const Tree&) const {}
Chris@16 77
Chris@16 78 const_iterator begin() const { return path_.begin(); }
Chris@16 79 const_iterator end() const { return path_.end(); }
Chris@16 80 };
Chris@16 81
Chris@16 82 // Forward declarations
Chris@16 83 template <typename> class tsp_tour_visitor;
Chris@16 84 template <typename, typename, typename, typename> class tsp_tour_len_visitor;
Chris@16 85
Chris@16 86 template<typename VertexListGraph, typename OutputIterator>
Chris@16 87 void metric_tsp_approx_tour(VertexListGraph& g, OutputIterator o)
Chris@16 88 {
Chris@16 89 metric_tsp_approx_from_vertex(g, *vertices(g).first,
Chris@16 90 get(edge_weight, g), get(vertex_index, g),
Chris@16 91 tsp_tour_visitor<OutputIterator>(o));
Chris@16 92 }
Chris@16 93
Chris@16 94 template<typename VertexListGraph, typename WeightMap, typename OutputIterator>
Chris@16 95 void metric_tsp_approx_tour(VertexListGraph& g, WeightMap w, OutputIterator o)
Chris@16 96 {
Chris@16 97 metric_tsp_approx_from_vertex(g, *vertices(g).first,
Chris@16 98 w, tsp_tour_visitor<OutputIterator>(o));
Chris@16 99 }
Chris@16 100
Chris@16 101 template<typename VertexListGraph, typename OutputIterator>
Chris@16 102 void metric_tsp_approx_tour_from_vertex(VertexListGraph& g,
Chris@16 103 typename graph_traits<VertexListGraph>::vertex_descriptor start,
Chris@16 104 OutputIterator o)
Chris@16 105 {
Chris@16 106 metric_tsp_approx_from_vertex(g, start, get(edge_weight, g),
Chris@16 107 get(vertex_index, g), tsp_tour_visitor<OutputIterator>(o));
Chris@16 108 }
Chris@16 109
Chris@16 110 template<typename VertexListGraph, typename WeightMap,
Chris@16 111 typename OutputIterator>
Chris@16 112 void metric_tsp_approx_tour_from_vertex(VertexListGraph& g,
Chris@16 113 typename graph_traits<VertexListGraph>::vertex_descriptor start,
Chris@16 114 WeightMap w, OutputIterator o)
Chris@16 115 {
Chris@16 116 metric_tsp_approx_from_vertex(g, start, w, get(vertex_index, g),
Chris@16 117 tsp_tour_visitor<OutputIterator>(o));
Chris@16 118 }
Chris@16 119
Chris@16 120 template<typename VertexListGraph, typename TSPVertexVisitor>
Chris@16 121 void metric_tsp_approx(VertexListGraph& g, TSPVertexVisitor vis)
Chris@16 122 {
Chris@16 123 metric_tsp_approx_from_vertex(g, *vertices(g).first,
Chris@16 124 get(edge_weight, g), get(vertex_index, g), vis);
Chris@16 125 }
Chris@16 126
Chris@16 127 template<typename VertexListGraph, typename Weightmap,
Chris@16 128 typename VertexIndexMap, typename TSPVertexVisitor>
Chris@16 129 void metric_tsp_approx(VertexListGraph& g, Weightmap w,
Chris@16 130 TSPVertexVisitor vis)
Chris@16 131 {
Chris@16 132 metric_tsp_approx_from_vertex(g, *vertices(g).first, w,
Chris@16 133 get(vertex_index, g), vis);
Chris@16 134 }
Chris@16 135
Chris@16 136 template<typename VertexListGraph, typename WeightMap,
Chris@16 137 typename VertexIndexMap, typename TSPVertexVisitor>
Chris@16 138 void metric_tsp_approx(VertexListGraph& g, WeightMap w, VertexIndexMap id,
Chris@16 139 TSPVertexVisitor vis)
Chris@16 140 {
Chris@16 141 metric_tsp_approx_from_vertex(g, *vertices(g).first, w, id, vis);
Chris@16 142 }
Chris@16 143
Chris@16 144 template<typename VertexListGraph, typename WeightMap,
Chris@16 145 typename TSPVertexVisitor>
Chris@16 146 void metric_tsp_approx_from_vertex(VertexListGraph& g,
Chris@16 147 typename graph_traits<VertexListGraph>::vertex_descriptor start,
Chris@16 148 WeightMap w, TSPVertexVisitor vis)
Chris@16 149 {
Chris@16 150 metric_tsp_approx_from_vertex(g, start, w, get(vertex_index, g), vis);
Chris@16 151 }
Chris@16 152
Chris@16 153 template <
Chris@16 154 typename VertexListGraph,
Chris@16 155 typename WeightMap,
Chris@16 156 typename VertexIndexMap,
Chris@16 157 typename TSPVertexVisitor>
Chris@16 158 void metric_tsp_approx_from_vertex(const VertexListGraph& g,
Chris@16 159 typename graph_traits<VertexListGraph>::vertex_descriptor start,
Chris@16 160 WeightMap weightmap,
Chris@16 161 VertexIndexMap indexmap,
Chris@16 162 TSPVertexVisitor vis)
Chris@16 163 {
Chris@16 164 using namespace boost;
Chris@16 165 using namespace std;
Chris@16 166
Chris@16 167 BOOST_CONCEPT_ASSERT((VertexListGraphConcept<VertexListGraph>));
Chris@16 168 BOOST_CONCEPT_ASSERT((TSPVertexVisitorConcept<TSPVertexVisitor, VertexListGraph>));
Chris@16 169
Chris@16 170 // Types related to the input graph (GVertex is a template parameter).
Chris@16 171 typedef typename graph_traits<VertexListGraph>::vertex_descriptor GVertex;
Chris@16 172 typedef typename graph_traits<VertexListGraph>::vertex_iterator GVItr;
Chris@16 173
Chris@16 174 // We build a custom graph in this algorithm.
Chris@16 175 typedef adjacency_list <vecS, vecS, directedS, no_property, no_property > MSTImpl;
Chris@16 176 typedef graph_traits<MSTImpl>::vertex_descriptor Vertex;
Chris@16 177 typedef graph_traits<MSTImpl>::vertex_iterator VItr;
Chris@16 178
Chris@16 179 // And then re-cast it as a tree.
Chris@16 180 typedef iterator_property_map<vector<Vertex>::iterator, property_map<MSTImpl, vertex_index_t>::type> ParentMap;
Chris@16 181 typedef graph_as_tree<MSTImpl, ParentMap> Tree;
Chris@16 182 typedef tree_traits<Tree>::node_descriptor Node;
Chris@16 183
Chris@16 184 // A predecessor map.
Chris@16 185 typedef vector<GVertex> PredMap;
Chris@16 186 typedef iterator_property_map<typename PredMap::iterator, VertexIndexMap> PredPMap;
Chris@16 187
Chris@16 188 PredMap preds(num_vertices(g));
Chris@16 189 PredPMap pred_pmap(preds.begin(), indexmap);
Chris@16 190
Chris@16 191 // Compute a spanning tree over the in put g.
Chris@16 192 prim_minimum_spanning_tree(g, pred_pmap,
Chris@16 193 root_vertex(start)
Chris@16 194 .vertex_index_map(indexmap)
Chris@16 195 .weight_map(weightmap));
Chris@16 196
Chris@16 197 // Build a MST using the predecessor map from prim mst
Chris@16 198 MSTImpl mst(num_vertices(g));
Chris@16 199 std::size_t cnt = 0;
Chris@16 200 pair<VItr, VItr> mst_verts(vertices(mst));
Chris@16 201 for(typename PredMap::iterator vi(preds.begin()); vi != preds.end(); ++vi, ++cnt)
Chris@16 202 {
Chris@16 203 if(indexmap[*vi] != cnt) {
Chris@16 204 add_edge(*next(mst_verts.first, indexmap[*vi]),
Chris@16 205 *next(mst_verts.first, cnt), mst);
Chris@16 206 }
Chris@16 207 }
Chris@16 208
Chris@16 209 // Build a tree abstraction over the MST.
Chris@16 210 vector<Vertex> parent(num_vertices(mst));
Chris@16 211 Tree t(mst, *vertices(mst).first,
Chris@16 212 make_iterator_property_map(parent.begin(),
Chris@16 213 get(vertex_index, mst)));
Chris@16 214
Chris@16 215 // Create tour using a preorder traversal of the mst
Chris@16 216 vector<Node> tour;
Chris@16 217 PreorderTraverser<Node, Tree> tvis(tour);
Chris@16 218 traverse_tree(indexmap[start], t, tvis);
Chris@16 219
Chris@16 220 pair<GVItr, GVItr> g_verts(vertices(g));
Chris@16 221 for(PreorderTraverser<Node, Tree>::const_iterator curr(tvis.begin());
Chris@16 222 curr != tvis.end(); ++curr)
Chris@16 223 {
Chris@16 224 // TODO: This is will be O(n^2) if vertex storage of g != vecS.
Chris@16 225 GVertex v = *next(g_verts.first, get(vertex_index, mst)[*curr]);
Chris@16 226 vis.visit_vertex(v, g);
Chris@16 227 }
Chris@16 228
Chris@16 229 // Connect back to the start of the tour
Chris@16 230 vis.visit_vertex(start, g);
Chris@16 231 }
Chris@16 232
Chris@16 233 // Default tsp tour visitor that puts the tour in an OutputIterator
Chris@16 234 template <typename OutItr>
Chris@16 235 class tsp_tour_visitor
Chris@16 236 {
Chris@16 237 OutItr itr_;
Chris@16 238 public:
Chris@16 239 tsp_tour_visitor(OutItr itr)
Chris@16 240 : itr_(itr)
Chris@16 241 { }
Chris@16 242
Chris@16 243 template <typename Vertex, typename Graph>
Chris@16 244 void visit_vertex(Vertex v, const Graph&)
Chris@16 245 {
Chris@16 246 BOOST_CONCEPT_ASSERT((OutputIterator<OutItr, Vertex>));
Chris@16 247 *itr_++ = v;
Chris@16 248 }
Chris@16 249
Chris@16 250 };
Chris@16 251
Chris@16 252 // Tsp tour visitor that adds the total tour length.
Chris@16 253 template<typename Graph, typename WeightMap, typename OutIter, typename Length>
Chris@16 254 class tsp_tour_len_visitor
Chris@16 255 {
Chris@16 256 typedef typename graph_traits<Graph>::vertex_descriptor Vertex;
Chris@16 257 BOOST_CONCEPT_ASSERT((OutputIterator<OutIter, Vertex>));
Chris@16 258
Chris@16 259 OutIter iter_;
Chris@16 260 Length& tourlen_;
Chris@16 261 WeightMap& wmap_;
Chris@16 262 Vertex previous_;
Chris@16 263
Chris@16 264 // Helper function for getting the null vertex.
Chris@16 265 Vertex null()
Chris@16 266 { return graph_traits<Graph>::null_vertex(); }
Chris@16 267
Chris@16 268 public:
Chris@16 269 tsp_tour_len_visitor(Graph const&, OutIter iter, Length& l, WeightMap map)
Chris@16 270 : iter_(iter), tourlen_(l), wmap_(map), previous_(null())
Chris@16 271 { }
Chris@16 272
Chris@16 273 void visit_vertex(Vertex v, const Graph& g)
Chris@16 274 {
Chris@16 275 typedef typename graph_traits<Graph>::edge_descriptor Edge;
Chris@16 276
Chris@16 277 // If it is not the start, then there is a
Chris@16 278 // previous vertex
Chris@16 279 if(previous_ != null())
Chris@16 280 {
Chris@16 281 // NOTE: For non-adjacency matrix graphs g, this bit of code
Chris@16 282 // will be linear in the degree of previous_ or v. A better
Chris@16 283 // solution would be to visit edges of the graph, but that
Chris@16 284 // would require revisiting the core algorithm.
Chris@16 285 Edge e;
Chris@16 286 bool found;
Chris@16 287 boost::tie(e, found) = lookup_edge(previous_, v, g);
Chris@16 288 if(!found) {
Chris@16 289 BOOST_THROW_EXCEPTION(not_complete());
Chris@16 290 }
Chris@16 291
Chris@16 292 tourlen_ += wmap_[e];
Chris@16 293 }
Chris@16 294
Chris@16 295 previous_ = v;
Chris@16 296 *iter_++ = v;
Chris@16 297 }
Chris@16 298 };
Chris@16 299
Chris@16 300 // Object generator(s)
Chris@16 301 template <typename OutIter>
Chris@16 302 inline tsp_tour_visitor<OutIter>
Chris@16 303 make_tsp_tour_visitor(OutIter iter)
Chris@16 304 { return tsp_tour_visitor<OutIter>(iter); }
Chris@16 305
Chris@16 306 template <typename Graph, typename WeightMap, typename OutIter, typename Length>
Chris@16 307 inline tsp_tour_len_visitor<Graph, WeightMap, OutIter, Length>
Chris@16 308 make_tsp_tour_len_visitor(Graph const& g, OutIter iter, Length& l, WeightMap map)
Chris@16 309 { return tsp_tour_len_visitor<Graph, WeightMap, OutIter, Length>(g, iter, l, map); }
Chris@16 310
Chris@16 311 } //boost
Chris@16 312
Chris@16 313 #endif // BOOST_GRAPH_METRIC_TSP_APPROX_HPP