Chris@16: // Copyright 2005 The Trustees of Indiana University. Chris@16: Chris@16: // Use, modification and distribution is subject to the Boost Software Chris@16: // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at Chris@16: // http://www.boost.org/LICENSE_1_0.txt) Chris@16: Chris@16: // Authors: Douglas Gregor Chris@16: // Andrew Lumsdaine Chris@16: #ifndef BOOST_GRAPH_METIS_HPP Chris@16: #define BOOST_GRAPH_METIS_HPP Chris@16: Chris@16: #ifdef BOOST_GRAPH_METIS_NO_INLINE Chris@16: # define BOOST_GRAPH_METIS_INLINE_KEYWORD Chris@16: #else Chris@16: # define BOOST_GRAPH_METIS_INLINE_KEYWORD inline Chris@16: #endif Chris@16: Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: #include Chris@16: Chris@16: namespace boost { namespace graph { Chris@16: Chris@16: class metis_exception : public std::exception {}; Chris@16: class metis_input_exception : public metis_exception {}; Chris@16: Chris@16: class metis_reader Chris@16: { Chris@16: public: Chris@16: typedef std::size_t vertices_size_type; Chris@16: typedef std::size_t edges_size_type; Chris@16: typedef double vertex_weight_type; Chris@16: typedef double edge_weight_type; Chris@16: Chris@16: class edge_iterator Chris@16: { Chris@16: public: Chris@16: typedef std::input_iterator_tag iterator_category; Chris@16: typedef std::pair value_type; Chris@16: typedef const value_type& reference; Chris@16: typedef const value_type* pointer; Chris@16: typedef std::ptrdiff_t difference_type; Chris@16: Chris@16: private: Chris@16: class postincrement_proxy Chris@16: { Chris@16: postincrement_proxy(const value_type& value) : value(value) { } Chris@16: Chris@16: public: Chris@16: reference operator*() const { return value; } Chris@16: Chris@16: private: Chris@16: value_type value; Chris@16: friend class edge_iterator; Chris@16: }; Chris@16: Chris@16: public: Chris@16: edge_iterator& operator++(); Chris@16: postincrement_proxy operator++(int); Chris@16: Chris@16: reference operator*() const { return self->edge; } Chris@16: pointer operator->() const { return &self->edge; } Chris@16: Chris@16: // Default copy constructor and assignment operator are okay Chris@16: Chris@16: private: Chris@16: edge_iterator(metis_reader* self); Chris@16: void advance(bool skip_initial_read); Chris@16: Chris@16: metis_reader* self; Chris@16: Chris@16: friend class metis_reader; Chris@16: friend bool operator==(edge_iterator, edge_iterator); Chris@16: friend bool operator!=(edge_iterator, edge_iterator); Chris@16: }; Chris@16: friend class edge_iterator; Chris@16: Chris@16: class edge_weight_iterator Chris@16: { Chris@16: public: Chris@16: typedef std::input_iterator_tag iterator_category; Chris@16: typedef edge_weight_type value_type; Chris@16: typedef const value_type& reference; Chris@16: typedef const value_type* pointer; Chris@16: Chris@16: // Default copy constructor and assignment operator are okay Chris@16: Chris@16: reference operator*() const { return self->edge_weight; } Chris@16: pointer operator->() const { return &self->edge_weight; } Chris@16: Chris@16: edge_weight_iterator& operator++() { return *this; } Chris@16: edge_weight_iterator operator++(int) { return *this; } Chris@16: Chris@16: private: Chris@16: edge_weight_iterator(metis_reader* self) : self(self) { } Chris@16: Chris@16: metis_reader* self; Chris@16: Chris@16: friend class metis_reader; Chris@16: }; Chris@16: Chris@16: metis_reader(std::istream& in) : in(in), edge_weight(1.0) { start(); } Chris@16: Chris@16: edge_iterator begin(); Chris@16: edge_iterator end(); Chris@16: edge_weight_iterator weight_begin(); Chris@16: Chris@16: vertices_size_type num_vertices() const { return n_vertices; } Chris@16: edges_size_type num_edges() const { return n_edges; } Chris@16: Chris@16: std::size_t num_vertex_weights() const { return n_vertex_weights; } Chris@16: Chris@16: vertex_weight_type vertex_weight(vertices_size_type v, std::size_t n) Chris@16: { return vertex_weights[v*num_vertex_weights() + n]; } Chris@16: Chris@16: bool has_edge_weights() const { return edge_weights; } Chris@16: Chris@16: private: Chris@16: void start(); Chris@16: Chris@16: // Configuration information Chris@16: std::istream& in; Chris@16: Chris@16: // Information about the current METIS file Chris@16: vertices_size_type n_vertices; Chris@16: edges_size_type n_edges; Chris@16: std::size_t n_vertex_weights; Chris@16: bool edge_weights; Chris@16: Chris@16: // Information about the current edge/vertex Chris@16: std::istringstream line_in; Chris@16: std::pair edge; Chris@16: std::vector vertex_weights; Chris@16: edge_weight_type edge_weight; Chris@16: Chris@16: friend bool operator==(edge_iterator, edge_iterator); Chris@16: friend bool operator!=(edge_iterator, edge_iterator); Chris@16: }; Chris@16: Chris@16: class metis_distribution Chris@16: { Chris@16: public: Chris@16: typedef int process_id_type; Chris@16: typedef std::size_t size_type; Chris@16: typedef std::vector::iterator iterator; Chris@16: Chris@16: metis_distribution(std::istream& in, process_id_type my_id); Chris@16: Chris@16: size_type block_size(process_id_type id, size_type) const; Chris@16: process_id_type operator()(size_type n) const { return vertices[n]; } Chris@16: size_type local(size_type n) const; Chris@16: size_type global(size_type n) const { return global(my_id, n); } Chris@16: size_type global(process_id_type id, size_type n) const; Chris@16: Chris@16: iterator begin() { return vertices.begin(); } Chris@16: iterator end() { return vertices.end(); } Chris@16: Chris@16: private: Chris@16: std::istream& in; Chris@16: process_id_type my_id; Chris@16: std::vector vertices; Chris@16: }; Chris@16: Chris@16: #if !defined(BOOST_GRAPH_METIS_NO_INLINE) || defined(BOOST_GRAPH_METIS_SOURCE) Chris@16: BOOST_GRAPH_METIS_INLINE_KEYWORD Chris@16: bool operator==(metis_reader::edge_iterator x, metis_reader::edge_iterator y) Chris@16: { Chris@16: return (x.self == y.self Chris@16: || (x.self && x.self->edge.first == x.self->num_vertices()) Chris@16: || (y.self && y.self->edge.first == y.self->num_vertices())); Chris@16: } Chris@16: Chris@16: BOOST_GRAPH_METIS_INLINE_KEYWORD Chris@16: bool operator!=(metis_reader::edge_iterator x, metis_reader::edge_iterator y) Chris@16: { Chris@16: return !(x == y); Chris@16: } Chris@16: Chris@16: BOOST_GRAPH_METIS_INLINE_KEYWORD Chris@16: metis_reader::edge_iterator::edge_iterator(metis_reader* self) Chris@16: : self(self) Chris@16: { Chris@16: if (self) advance(true); Chris@16: } Chris@16: Chris@16: BOOST_GRAPH_METIS_INLINE_KEYWORD Chris@16: metis_reader::edge_iterator& metis_reader::edge_iterator::operator++() Chris@16: { Chris@16: advance(false); Chris@16: return *this; Chris@16: } Chris@16: Chris@16: BOOST_GRAPH_METIS_INLINE_KEYWORD Chris@16: void metis_reader::edge_iterator::advance(bool skip_initial_read) Chris@16: { Chris@16: do { Chris@16: Chris@16: if (!skip_initial_read) { Chris@16: // Try to read the next edge Chris@16: if (self->line_in >> std::ws >> self->edge.second) { Chris@16: --self->edge.second; Chris@16: if (self->has_edge_weights()) { Chris@16: if (!(self->line_in >> self->edge_weight)) Chris@16: boost::throw_exception(metis_input_exception()); Chris@16: } Chris@16: return; Chris@16: } Chris@16: Chris@16: // Check if we're done Chris@16: ++self->edge.first; Chris@16: if (self->edge.first == self->num_vertices()) Chris@16: return; Chris@16: } Chris@16: Chris@16: // Find the next line Chris@16: std::string line; Chris@16: while (getline(self->in, line) && !line.empty() && line[0] == '%') { Chris@16: /* Keep reading lines in the loop header... */ Chris@16: } Chris@16: if (!self->in) boost::throw_exception(metis_input_exception()); Chris@16: self->line_in.str(line); Chris@16: self->line_in.clear(); Chris@16: Chris@16: // Read the next line Chris@16: std::size_t weights_left = self->n_vertex_weights; Chris@16: vertex_weight_type weight; Chris@16: while (weights_left > 0) { Chris@16: if (self->line_in >> weight) self->vertex_weights.push_back(weight); Chris@16: else boost::throw_exception(metis_input_exception()); Chris@16: --weights_left; Chris@16: } Chris@16: Chris@16: // Successive iterations will pick up edges for this vertex. Chris@16: skip_initial_read = false; Chris@16: } while (true); Chris@16: } Chris@16: Chris@16: BOOST_GRAPH_METIS_INLINE_KEYWORD Chris@16: metis_reader::edge_iterator::postincrement_proxy Chris@16: metis_reader::edge_iterator::operator++(int) Chris@16: { Chris@16: postincrement_proxy result(**this); Chris@16: ++(*this); Chris@16: return result; Chris@16: } Chris@16: Chris@16: BOOST_GRAPH_METIS_INLINE_KEYWORD Chris@16: metis_reader::edge_iterator metis_reader::begin() Chris@16: { Chris@16: if (edge.first != 0) start(); Chris@16: return edge_iterator(this); Chris@16: } Chris@16: Chris@16: BOOST_GRAPH_METIS_INLINE_KEYWORD Chris@16: metis_reader::edge_iterator metis_reader::end() Chris@16: { Chris@16: return edge_iterator(0); Chris@16: } Chris@16: Chris@16: BOOST_GRAPH_METIS_INLINE_KEYWORD Chris@16: metis_reader::edge_weight_iterator metis_reader::weight_begin() Chris@16: { Chris@16: return edge_weight_iterator(this); Chris@16: } Chris@16: Chris@16: BOOST_GRAPH_METIS_INLINE_KEYWORD Chris@16: void metis_reader::start() Chris@16: { Chris@16: in.seekg(0, std::ios::beg); Chris@16: std::string line; Chris@16: while (getline(in, line) && !line.empty() && line[0] == '%') { Chris@16: /* Keep getting lines in loop header. */ Chris@16: } Chris@16: Chris@16: if (!in || line.empty()) boost::throw_exception(metis_input_exception()); Chris@16: Chris@16: // Determine number of vertices and edges in the graph Chris@16: line_in.str(line); Chris@16: if (!(line_in >> n_vertices >> n_edges)) boost::throw_exception(metis_input_exception()); Chris@16: Chris@16: // Determine whether vertex or edge weights are included in the graph Chris@16: int fmt = 0; Chris@16: line_in >> fmt; Chris@16: n_vertex_weights = fmt / 10; Chris@16: edge_weights = (fmt % 10 == 1); Chris@16: Chris@16: // Determine how many (if any!) vertex weights are included Chris@16: if (n_vertex_weights) line_in >> n_vertex_weights; Chris@16: Chris@16: // Setup the iteration data structures Chris@16: edge_weight = 1.0; Chris@16: edge.first = 0; Chris@16: edge.second = 0; Chris@16: vertex_weights.reserve(n_vertex_weights * num_vertices()); Chris@16: } Chris@16: Chris@16: metis_distribution::metis_distribution(std::istream& in, process_id_type my_id) Chris@16: : in(in), my_id(my_id), Chris@16: vertices(std::istream_iterator(in), Chris@16: std::istream_iterator()) Chris@16: { Chris@16: } Chris@16: Chris@16: Chris@16: metis_distribution::size_type Chris@16: metis_distribution::block_size(process_id_type id, size_type) const Chris@16: { Chris@16: return std::count(vertices.begin(), vertices.end(), id); Chris@16: } Chris@16: Chris@16: metis_distribution::size_type metis_distribution::local(size_type n) const Chris@16: { Chris@16: return std::count(vertices.begin(), vertices.begin() + n, vertices[n]); Chris@16: } Chris@16: Chris@16: metis_distribution::size_type Chris@16: metis_distribution::global(process_id_type id, size_type n) const Chris@16: { Chris@16: std::vector::const_iterator i = vertices.begin(); Chris@16: while (*i != id) ++i; Chris@16: Chris@16: while (n > 0) { Chris@16: do { ++i; } while (*i != id); Chris@16: --n; Chris@16: } Chris@16: Chris@16: return i - vertices.begin(); Chris@16: } Chris@16: Chris@16: #endif Chris@16: Chris@16: } } // end namespace boost::graph Chris@16: Chris@16: #endif // BOOST_GRAPH_METIS_HPP