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