1 // Copyright 2005 The Trustees of Indiana University.
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)
7 // Authors: Douglas Gregor
9 #ifndef BOOST_GRAPH_METIS_HPP
10 #define BOOST_GRAPH_METIS_HPP
12 #ifdef BOOST_GRAPH_METIS_NO_INLINE
13 # define BOOST_GRAPH_METIS_INLINE_KEYWORD
15 # define BOOST_GRAPH_METIS_INLINE_KEYWORD inline
27 namespace boost
{ namespace graph
{
29 class metis_exception
: public std::exception
{};
30 class metis_input_exception
: public metis_exception
{};
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
;
43 typedef std::input_iterator_tag iterator_category
;
44 typedef std::pair
<vertices_size_type
, vertices_size_type
> value_type
;
45 typedef const value_type
& reference
;
46 typedef const value_type
* pointer
;
47 typedef std::ptrdiff_t difference_type
;
50 class postincrement_proxy
52 postincrement_proxy(const value_type
& value
) : value(value
) { }
55 reference
operator*() const { return value
; }
59 friend class edge_iterator
;
63 edge_iterator
& operator++();
64 postincrement_proxy
operator++(int);
66 reference
operator*() const { return self
->edge
; }
67 pointer
operator->() const { return &self
->edge
; }
69 // Default copy constructor and assignment operator are okay
72 edge_iterator(metis_reader
* self
);
73 void advance(bool skip_initial_read
);
77 friend class metis_reader
;
78 friend bool operator==(edge_iterator
, edge_iterator
);
79 friend bool operator!=(edge_iterator
, edge_iterator
);
81 friend class edge_iterator
;
83 class edge_weight_iterator
86 typedef std::input_iterator_tag iterator_category
;
87 typedef edge_weight_type value_type
;
88 typedef const value_type
& reference
;
89 typedef const value_type
* pointer
;
91 // Default copy constructor and assignment operator are okay
93 reference
operator*() const { return self
->edge_weight
; }
94 pointer
operator->() const { return &self
->edge_weight
; }
96 edge_weight_iterator
& operator++() { return *this; }
97 edge_weight_iterator
operator++(int) { return *this; }
100 edge_weight_iterator(metis_reader
* self
) : self(self
) { }
104 friend class metis_reader
;
107 metis_reader(std::istream
& in
) : in(in
), edge_weight(1.0) { start(); }
109 edge_iterator
begin();
111 edge_weight_iterator
weight_begin();
113 vertices_size_type
num_vertices() const { return n_vertices
; }
114 edges_size_type
num_edges() const { return n_edges
; }
116 std::size_t num_vertex_weights() const { return n_vertex_weights
; }
118 vertex_weight_type
vertex_weight(vertices_size_type v
, std::size_t n
)
119 { return vertex_weights
[v
*num_vertex_weights() + n
]; }
121 bool has_edge_weights() const { return edge_weights
; }
126 // Configuration information
129 // Information about the current METIS file
130 vertices_size_type n_vertices
;
131 edges_size_type n_edges
;
132 std::size_t n_vertex_weights
;
135 // Information about the current edge/vertex
136 std::istringstream line_in
;
137 std::pair
<vertices_size_type
, vertices_size_type
> edge
;
138 std::vector
<vertex_weight_type
> vertex_weights
;
139 edge_weight_type edge_weight
;
141 friend bool operator==(edge_iterator
, edge_iterator
);
142 friend bool operator!=(edge_iterator
, edge_iterator
);
145 class metis_distribution
148 typedef int process_id_type
;
149 typedef std::size_t size_type
;
150 typedef std::vector
<process_id_type
>::iterator iterator
;
152 metis_distribution(std::istream
& in
, process_id_type my_id
);
154 size_type
block_size(process_id_type id
, size_type
) const;
155 process_id_type
operator()(size_type n
) const { return vertices
[n
]; }
156 size_type
local(size_type n
) const;
157 size_type
global(size_type n
) const { return global(my_id
, n
); }
158 size_type
global(process_id_type id
, size_type n
) const;
160 iterator
begin() { return vertices
.begin(); }
161 iterator
end() { return vertices
.end(); }
165 process_id_type my_id
;
166 std::vector
<process_id_type
> vertices
;
169 #if !defined(BOOST_GRAPH_METIS_NO_INLINE) || defined(BOOST_GRAPH_METIS_SOURCE)
170 BOOST_GRAPH_METIS_INLINE_KEYWORD
171 bool operator==(metis_reader::edge_iterator x
, metis_reader::edge_iterator y
)
173 return (x
.self
== y
.self
174 || (x
.self
&& x
.self
->edge
.first
== x
.self
->num_vertices())
175 || (y
.self
&& y
.self
->edge
.first
== y
.self
->num_vertices()));
178 BOOST_GRAPH_METIS_INLINE_KEYWORD
179 bool operator!=(metis_reader::edge_iterator x
, metis_reader::edge_iterator y
)
184 BOOST_GRAPH_METIS_INLINE_KEYWORD
185 metis_reader::edge_iterator::edge_iterator(metis_reader
* self
)
188 if (self
) advance(true);
191 BOOST_GRAPH_METIS_INLINE_KEYWORD
192 metis_reader::edge_iterator
& metis_reader::edge_iterator::operator++()
198 BOOST_GRAPH_METIS_INLINE_KEYWORD
199 void metis_reader::edge_iterator::advance(bool skip_initial_read
)
203 if (!skip_initial_read
) {
204 // Try to read the next edge
205 if (self
->line_in
>> std::ws
>> self
->edge
.second
) {
207 if (self
->has_edge_weights()) {
208 if (!(self
->line_in
>> self
->edge_weight
))
209 boost::throw_exception(metis_input_exception());
214 // Check if we're done
216 if (self
->edge
.first
== self
->num_vertices())
220 // Find the next line
222 while (getline(self
->in
, line
) && !line
.empty() && line
[0] == '%') {
223 /* Keep reading lines in the loop header... */
225 if (!self
->in
) boost::throw_exception(metis_input_exception());
226 self
->line_in
.str(line
);
227 self
->line_in
.clear();
229 // Read the next line
230 std::size_t weights_left
= self
->n_vertex_weights
;
231 vertex_weight_type weight
;
232 while (weights_left
> 0) {
233 if (self
->line_in
>> weight
) self
->vertex_weights
.push_back(weight
);
234 else boost::throw_exception(metis_input_exception());
238 // Successive iterations will pick up edges for this vertex.
239 skip_initial_read
= false;
243 BOOST_GRAPH_METIS_INLINE_KEYWORD
244 metis_reader::edge_iterator::postincrement_proxy
245 metis_reader::edge_iterator::operator++(int)
247 postincrement_proxy
result(**this);
252 BOOST_GRAPH_METIS_INLINE_KEYWORD
253 metis_reader::edge_iterator
metis_reader::begin()
255 if (edge
.first
!= 0) start();
256 return edge_iterator(this);
259 BOOST_GRAPH_METIS_INLINE_KEYWORD
260 metis_reader::edge_iterator
metis_reader::end()
262 return edge_iterator(0);
265 BOOST_GRAPH_METIS_INLINE_KEYWORD
266 metis_reader::edge_weight_iterator
metis_reader::weight_begin()
268 return edge_weight_iterator(this);
271 BOOST_GRAPH_METIS_INLINE_KEYWORD
272 void metis_reader::start()
274 in
.seekg(0, std::ios::beg
);
276 while (getline(in
, line
) && !line
.empty() && line
[0] == '%') {
277 /* Keep getting lines in loop header. */
280 if (!in
|| line
.empty()) boost::throw_exception(metis_input_exception());
282 // Determine number of vertices and edges in the graph
284 if (!(line_in
>> n_vertices
>> n_edges
)) boost::throw_exception(metis_input_exception());
286 // Determine whether vertex or edge weights are included in the graph
289 n_vertex_weights
= fmt
/ 10;
290 edge_weights
= (fmt
% 10 == 1);
292 // Determine how many (if any!) vertex weights are included
293 if (n_vertex_weights
) line_in
>> n_vertex_weights
;
295 // Setup the iteration data structures
299 vertex_weights
.reserve(n_vertex_weights
* num_vertices());
302 metis_distribution::metis_distribution(std::istream
& in
, process_id_type my_id
)
303 : in(in
), my_id(my_id
),
304 vertices(std::istream_iterator
<process_id_type
>(in
),
305 std::istream_iterator
<process_id_type
>())
310 metis_distribution::size_type
311 metis_distribution::block_size(process_id_type id
, size_type
) const
313 return std::count(vertices
.begin(), vertices
.end(), id
);
316 metis_distribution::size_type
metis_distribution::local(size_type n
) const
318 return std::count(vertices
.begin(), vertices
.begin() + n
, vertices
[n
]);
321 metis_distribution::size_type
322 metis_distribution::global(process_id_type id
, size_type n
) const
324 std::vector
<process_id_type
>::const_iterator i
= vertices
.begin();
325 while (*i
!= id
) ++i
;
328 do { ++i
; } while (*i
!= id
);
332 return i
- vertices
.begin();
337 } } // end namespace boost::graph
339 #endif // BOOST_GRAPH_METIS_HPP