metis.hpp 9.0 KB

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