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