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