metric_tsp_approx.hpp 11 KB

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