metis.hpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  1. // Copyright 2005 The Trustees of Indiana University.
  2. // Use, modification and distribution is subject to the Boost Software
  3. // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
  4. // http://www.boost.org/LICENSE_1_0.txt)
  5. // Authors: Douglas Gregor
  6. // Andrew Lumsdaine
  7. #ifndef BOOST_GRAPH_METIS_HPP
  8. #define BOOST_GRAPH_METIS_HPP
  9. #ifdef BOOST_GRAPH_METIS_NO_INLINE
  10. #define BOOST_GRAPH_METIS_INLINE_KEYWORD
  11. #else
  12. #define BOOST_GRAPH_METIS_INLINE_KEYWORD inline
  13. #endif
  14. #include <string>
  15. #include <iostream>
  16. #include <iterator>
  17. #include <utility>
  18. #include <sstream>
  19. #include <exception>
  20. #include <vector>
  21. #include <algorithm>
  22. namespace boost
  23. {
  24. namespace graph
  25. {
  26. class BOOST_SYMBOL_VISIBLE metis_exception : public std::exception
  27. {
  28. };
  29. class BOOST_SYMBOL_VISIBLE metis_input_exception : public metis_exception
  30. {
  31. };
  32. class metis_reader
  33. {
  34. public:
  35. typedef std::size_t vertices_size_type;
  36. typedef std::size_t edges_size_type;
  37. typedef double vertex_weight_type;
  38. typedef double edge_weight_type;
  39. class edge_iterator
  40. {
  41. public:
  42. typedef std::input_iterator_tag iterator_category;
  43. typedef std::pair< vertices_size_type, vertices_size_type >
  44. value_type;
  45. typedef const value_type& reference;
  46. typedef const value_type* pointer;
  47. typedef std::ptrdiff_t difference_type;
  48. private:
  49. class postincrement_proxy
  50. {
  51. postincrement_proxy(const value_type& value) : value(value) {}
  52. public:
  53. reference operator*() const { return value; }
  54. private:
  55. value_type value;
  56. friend class edge_iterator;
  57. };
  58. public:
  59. edge_iterator& operator++();
  60. postincrement_proxy operator++(int);
  61. reference operator*() const { return self->edge; }
  62. pointer operator->() const { return &self->edge; }
  63. // Default copy constructor and assignment operator are okay
  64. private:
  65. edge_iterator(metis_reader* self);
  66. void advance(bool skip_initial_read);
  67. metis_reader* self;
  68. friend class metis_reader;
  69. friend bool operator==(edge_iterator, edge_iterator);
  70. friend bool operator!=(edge_iterator, edge_iterator);
  71. };
  72. friend class edge_iterator;
  73. class edge_weight_iterator
  74. {
  75. public:
  76. typedef std::input_iterator_tag iterator_category;
  77. typedef edge_weight_type value_type;
  78. typedef const value_type& reference;
  79. typedef const value_type* pointer;
  80. // Default copy constructor and assignment operator are okay
  81. reference operator*() const { return self->edge_weight; }
  82. pointer operator->() const { return &self->edge_weight; }
  83. edge_weight_iterator& operator++() { return *this; }
  84. edge_weight_iterator operator++(int) { return *this; }
  85. private:
  86. edge_weight_iterator(metis_reader* self) : self(self) {}
  87. metis_reader* self;
  88. friend class metis_reader;
  89. };
  90. metis_reader(std::istream& in) : in(in), edge_weight(1.0) { start(); }
  91. edge_iterator begin();
  92. edge_iterator end();
  93. edge_weight_iterator weight_begin();
  94. vertices_size_type num_vertices() const { return n_vertices; }
  95. edges_size_type num_edges() const { return n_edges; }
  96. std::size_t num_vertex_weights() const { return n_vertex_weights; }
  97. vertex_weight_type vertex_weight(vertices_size_type v, std::size_t n)
  98. {
  99. return vertex_weights[v * num_vertex_weights() + n];
  100. }
  101. bool has_edge_weights() const { return edge_weights; }
  102. private:
  103. void start();
  104. // Configuration information
  105. std::istream& in;
  106. // Information about the current METIS file
  107. vertices_size_type n_vertices;
  108. edges_size_type n_edges;
  109. std::size_t n_vertex_weights;
  110. bool edge_weights;
  111. // Information about the current edge/vertex
  112. std::istringstream line_in;
  113. std::pair< vertices_size_type, vertices_size_type > edge;
  114. std::vector< vertex_weight_type > vertex_weights;
  115. edge_weight_type edge_weight;
  116. friend bool operator==(edge_iterator, edge_iterator);
  117. friend bool operator!=(edge_iterator, edge_iterator);
  118. };
  119. class metis_distribution
  120. {
  121. public:
  122. typedef int process_id_type;
  123. typedef std::size_t size_type;
  124. typedef std::vector< process_id_type >::iterator iterator;
  125. metis_distribution(std::istream& in, process_id_type my_id);
  126. size_type block_size(process_id_type id, size_type) const;
  127. process_id_type operator()(size_type n) const { return vertices[n]; }
  128. size_type local(size_type n) const;
  129. size_type global(size_type n) const { return global(my_id, n); }
  130. size_type global(process_id_type id, size_type n) const;
  131. iterator begin() { return vertices.begin(); }
  132. iterator end() { return vertices.end(); }
  133. private:
  134. process_id_type my_id;
  135. std::vector< process_id_type > vertices;
  136. };
  137. #if !defined(BOOST_GRAPH_METIS_NO_INLINE) || defined(BOOST_GRAPH_METIS_SOURCE)
  138. BOOST_GRAPH_METIS_INLINE_KEYWORD
  139. bool operator==(
  140. metis_reader::edge_iterator x, metis_reader::edge_iterator y)
  141. {
  142. return (x.self == y.self
  143. || (x.self && x.self->edge.first == x.self->num_vertices())
  144. || (y.self && y.self->edge.first == y.self->num_vertices()));
  145. }
  146. BOOST_GRAPH_METIS_INLINE_KEYWORD
  147. bool operator!=(
  148. metis_reader::edge_iterator x, metis_reader::edge_iterator y)
  149. {
  150. return !(x == y);
  151. }
  152. BOOST_GRAPH_METIS_INLINE_KEYWORD
  153. metis_reader::edge_iterator::edge_iterator(metis_reader* self) : self(self)
  154. {
  155. if (self)
  156. advance(true);
  157. }
  158. BOOST_GRAPH_METIS_INLINE_KEYWORD
  159. metis_reader::edge_iterator& metis_reader::edge_iterator::operator++()
  160. {
  161. advance(false);
  162. return *this;
  163. }
  164. BOOST_GRAPH_METIS_INLINE_KEYWORD
  165. void metis_reader::edge_iterator::advance(bool skip_initial_read)
  166. {
  167. do
  168. {
  169. if (!skip_initial_read)
  170. {
  171. // Try to read the next edge
  172. if (self->line_in >> std::ws >> self->edge.second)
  173. {
  174. --self->edge.second;
  175. if (self->has_edge_weights())
  176. {
  177. if (!(self->line_in >> self->edge_weight))
  178. boost::throw_exception(metis_input_exception());
  179. }
  180. return;
  181. }
  182. // Check if we're done
  183. ++self->edge.first;
  184. if (self->edge.first == self->num_vertices())
  185. return;
  186. }
  187. // Find the next line
  188. std::string line;
  189. while (getline(self->in, line) && !line.empty() && line[0] == '%')
  190. {
  191. /* Keep reading lines in the loop header... */
  192. }
  193. if (!self->in)
  194. boost::throw_exception(metis_input_exception());
  195. self->line_in.str(line);
  196. self->line_in.clear();
  197. // Read the next line
  198. std::size_t weights_left = self->n_vertex_weights;
  199. vertex_weight_type weight;
  200. while (weights_left > 0)
  201. {
  202. if (self->line_in >> weight)
  203. self->vertex_weights.push_back(weight);
  204. else
  205. boost::throw_exception(metis_input_exception());
  206. --weights_left;
  207. }
  208. // Successive iterations will pick up edges for this vertex.
  209. skip_initial_read = false;
  210. } while (true);
  211. }
  212. BOOST_GRAPH_METIS_INLINE_KEYWORD
  213. metis_reader::edge_iterator::postincrement_proxy
  214. metis_reader::edge_iterator::operator++(int)
  215. {
  216. postincrement_proxy result(**this);
  217. ++(*this);
  218. return result;
  219. }
  220. BOOST_GRAPH_METIS_INLINE_KEYWORD
  221. metis_reader::edge_iterator metis_reader::begin()
  222. {
  223. if (edge.first != 0)
  224. start();
  225. return edge_iterator(this);
  226. }
  227. BOOST_GRAPH_METIS_INLINE_KEYWORD
  228. metis_reader::edge_iterator metis_reader::end() { return edge_iterator(0); }
  229. BOOST_GRAPH_METIS_INLINE_KEYWORD
  230. metis_reader::edge_weight_iterator metis_reader::weight_begin()
  231. {
  232. return edge_weight_iterator(this);
  233. }
  234. BOOST_GRAPH_METIS_INLINE_KEYWORD
  235. void metis_reader::start()
  236. {
  237. in.seekg(0, std::ios::beg);
  238. std::string line;
  239. while (getline(in, line) && !line.empty() && line[0] == '%')
  240. {
  241. /* Keep getting lines in loop header. */
  242. }
  243. if (!in || line.empty())
  244. boost::throw_exception(metis_input_exception());
  245. // Determine number of vertices and edges in the graph
  246. line_in.str(line);
  247. if (!(line_in >> n_vertices >> n_edges))
  248. boost::throw_exception(metis_input_exception());
  249. // Determine whether vertex or edge weights are included in the graph
  250. int fmt = 0;
  251. line_in >> fmt;
  252. n_vertex_weights = fmt / 10;
  253. edge_weights = (fmt % 10 == 1);
  254. // Determine how many (if any!) vertex weights are included
  255. if (n_vertex_weights)
  256. line_in >> n_vertex_weights;
  257. // Setup the iteration data structures
  258. edge_weight = 1.0;
  259. edge.first = 0;
  260. edge.second = 0;
  261. vertex_weights.reserve(n_vertex_weights * num_vertices());
  262. }
  263. metis_distribution::metis_distribution(
  264. std::istream& in, process_id_type my_id)
  265. : my_id(my_id)
  266. , vertices(std::istream_iterator< process_id_type >(in),
  267. std::istream_iterator< process_id_type >())
  268. {
  269. }
  270. metis_distribution::size_type metis_distribution::block_size(
  271. process_id_type id, size_type) const
  272. {
  273. return std::count(vertices.begin(), vertices.end(), id);
  274. }
  275. metis_distribution::size_type metis_distribution::local(size_type n) const
  276. {
  277. return std::count(vertices.begin(), vertices.begin() + n, vertices[n]);
  278. }
  279. metis_distribution::size_type metis_distribution::global(
  280. process_id_type id, size_type n) const
  281. {
  282. std::vector< process_id_type >::const_iterator i = vertices.begin();
  283. while (*i != id)
  284. ++i;
  285. while (n > 0)
  286. {
  287. do
  288. {
  289. ++i;
  290. } while (*i != id);
  291. --n;
  292. }
  293. return i - vertices.begin();
  294. }
  295. #endif
  296. }
  297. } // end namespace boost::graph
  298. #endif // BOOST_GRAPH_METIS_HPP