File indexing completed on 2025-07-15 08:35:58
0001
0002
0003
0004
0005
0006
0007
0008
0009 #ifndef BOOST_GRAPH_METIS_HPP
0010 #define BOOST_GRAPH_METIS_HPP
0011
0012 #ifdef BOOST_GRAPH_METIS_NO_INLINE
0013 #define BOOST_GRAPH_METIS_INLINE_KEYWORD
0014 #else
0015 #define BOOST_GRAPH_METIS_INLINE_KEYWORD inline
0016 #endif
0017
0018 #include <string>
0019 #include <iostream>
0020 #include <iterator>
0021 #include <utility>
0022 #include <sstream>
0023 #include <exception>
0024 #include <vector>
0025 #include <algorithm>
0026
0027 #include <boost/throw_exception.hpp>
0028
0029 namespace boost
0030 {
0031 namespace graph
0032 {
0033
0034 class BOOST_SYMBOL_VISIBLE metis_exception : public std::exception
0035 {
0036 };
0037 class BOOST_SYMBOL_VISIBLE metis_input_exception : public metis_exception
0038 {
0039 };
0040
0041 class metis_reader
0042 {
0043 public:
0044 typedef std::size_t vertices_size_type;
0045 typedef std::size_t edges_size_type;
0046 typedef double vertex_weight_type;
0047 typedef double edge_weight_type;
0048
0049 class edge_iterator
0050 {
0051 public:
0052 typedef std::input_iterator_tag iterator_category;
0053 typedef std::pair< vertices_size_type, vertices_size_type >
0054 value_type;
0055 typedef const value_type& reference;
0056 typedef const value_type* pointer;
0057 typedef std::ptrdiff_t difference_type;
0058
0059 private:
0060 class postincrement_proxy
0061 {
0062 postincrement_proxy(const value_type& value) : value(value) {}
0063
0064 public:
0065 reference operator*() const { return value; }
0066
0067 private:
0068 value_type value;
0069 friend class edge_iterator;
0070 };
0071
0072 public:
0073 edge_iterator& operator++();
0074 postincrement_proxy operator++(int);
0075
0076 reference operator*() const { return self->edge; }
0077 pointer operator->() const { return &self->edge; }
0078
0079
0080
0081 private:
0082 edge_iterator(metis_reader* self);
0083 void advance(bool skip_initial_read);
0084
0085 metis_reader* self;
0086
0087 friend class metis_reader;
0088 friend bool operator==(edge_iterator, edge_iterator);
0089 friend bool operator!=(edge_iterator, edge_iterator);
0090 };
0091 friend class edge_iterator;
0092
0093 class edge_weight_iterator
0094 {
0095 public:
0096 typedef std::input_iterator_tag iterator_category;
0097 typedef edge_weight_type value_type;
0098 typedef const value_type& reference;
0099 typedef const value_type* pointer;
0100
0101
0102
0103 reference operator*() const { return self->edge_weight; }
0104 pointer operator->() const { return &self->edge_weight; }
0105
0106 edge_weight_iterator& operator++() { return *this; }
0107 edge_weight_iterator operator++(int) { return *this; }
0108
0109 private:
0110 edge_weight_iterator(metis_reader* self) : self(self) {}
0111
0112 metis_reader* self;
0113
0114 friend class metis_reader;
0115 };
0116
0117 metis_reader(std::istream& in) : in(in), edge_weight(1.0) { start(); }
0118
0119 edge_iterator begin();
0120 edge_iterator end();
0121 edge_weight_iterator weight_begin();
0122
0123 vertices_size_type num_vertices() const { return n_vertices; }
0124 edges_size_type num_edges() const { return n_edges; }
0125
0126 std::size_t num_vertex_weights() const { return n_vertex_weights; }
0127
0128 vertex_weight_type vertex_weight(vertices_size_type v, std::size_t n)
0129 {
0130 return vertex_weights[v * num_vertex_weights() + n];
0131 }
0132
0133 bool has_edge_weights() const { return edge_weights; }
0134
0135 private:
0136 void start();
0137
0138
0139 std::istream& in;
0140
0141
0142 vertices_size_type n_vertices;
0143 edges_size_type n_edges;
0144 std::size_t n_vertex_weights;
0145 bool edge_weights;
0146
0147
0148 std::istringstream line_in;
0149 std::pair< vertices_size_type, vertices_size_type > edge;
0150 std::vector< vertex_weight_type > vertex_weights;
0151 edge_weight_type edge_weight;
0152
0153 friend bool operator==(edge_iterator, edge_iterator);
0154 friend bool operator!=(edge_iterator, edge_iterator);
0155 };
0156
0157 class metis_distribution
0158 {
0159 public:
0160 typedef int process_id_type;
0161 typedef std::size_t size_type;
0162 typedef std::vector< process_id_type >::iterator iterator;
0163
0164 metis_distribution(std::istream& in, process_id_type my_id);
0165
0166 size_type block_size(process_id_type id, size_type) const;
0167 process_id_type operator()(size_type n) const { return vertices[n]; }
0168 size_type local(size_type n) const;
0169 size_type global(size_type n) const { return global(my_id, n); }
0170 size_type global(process_id_type id, size_type n) const;
0171
0172 iterator begin() { return vertices.begin(); }
0173 iterator end() { return vertices.end(); }
0174
0175 private:
0176 process_id_type my_id;
0177 std::vector< process_id_type > vertices;
0178 };
0179
0180 #if !defined(BOOST_GRAPH_METIS_NO_INLINE) || defined(BOOST_GRAPH_METIS_SOURCE)
0181 BOOST_GRAPH_METIS_INLINE_KEYWORD
0182 bool operator==(
0183 metis_reader::edge_iterator x, metis_reader::edge_iterator y)
0184 {
0185 return (x.self == y.self
0186 || (x.self && x.self->edge.first == x.self->num_vertices())
0187 || (y.self && y.self->edge.first == y.self->num_vertices()));
0188 }
0189
0190 BOOST_GRAPH_METIS_INLINE_KEYWORD
0191 bool operator!=(
0192 metis_reader::edge_iterator x, metis_reader::edge_iterator y)
0193 {
0194 return !(x == y);
0195 }
0196
0197 BOOST_GRAPH_METIS_INLINE_KEYWORD
0198 metis_reader::edge_iterator::edge_iterator(metis_reader* self) : self(self)
0199 {
0200 if (self)
0201 advance(true);
0202 }
0203
0204 BOOST_GRAPH_METIS_INLINE_KEYWORD
0205 metis_reader::edge_iterator& metis_reader::edge_iterator::operator++()
0206 {
0207 advance(false);
0208 return *this;
0209 }
0210
0211 BOOST_GRAPH_METIS_INLINE_KEYWORD
0212 void metis_reader::edge_iterator::advance(bool skip_initial_read)
0213 {
0214 do
0215 {
0216
0217 if (!skip_initial_read)
0218 {
0219
0220 if (self->line_in >> std::ws >> self->edge.second)
0221 {
0222 --self->edge.second;
0223 if (self->has_edge_weights())
0224 {
0225 if (!(self->line_in >> self->edge_weight))
0226 boost::throw_exception(metis_input_exception());
0227 }
0228 return;
0229 }
0230
0231
0232 ++self->edge.first;
0233 if (self->edge.first == self->num_vertices())
0234 return;
0235 }
0236
0237
0238 std::string line;
0239 while (getline(self->in, line) && !line.empty() && line[0] == '%')
0240 {
0241
0242 }
0243 if (!self->in)
0244 boost::throw_exception(metis_input_exception());
0245 self->line_in.str(line);
0246 self->line_in.clear();
0247
0248
0249 std::size_t weights_left = self->n_vertex_weights;
0250 vertex_weight_type weight;
0251 while (weights_left > 0)
0252 {
0253 if (self->line_in >> weight)
0254 self->vertex_weights.push_back(weight);
0255 else
0256 boost::throw_exception(metis_input_exception());
0257 --weights_left;
0258 }
0259
0260
0261 skip_initial_read = false;
0262 } while (true);
0263 }
0264
0265 BOOST_GRAPH_METIS_INLINE_KEYWORD
0266 metis_reader::edge_iterator::postincrement_proxy
0267 metis_reader::edge_iterator::operator++(int)
0268 {
0269 postincrement_proxy result(**this);
0270 ++(*this);
0271 return result;
0272 }
0273
0274 BOOST_GRAPH_METIS_INLINE_KEYWORD
0275 metis_reader::edge_iterator metis_reader::begin()
0276 {
0277 if (edge.first != 0)
0278 start();
0279 return edge_iterator(this);
0280 }
0281
0282 BOOST_GRAPH_METIS_INLINE_KEYWORD
0283 metis_reader::edge_iterator metis_reader::end() { return edge_iterator(0); }
0284
0285 BOOST_GRAPH_METIS_INLINE_KEYWORD
0286 metis_reader::edge_weight_iterator metis_reader::weight_begin()
0287 {
0288 return edge_weight_iterator(this);
0289 }
0290
0291 BOOST_GRAPH_METIS_INLINE_KEYWORD
0292 void metis_reader::start()
0293 {
0294 in.seekg(0, std::ios::beg);
0295 std::string line;
0296 while (getline(in, line) && !line.empty() && line[0] == '%')
0297 {
0298
0299 }
0300
0301 if (!in || line.empty())
0302 boost::throw_exception(metis_input_exception());
0303
0304
0305 line_in.str(line);
0306 if (!(line_in >> n_vertices >> n_edges))
0307 boost::throw_exception(metis_input_exception());
0308
0309
0310 int fmt = 0;
0311 line_in >> fmt;
0312 n_vertex_weights = fmt / 10;
0313 edge_weights = (fmt % 10 == 1);
0314
0315
0316 if (n_vertex_weights)
0317 line_in >> n_vertex_weights;
0318
0319
0320 edge_weight = 1.0;
0321 edge.first = 0;
0322 edge.second = 0;
0323 vertex_weights.reserve(n_vertex_weights * num_vertices());
0324 }
0325
0326 metis_distribution::metis_distribution(
0327 std::istream& in, process_id_type my_id)
0328 : my_id(my_id)
0329 , vertices(std::istream_iterator< process_id_type >(in),
0330 std::istream_iterator< process_id_type >())
0331 {
0332 }
0333
0334 metis_distribution::size_type metis_distribution::block_size(
0335 process_id_type id, size_type) const
0336 {
0337 return std::count(vertices.begin(), vertices.end(), id);
0338 }
0339
0340 metis_distribution::size_type metis_distribution::local(size_type n) const
0341 {
0342 return std::count(vertices.begin(), vertices.begin() + n, vertices[n]);
0343 }
0344
0345 metis_distribution::size_type metis_distribution::global(
0346 process_id_type id, size_type n) const
0347 {
0348 std::vector< process_id_type >::const_iterator i = vertices.begin();
0349 while (*i != id)
0350 ++i;
0351
0352 while (n > 0)
0353 {
0354 do
0355 {
0356 ++i;
0357 } while (*i != id);
0358 --n;
0359 }
0360
0361 return i - vertices.begin();
0362 }
0363
0364 #endif
0365
0366 }
0367 }
0368
0369 #endif