metis.hpp 11 KB

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