c++boostboost-graphboost-property-map

boost DFS does not work with setS vertice lists


The following code is not compiled.

#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/topological_sort.hpp>
#include <boost/function_output_iterator.hpp>

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 // edgelist
> Graph;

bool hasCycle(const Graph& aG) 
{
    try {
        boost::topological_sort(
            aG, 
            boost::make_function_output_iterator([](int){}));
    } catch(boost::not_a_dag const&)
    {
        return true;
    }
    return false;
 } 

It works after changing vertice lists to be vecS http://coliru.stacked-crooked.com/a/abeb9e3f96e92af0

Is this limitation because DFS needs a deterministic visits?

Thank you,


Solution

  • The "limitation" is documented as the need for a vertex index. You could add one (note that you also should replace int by Graph::vertex_descriptor), or adjust the graph type to include one:

    Adding an external index property map

    Live On Coliru

    #include <boost/graph/adjacency_list.hpp>
    #include <boost/graph/topological_sort.hpp>
    #include <boost/function_output_iterator.hpp>
    
    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 // edgelist
    > Graph;
    
    bool hasCycle(const Graph& aG)
    {
        try {
            std::map<Graph::vertex_descriptor, size_t> index;
            auto pmap = boost::make_assoc_property_map(index);
    
            for (auto vd : boost::make_iterator_range(boost::vertices(aG)))
                index[vd] = index.size();
    
            boost::topological_sort(
                aG,
                boost::make_function_output_iterator([](Graph::vertex_descriptor){}),
                boost::vertex_index_map(pmap));
        }
        catch (boost::not_a_dag const&)
        {
            return true;
        }
        return false;
    }
    
    int main() {
    }
    

    Adding an internal index property map

    This amounts to shifting the burden to the caller. This might make (a lot of) sense depending on the performance requirements for you application.

    Live On Coliru

    #include <boost/graph/adjacency_list.hpp>
    #include <boost/graph/topological_sort.hpp>
    #include <boost/function_output_iterator.hpp>
    
    typedef boost::adjacency_list<
        boost::setS, // outedge list
        boost::setS, // vertex list
        boost::directedS, // undirected 
        boost::property<boost::vertex_index_t, int>, // vertex prop
        boost::no_property, // edge prop
        boost::no_property, // graph prop
        boost::setS // edgelist
    > Graph;
    
    bool hasCycle(const Graph& aG)
    {
        try {
            boost::topological_sort(
                aG,
                boost::make_function_output_iterator([](Graph::vertex_descriptor){})
            );
        }
        catch (boost::not_a_dag const&)
        {
            return true;
        }
        return false;
    }
    
    #include <boost/graph/random.hpp>
    #include <random>
    
    int main() {
        std::mt19937 prng{ std::random_device{}() };
        Graph g;
        boost::generate_random_graph(g, 100, 200, prng);
        auto index = boost::get(boost::vertex_index, g);
    
        int gen_id = 0;
        for (auto vd : boost::make_iterator_range(boost::vertices(g))) {
            boost::put(index, vd, gen_id++);
            std::cout << "Vertex " << boost::get(index, vd) << "\n";
        }
    
        bool check = hasCycle(g);
    }