3

I have a simple graph, I suceeded writing properties with the vertex, but when I use make_label_writer to write properties to the edges, the complier always complains. Could someone help with it?

My code is as following:

int main (int argc, char * argv[]) {
    typedef std::pair<int ,int> Edge;
    std::vector<Edge> used_by = {Edge(1, 0), Edge(2, 1),
            Edge(1,2), Edge(2, 0)};
    using namespace boost;
    typedef adjacency_list<vecS, vecS, directedS
             > Graph;
    Graph g(used_by.begin(), used_by.end(), 3);
    std::ofstream dmp;
    dmp.open("dmp.dot");
    //name for vertex
    std::vector<std::string> name{"one", "two", "three"};
    //name for edge
    std::vector<std::string> name1{"e1", "e2", "e3", "e4"};
    write_graphviz(std::cout, g, make_label_writer(&name[0]) 
                                   ,make_label_writer(&name1[0]));
}

The write_graphviz() will ofc called the template, which is perfectly fine :

  template <typename Graph, typename VertexWriter, typename 
  EdgeWriter>
  inline void
  write_graphviz(std::ostream& out, const Graph& g,
             VertexWriter vw, EdgeWriter ew
       BOOST_GRAPH_ENABLE_IF_MODELS_PARM(Graph,vertex_list_graph_tag))
  {
    default_writer gw;
    write_graphviz(out, g, vw, ew, gw);
  }

So the problem is now: when I only write the vertex properties using make_label_writer(&name[0]]]), the code runs perfectly. But when I add make_label_writer(&name1[0]), there is error.

code707
  • 1,663
  • 1
  • 8
  • 20
Dexter
  • 101
  • 1
  • 9

1 Answers1

4

The default vertex index is integral, which is why you can use the address of the first vertex name as implied associative property map.

The edge descriptor is a different beast and requires you to either

  • create an explicit iterator property map (using an extra index property map to map from edge descriptor to the integral index into the name1 vector)
  • or use a model of the Associative PropertyMap concept.

In this case you should property do the later using a std::map<edge_descriptor, std::string>.

Please also consider making your life with properties a lot simpler by using Bundled Properties.

Associative Property Map

Live On Coliru

#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/graphviz.hpp>

typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::directedS> Graph;

int main() {
    Graph g(3);
    auto e1 = add_edge(1, 0, g).first;
    auto e2 = add_edge(2, 1, g).first;
    auto e3 = add_edge(1, 2, g).first;
    auto e4 = add_edge(2, 0, g).first;

    std::vector<std::string>                      vname{ "one", "two", "three" };
    std::map<Graph::edge_descriptor, std::string> ename{ 
        { e1, "e1" },
        { e2, "e2" },
        { e3, "e3" },
        { e4, "e4" },
    };

    write_graphviz(std::cout, g,
            boost::make_label_writer(&vname[0]),
            make_label_writer(boost::make_assoc_property_map(ename)));
}

Prints

Bundled Properties Instead

Live On Coliru

#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/graphviz.hpp>

struct VertexProps { std::string name; };
struct EdgeProps   { std::string name; };
typedef boost::adjacency_list<boost::vecS, boost::vecS, boost::directedS, VertexProps, EdgeProps> Graph;

int main() {
    Graph g(3);
    g[0].name = "one";
    g[1].name = "two";
    g[2].name = "three";
    add_edge(1, 0, {"e1"}, g);
    add_edge(2, 1, {"e2"}, g);
    add_edge(1, 2, {"e3"}, g);
    add_edge(2, 0, {"e4"}, g);

    write_graphviz(std::cout, g,
            make_label_writer(get(&VertexProps::name, g)),
            make_label_writer(get(&EdgeProps::name, g)));
}

Prints the same

Jeff Linahan
  • 3,775
  • 5
  • 37
  • 56
sehe
  • 374,641
  • 47
  • 450
  • 633
  • 1
    Added two live demos since I came home :) – sehe Jul 02 '18 at 19:52
  • Thx a lot for your help! I thought nobody would answer this :)) – Dexter Jul 03 '18 at 10:12
  • *@sehe* Thx a lot for your help! I thought nobody would answer this :)) – Dexter Jul 03 '18 at 10:34
  • But there is still one problem that when I see the source code of graphviz.hpp I could not find any clue that Vertex and Edge properties are treated differently. So I can think the clue is in the adjacency_list.hpp ? I just started to use Boost, and find it very hard to begin. Because there are not much documents and too many nested source code and I dont know where to begin..Is there any suggestions from you that I can learn boost in a better way? – Dexter Jul 03 '18 at 10:54
  • They aren't treated any differently. They both require an associative property map keyed by the descriptor. The clues are indeed inside `adjacency_list`. For fun, change the second container selector from `vecS` to `listS`. Tadaa: you'll see that the vertex label map had the same semantics all along, only you didn't realize it because of the implied integral indexing as my answer already explained. – sehe Jul 03 '18 at 11:50
  • 1
    The documentation that touches on this would be [If the VertexList of the graph is vecS, then the graph has a builtin vertex indices accessed via the property map for the vertex_index_t property. The indices fall in the range [0, num_vertices(g)) and are contiguous.](https://www.boost.org/doc/libs/1_67_0/libs/graph/doc/adjacency_list.html), I suppose. Also, perhaps you'll want to read about property maps in general: https://stackoverflow.com/questions/27863061/map-set-get-requests-into-c-class-structure-changes/27863767#27863767 – sehe Jul 03 '18 at 11:52
  • Thanks again for your detailed answer! really helpful :)) – Dexter Jul 03 '18 at 14:28
  • 2
    years later you have saved me from hours of frustration. thank you so much. – Xavier Hubbard Anderson Aug 14 '22 at 00:33
  • 1
    even more years later you may be saving few hours more of frustration. thank you so much. – WaterFox Dec 10 '22 at 03:07