2

I am using the undirected DFS (Depth First Search) algorithm implemented in boost::graph.

This algorithm needs color values on vertices and edges to keep track of the ones that have been parsed. In the provided example, the code stores these colors values as internal properties of the graph:

typedef adjacency_list<
    vecS,
    vecS,
    undirectedS,
    no_property,       // vertex properties
    property<edge_color_t, default_color_type> // edge colors
> graph_t;

And the call is done using the "named properties" version:

undirected_dfs(g, root_vertex(vertex_t(0)).visitor(vis)
             .edge_color_map(get(edge_color, g)));

My problem is that I have custom values for vertices and edges. I use what seems to be the preferred way of doing, which is called "bundled properties":

struct my_vertex { int a1; float a2; }
struct my_edge   { int b1; float b2; }
typedef adjacency_list<
    vecS,
    vecS,
    undirectedS,
    my_vertex,       // vertex properties
    my_edge          // edge properties
> graph_t;

Of course, the previous DFS function call does not work with this graph type definition. For vertices, the manual states that a default is provided, and it does build fine with only specific vertex type and the edges type as shown above. But if I want a specific edge type, I came to the conclusion that I need to provide separatly the colors needed by the algorithm, as I can't use the properties as shown in the example code. So I assume this can be done by providing them as "exterior properties".

My problem is: how do I do that ?

Manual excerpt:

UTIL: edge_color_map(EdgeColorMap edge_color) This is used by the algorithm to keep track of which edges have been visited. The type EdgeColorMap must be a model of Read/Write Property Map and its key type must be the graph's edge descriptor type and the value type of the color map must model ColorValue.

This is unclear to me, I have tried to read the part about property maps, but I just cant get it.

With the help of this answer, I tried this below, but this fails: (uses the "unnamed parameter" version)

std::vector<int> edge_color(   boost::num_edges(g), 0);
std::vector<int> vertex_color( boost::num_vertices(g), 0 );

boost::undirected_dfs(
    g,
    boost::visitor( boost::default_dfs_visitor() ),
    boost::vertex_color_map( vertex_color ),
    boost::edge_color_map( edge_color ),
    boost::root_vertex( vertex_t(0) )
);

If somebody could point me in the right direction...

Community
  • 1
  • 1
kebs
  • 6,387
  • 4
  • 41
  • 70

1 Answers1

1

You need to satisfy the exact parameter requirements documented: http://www.boost.org/doc/libs/1_63_0/libs/graph/doc/undirected_dfs.html

This means you /can/ get away with a vector for the vertex colors, but the edge colors need to be in an associative container, because the edge descriptor isn't integral like the vertex descriptor is for your graph type.

std::vector<default_color_type> vertex_color(num_vertices(g));
std::map<graph_t::edge_descriptor, default_color_type> edge_color;

auto idmap = get(vertex_index, g);
auto vcmap = make_iterator_property_map(vertex_color.begin(), idmap);
auto ecmap = make_assoc_property_map(edge_color);

graph_t::vertex_descriptor const start = 0;

Now you can invoke either the fixed-argument version of the algorithm:

undirected_dfs(g, vis, vcmap, ecmap, start);

Alternatively, invoke the exact same using the named-argument version:

undirected_dfs(g, 
        root_vertex(graph_t::vertex_descriptor(0))
        .visitor(vis)
        .vertex_color_map(vcmap)
        .edge_color_map(ecmap)
    );

DEMO

Live On Coliru

#include <iostream>
#include <boost/graph/depth_first_search.hpp>
#include <boost/graph/undirected_dfs.hpp>
#include <boost/graph/adjacency_list.hpp>

using namespace boost;

struct my_vertex { int a1; float a2; };
struct my_edge   { int b1; float b2; };

struct detect_loops : public boost::dfs_visitor<> {
    template <class Edge, class Graph>
    void back_edge(Edge e, const Graph& g) {
        std::cout << g[source(e,g)].a1 << " -- " << g[target(e,g)].a1 << "\n";
    }
};


typedef adjacency_list<vecS, vecS, undirectedS, my_vertex, my_edge> graph_t;

int main() {
    detect_loops vis;

    graph_t g;

    std::vector<default_color_type> vertex_color(num_vertices(g));
    std::map<graph_t::edge_descriptor, default_color_type> edge_color;

    auto idmap = get(vertex_index, g);
    auto vcmap = make_iterator_property_map(vertex_color.begin(), idmap);
    auto ecmap = make_assoc_property_map(edge_color);

    graph_t::vertex_descriptor const start = 0;

    undirected_dfs(g, vis, vcmap, ecmap, start);

    undirected_dfs(g, 
            root_vertex(graph_t::vertex_descriptor(0))
            .visitor(vis)
            .vertex_color_map(vcmap)
            .edge_color_map(ecmap)
        );
}
sehe
  • 374,641
  • 47
  • 450
  • 633
  • Thanks @sehe, I need some time to carefully study this, but I really appreciate you detailed answer. – kebs Apr 18 '17 at 20:27
  • Ok, confirmed. But this raises another question: how is the BGL user supposed to find that ? I mean, I searched on the [two](http://www.boost.org/doc/libs/1_63_0/libs/property_map/doc/property_map.html) [pages](http://www.boost.org/doc/libs/1_63_0/libs/graph/doc/using_property_maps.html) on property maps, but the two `make_XXX` functions don't seem to be documented there. Are they explained somewhere else ? If not, how where **you** able to know about them ? – kebs Apr 18 '17 at 22:48
  • Those pages have the goods. It's just so abstract that it takes some getting used to them, like lego blocks. Once you do, really simple stuff like: http://coliru.stacked-crooked.com/a/44f071dd0e299ae4 and then maybe stuff like http://coliru.stacked-crooked.com/a/3eff0ef4ae1ef829. Lego bricks. – sehe Apr 18 '17 at 23:01
  • Now to really know which property map can satisfy which Concepts as required by the docs for BGL algorithms, refer back to those documentation pages you already found. They're really quite exhaustive, just very dry :) (By the way, make sure to click all the types under the [Property Map Types](http://www.boost.org/doc/libs/1_63_0/libs/property_map/doc/property_map.html) heading). Also, see e.g. https://stackoverflow.com/questions/27863061/map-set-get-requests-into-c-class-structure-changes/27863767#27863767 – sehe Apr 18 '17 at 23:04
  • Once you start to _expect_ this kind of "dry rigor" from boost library docs (and this kind of abstraction from the library interfaces themselves), it will start becoming much easier to anticipate where to get your inspiration. Rest assured, I'm also happy to peruse examples I find, but I do **always** use them to locate the docs, and read the **immediately**, _next thing_. Many times the sample found are not the best match for your particular situation. – sehe Apr 18 '17 at 23:06
  • 1
    Thanks a lot for these comments and the 2 (very) valuable samples: this is really the kind of stuff that is missing in the docs ! I think I'm beginning to understand how property maps are working, thanks to you. – kebs Apr 19 '17 at 06:50
  • And, you are right, the property map types paragraph does gives a lot of info, but its hard to get the point if you are not comfortable with concepts and heavy metaprogramming style, which is (at present) my case. – kebs Apr 19 '17 at 07:00