metric_tsp_approx.cpp 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322
  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. #include <iostream>
  10. #include <vector>
  11. #include <fstream>
  12. #include <set>
  13. #include <ctime>
  14. #include <boost/assert.hpp>
  15. #include <boost/lexical_cast.hpp>
  16. #include <boost/random.hpp>
  17. #include <boost/timer.hpp>
  18. #include <boost/integer_traits.hpp>
  19. #include <boost/graph/adjacency_matrix.hpp>
  20. #include <boost/graph/adjacency_list.hpp>
  21. #include <boost/graph/simple_point.hpp>
  22. #include <boost/graph/metric_tsp_approx.hpp>
  23. #include <boost/graph/graphviz.hpp>
  24. // TODO: Integrate this into the test system a little better. We need to run
  25. // the test with some kind of input file.
  26. template<typename PointType>
  27. struct cmpPnt
  28. {
  29. bool operator()(const boost::simple_point<PointType>& l,
  30. const boost::simple_point<PointType>& r) const
  31. { return (l.x > r.x); }
  32. };
  33. //add edges to the graph (for each node connect it to all other nodes)
  34. template<typename VertexListGraph, typename PointContainer,
  35. typename WeightMap, typename VertexIndexMap>
  36. void connectAllEuclidean(VertexListGraph& g,
  37. const PointContainer& points,
  38. WeightMap wmap, // Property maps passed by value
  39. VertexIndexMap vmap, // Property maps passed by value
  40. int /*sz*/)
  41. {
  42. using namespace boost;
  43. using namespace std;
  44. typedef typename graph_traits<VertexListGraph>::edge_descriptor Edge;
  45. typedef typename graph_traits<VertexListGraph>::vertex_iterator VItr;
  46. Edge e;
  47. bool inserted;
  48. pair<VItr, VItr> verts(vertices(g));
  49. for (VItr src(verts.first); src != verts.second; src++)
  50. {
  51. for (VItr dest(src); dest != verts.second; dest++)
  52. {
  53. if (dest != src)
  54. {
  55. double weight(sqrt(pow(
  56. static_cast<double>(points[vmap[*src]].x -
  57. points[vmap[*dest]].x), 2.0) +
  58. pow(static_cast<double>(points[vmap[*dest]].y -
  59. points[vmap[*src]].y), 2.0)));
  60. boost::tie(e, inserted) = add_edge(*src, *dest, g);
  61. wmap[e] = weight;
  62. }
  63. }
  64. }
  65. }
  66. // Create a randomly generated point
  67. // scatter time execution
  68. void testScalability(unsigned numpts)
  69. {
  70. using namespace boost;
  71. using namespace std;
  72. typedef adjacency_matrix<undirectedS, no_property,
  73. property <edge_weight_t, double,
  74. property<edge_index_t, int> > > Graph;
  75. typedef graph_traits<Graph>::vertex_descriptor Vertex;
  76. typedef property_map<Graph, edge_weight_t>::type WeightMap;
  77. typedef set<simple_point<double>, cmpPnt<double> > PointSet;
  78. typedef vector< Vertex > Container;
  79. boost::mt19937 rng(time(0));
  80. uniform_real<> range(0.01, (numpts * 2));
  81. variate_generator<boost::mt19937&, uniform_real<> >
  82. pnt_gen(rng, range);
  83. PointSet points;
  84. simple_point<double> pnt;
  85. while (points.size() < numpts)
  86. {
  87. pnt.x = pnt_gen();
  88. pnt.y = pnt_gen();
  89. points.insert(pnt);
  90. }
  91. Graph g(numpts);
  92. WeightMap weight_map(get(edge_weight, g));
  93. vector<simple_point<double> > point_vec(points.begin(), points.end());
  94. connectAllEuclidean(g, point_vec, weight_map, get(vertex_index, g), numpts);
  95. Container c;
  96. timer t;
  97. double len = 0.0;
  98. // Run the TSP approx, creating the visitor on the fly.
  99. metric_tsp_approx(g, make_tsp_tour_len_visitor(g, back_inserter(c), len, weight_map));
  100. cout << "Number of points: " << num_vertices(g) << endl;
  101. cout << "Number of edges: " << num_edges(g) << endl;
  102. cout << "Length of tour: " << len << endl;
  103. cout << "Elapsed: " << t.elapsed() << endl;
  104. }
  105. template <typename PositionVec>
  106. void checkAdjList(PositionVec v)
  107. {
  108. using namespace std;
  109. using namespace boost;
  110. typedef adjacency_list<listS, listS, undirectedS> Graph;
  111. typedef graph_traits<Graph>::vertex_descriptor Vertex;
  112. typedef graph_traits <Graph>::edge_descriptor Edge;
  113. typedef vector<Vertex> Container;
  114. typedef map<Vertex, std::size_t> VertexIndexMap;
  115. typedef map<Edge, double> EdgeWeightMap;
  116. typedef associative_property_map<VertexIndexMap> VPropertyMap;
  117. typedef associative_property_map<EdgeWeightMap> EWeightPropertyMap;
  118. typedef graph_traits<Graph>::vertex_iterator VItr;
  119. Container c;
  120. EdgeWeightMap w_map;
  121. VertexIndexMap v_map;
  122. VPropertyMap v_pmap(v_map);
  123. EWeightPropertyMap w_pmap(w_map);
  124. Graph g(v.size());
  125. //create vertex index map
  126. VItr vi, ve;
  127. int idx(0);
  128. for (boost::tie(vi, ve) = vertices(g); vi != ve; ++vi)
  129. {
  130. Vertex v(*vi);
  131. v_pmap[v] = idx;
  132. idx++;
  133. }
  134. connectAllEuclidean(g, v, w_pmap,
  135. v_pmap, v.size());
  136. metric_tsp_approx_from_vertex(g,
  137. *vertices(g).first,
  138. w_pmap,
  139. v_pmap,
  140. tsp_tour_visitor<back_insert_iterator<Container > >
  141. (back_inserter(c)));
  142. cout << "adj_list" << endl;
  143. for (Container::iterator itr = c.begin(); itr != c.end(); ++itr) {
  144. cout << v_map[*itr] << " ";
  145. }
  146. cout << endl << endl;
  147. c.clear();
  148. }
  149. static void usage()
  150. {
  151. using namespace std;
  152. cerr << "To run this program properly please place a "
  153. << "file called graph.txt"
  154. << endl << "into the current working directory." << endl
  155. << "Each line of this file should be a coordinate specifying the"
  156. << endl << "location of a vertex" << endl
  157. << "For example: " << endl << "1,2" << endl << "20,4" << endl
  158. << "15,7" << endl << endl;
  159. }
  160. int main(int argc, char* argv[])
  161. {
  162. using namespace boost;
  163. using namespace std;
  164. typedef vector<simple_point<double> > PositionVec;
  165. typedef adjacency_matrix<undirectedS, no_property,
  166. property <edge_weight_t, double> > Graph;
  167. typedef graph_traits<Graph>::vertex_descriptor Vertex;
  168. typedef vector<Vertex> Container;
  169. typedef property_map<Graph, edge_weight_t>::type WeightMap;
  170. typedef property_map<Graph, vertex_index_t>::type VertexMap;
  171. // Make sure that the the we can parse the given file.
  172. if(argc < 2) {
  173. usage();
  174. // return -1;
  175. return 0;
  176. }
  177. // Open the graph file, failing if one isn't given on the command line.
  178. ifstream fin(argv[1]);
  179. if (!fin)
  180. {
  181. usage();
  182. // return -1;
  183. return 0;
  184. }
  185. string line;
  186. PositionVec position_vec;
  187. int n(0);
  188. while (getline(fin, line))
  189. {
  190. simple_point<double> vertex;
  191. size_t idx(line.find(","));
  192. string xStr(line.substr(0, idx));
  193. string yStr(line.substr(idx + 1, line.size() - idx));
  194. vertex.x = lexical_cast<double>(xStr);
  195. vertex.y = lexical_cast<double>(yStr);
  196. position_vec.push_back(vertex);
  197. n++;
  198. }
  199. fin.close();
  200. Container c;
  201. Graph g(position_vec.size());
  202. WeightMap weight_map(get(edge_weight, g));
  203. VertexMap v_map = get(vertex_index, g);
  204. connectAllEuclidean(g, position_vec, weight_map, v_map, n);
  205. metric_tsp_approx_tour(g, back_inserter(c));
  206. for (vector<Vertex>::iterator itr = c.begin(); itr != c.end(); ++itr)
  207. {
  208. cout << *itr << " ";
  209. }
  210. cout << endl << endl;
  211. c.clear();
  212. checkAdjList(position_vec);
  213. metric_tsp_approx_from_vertex(g, *vertices(g).first,
  214. get(edge_weight, g), get(vertex_index, g),
  215. tsp_tour_visitor<back_insert_iterator<vector<Vertex> > >
  216. (back_inserter(c)));
  217. for (vector<Vertex>::iterator itr = c.begin(); itr != c.end(); ++itr)
  218. {
  219. cout << *itr << " ";
  220. }
  221. cout << endl << endl;
  222. c.clear();
  223. double len(0.0);
  224. try {
  225. metric_tsp_approx(g, make_tsp_tour_len_visitor(g, back_inserter(c), len, weight_map));
  226. }
  227. catch (const bad_graph& e) {
  228. cerr << "bad_graph: " << e.what() << endl;
  229. return -1;
  230. }
  231. cout << "Number of points: " << num_vertices(g) << endl;
  232. cout << "Number of edges: " << num_edges(g) << endl;
  233. cout << "Length of Tour: " << len << endl;
  234. int cnt(0);
  235. pair<Vertex,Vertex> triangleEdge;
  236. for (vector<Vertex>::iterator itr = c.begin(); itr != c.end();
  237. ++itr, ++cnt)
  238. {
  239. cout << *itr << " ";
  240. if (cnt == 2)
  241. {
  242. triangleEdge.first = *itr;
  243. }
  244. if (cnt == 3)
  245. {
  246. triangleEdge.second = *itr;
  247. }
  248. }
  249. cout << endl << endl;
  250. c.clear();
  251. testScalability(1000);
  252. // if the graph is not fully connected then some of the
  253. // assumed triangle-inequality edges may not exist
  254. remove_edge(edge(triangleEdge.first, triangleEdge.second, g).first, g);
  255. // Make sure that we can actually trap incomplete graphs.
  256. bool caught = false;
  257. try {
  258. double len = 0.0;
  259. metric_tsp_approx(g, make_tsp_tour_len_visitor(g, back_inserter(c), len, weight_map));
  260. }
  261. catch (const bad_graph& e) { caught = true; }
  262. BOOST_ASSERT(caught);
  263. return 0;
  264. }