Search code examples
c++boostgraphgraphvizboost-property-map

write_graphviz does not work when vertex list is setS?


The following code has errors:

cannot bind ‘std::basic_ostream’ lvalue to ‘std::basic_ostream&&

#include <boost/graph/graphviz.hpp>
void foo(int,char*[])
{
  using namespace boost;

  typedef boost::adjacency_list<
      boost::setS, // outedge list
      boost::setS, // vertex list
      boost::directedS, // undirected 
      boost::no_property, // vertex prop
      boost::no_property, // edge prop
      boost::no_property, // graph prop
      boost::setS // edgelistc
      > Graph;
  Graph g;

  std::ostringstream dotname;
  dotname << "a.dot";
  std::ofstream dot(dotname.str());

  write_graphviz(dot, g);
}

It works when boost::vecS, // vertex list

Is it expected?


Solution

  • Change the vertex container selector to setS changes the vertex descriptor into a type that is not streamable.

    You should, as with many many other algorithms in BGL, pass a separate vertex index:

    IN: VertexAndEdgeListGraph& g

    A directed or undirected graph. The graph's type must be a model of VertexAndEdgeListGraph. In most cases, the graph must have an internal vertex_index property map.

    External Vertex Id mapping

    Live On Coliru

    #include <boost/graph/graphviz.hpp>
    #include <boost/graph/random.hpp>
    #include <random>
    
    int main(int,char*[])
    {
        using namespace boost;
    
        typedef boost::adjacency_list<setS, setS, directedS> Graph;
        Graph g;
    
        std::mt19937 prng{std::random_device{}()};
        generate_random_graph(g, 3, 5, prng);
    
        std::map<Graph::vertex_descriptor, size_t> ids;
    
        for (auto u : make_iterator_range(vertices(g)))
            ids[u] = ids.size();
    
        default_writer w;
    
        write_graphviz(std::cout, g, w, w, w, make_assoc_property_map(ids));
    }
    

    Prints e.g.

    digraph G {
    1;
    2;
    3;
    1->2 ;
    2->1 ;
    2->3 ;
    3->1 ;
    3->2 ;
    }
    

    Internal property map:

    You can put the property internally without much changing:

    Live On Coliru

    #include <boost/graph/graphviz.hpp>
    #include <boost/graph/random.hpp>
    #include <random>
    
    int main(int,char*[])
    {
        using namespace boost;
    
        typedef boost::adjacency_list<setS, setS, directedS, property<vertex_index_t, size_t> > Graph;
        Graph g;
    
        std::mt19937 prng{std::random_device{}()};
        generate_random_graph(g, 3, 5, prng);
    
        auto ids = get(vertex_index, g);
        size_t num = 0;
        for (auto u : make_iterator_range(vertices(g)))
            put(ids, u, num++);
    
        write_graphviz(std::cout, g);
    }