快速添加vertex_index到listS图表以实现中介中心性

时间:2015-05-15 15:43:16

标签: c++ boost-graph

更新:问题可能出在中介代码中。如果我注释掉对brandes_betweenness_centrality的调用,代码将编译。问题可能不是以前认为的索引设置。如果您能够提出另一个对Brandes_betweenness_centrality的调用,我将奖励赏金,这将允许将索引保持在外部。

我正在尝试将一些旧的vecS代码转换为listS,特别是brandes_betweenness_centrality算法。

我正在尝试保持Vertex和Edge属性非常轻,并且主要使用外部属性。原因是我不知道此时我想要与他们联系的是什么。

我得到的错误来自adjacency_list.hpp内部,所以我认为问题出在我们的老朋友vertex_index_t和listS上。

以下代码显示了如何重现编译错误。在这个工作示例中,您可以更改定义以将vertex_index填充到图形定义中,并在完整工作代码(正确运行中间性)的中介方法中更改设置。

完整的例子:

#include <iostream>
#include <algorithm>
#include <vector>

#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/graph_traits.hpp>
#include <boost/graph/betweenness_centrality.hpp>

#include <boost/timer.hpp>

using namespace std;

enum edge_t {A,B};

struct VertexProperties{
    std::string id;
};

struct EdgeProperties{
    edge_t type;
};

//vertex_index in as internal property, switch to this graph and change below vertex map for working code
//typedef boost::adjacency_list < boost::listS, boost::listS, boost::undirectedS,
//      boost::property<boost::vertex_index_t,size_t,VertexProperties>, EdgeProperties > DynamicNet;

// No internal vertex_index
typedef boost::adjacency_list < boost::listS, boost::listS, boost::undirectedS,
        VertexProperties, EdgeProperties > DynamicNet;

typedef boost::graph_traits<DynamicNet>::vertex_descriptor DynamicNetVertex;
typedef boost::graph_traits<DynamicNet>::vertex_iterator   DynamicNetVI;

typedef boost::graph_traits<DynamicNet>::edge_descriptor   DynamicNetEdge;
typedef boost::graph_traits<DynamicNet>::edge_iterator     DynamicNetEI;


void calcBetweenness(DynamicNet &g,
                     std::vector<double> &v_centrality_vec,
                     std::vector<double> &e_centrality_vec);


int main(int argc, char* argv[]){
    cout <<  "betweenness" << endl;

    DynamicNet net;

    //Fig. 1, wheen graph (a - h), modified with added z added to a
    //http://www.boost.org/doc/libs/1_58_0/libs/graph/doc/betweenness_centrality.html
    DynamicNetVertex a = boost::add_vertex(net); net[a].id = "a";
    DynamicNetVertex b = boost::add_vertex(net); net[b].id = "b";
    DynamicNetVertex c = boost::add_vertex(net); net[c].id = "c";
    DynamicNetVertex d = boost::add_vertex(net); net[d].id = "d";
    DynamicNetVertex e = boost::add_vertex(net); net[e].id = "e";
    DynamicNetVertex f = boost::add_vertex(net); net[f].id = "f";
    DynamicNetVertex g = boost::add_vertex(net); net[g].id = "g";

    //core
    DynamicNetVertex h = boost::add_vertex(net); net[h].id = "h";

    boost::add_edge(a,h,net); 
    boost::add_edge(b,h,net);
    boost::add_edge(c,h,net);
    boost::add_edge(d,h,net);
    boost::add_edge(e,h,net);
    boost::add_edge(f,h,net);
    boost::add_edge(g,h,net);

    //add an edge to make the calculation more interesting
    DynamicNetVertex z = boost::add_vertex(net); net[z].id = "z";
    boost::add_edge(a,z,net);



    vector<double> v_centrality_vec(boost::num_vertices(net),0.0);
    vector<double> e_centrality_vec(boost::num_edges(net),0.0);

    boost::timer t;
    t.restart();
    calcBetweenness(net,v_centrality_vec,e_centrality_vec);
    double s = t.elapsed();
    cout << s << " s" << endl;
    cout << endl;

    cout << "Vertex betweenness" << endl;
    DynamicNetVI vi,ve;     
    size_t i = 0;
    for(boost::tie(vi,ve) = boost::vertices(net); vi != ve; ++vi){
        cout << net[*vi].id << "\t" << v_centrality_vec.at(i) << endl;
        ++i;
    }

    cout << endl;

    cout << "Edge betweenness" << endl;
    DynamicNetEI ei,ee; 
    i = 0;
    for(boost::tie(ei,ee) = boost::edges(net); ei != ee; ++ei){
        DynamicNetEdge e = *ei;
        cout << net[boost::source(e,net)].id << "\t" 
             << net[boost::target(e,net)].id << "\t" << e_centrality_vec.at(i) << endl;
        ++i;
    }

    cin.get();
}

void calcBetweenness(DynamicNet &g,
                     std::vector<double> &v_centrality_vec,
                     std::vector<double> &e_centrality_vec)
{
    std::cout << "betweenness called" << std::endl;

    //vertex
    //Uncomment and change to internal vertex graph above for working code.

/*
    typedef std::map<DynamicNetVertex,size_t> StdVertexIndexMap;
    StdVertexIndexMap viMap;
    typedef boost::property_map<DynamicNet, boost::vertex_index_t>::type VertexIndexMap;
    VertexIndexMap v_index = boost::get(boost::vertex_index,g);
    DynamicNetVI vi,ve;
    size_t i = 0;
    for(boost::tie(vi,ve) = boost::vertices(g); vi != ve; ++vi){
        boost::put(v_index,*vi,i);
        ++i;
    }
    boost::iterator_property_map< std::vector< double >::iterator, VertexIndexMap >
        v_centrality_map(v_centrality_vec.begin(), v_index);
*/  

    //this code which exactly mimics the working approached used by edge results in an error
    typedef std::map<DynamicNetVertex,size_t> StdVertexIndexMap;
    StdVertexIndexMap viMap;
    typedef boost::associative_property_map<StdVertexIndexMap> VertexIndexMap;
    VertexIndexMap v_index(viMap);
    DynamicNetVI vi,ve;
    size_t i = 0;
    for(boost::tie(vi,ve) = boost::vertices(g); vi != ve; ++vi){
        boost::put(v_index,*vi,i);
        ++i;
    }
    boost::iterator_property_map< std::vector< double >::iterator, VertexIndexMap >
        v_centrality_map(v_centrality_vec.begin(), v_index);



    //edge, this appraoch works fine for edge
    typedef std::map<DynamicNetEdge,size_t> StdEdgeIndexMap;
    StdEdgeIndexMap eiMap;
    typedef boost::associative_property_map<StdEdgeIndexMap> EdgeIndexMap;
    EdgeIndexMap e_index(eiMap);
    DynamicNetEI ei,ee; 
    i = 0;
    for(boost::tie(ei,ee) = boost::edges(g); ei != ee; ++ei){
        boost::put(e_index,*ei,i);
        ++i;
    }
    boost::iterator_property_map< std::vector< double >::iterator, EdgeIndexMap >
        e_centrality_map(e_centrality_vec.begin(), e_index);

    brandes_betweenness_centrality(g,v_centrality_map, e_centrality_map);
}

错误:

Error   1   error C2182: 'reference' : illegal use of type 'void'   ... \boost_1_58_0\boost\graph\detail\adjacency_list.hpp 2543
Error   2   error C2182: 'const_reference' : illegal use of type 'void' ... \boost_1_58_0\boost\graph\detail\adjacency_list.hpp 2544

MSVS输出:

1>------ Build started: Project: testBetweenness, Configuration: Release 

Win32 ------
1>Compiling...
1>testBetweenness.cpp
1>...\boost_1_58_0\boost/graph/detail/adjacency_list.hpp(2543) : error C2182: 'reference' : illegal use of type 'void'
1>        ...\boost_1_58_0\boost/graph/detail/adjacency_list.hpp(2619) : see reference to class template instantiation 'boost::adj_list_any_vertex_pa::bind_<Tag,Graph,Property>' being compiled
1>        with
1>        [
1>            Tag=boost::vertex_index_t,
1>            Graph=boost::adjacency_list<boost::listS,boost::listS,boost::undirectedS,pintk::VertexProperties,pintk::EdgeProperties>,
1>            Property=pintk::VertexProperties
1>        ]
1>        ...\boost_1_58_0\boost/graph/detail/adjacency_list.hpp(2752) : see reference to class template instantiation 'boost::detail::adj_list_choose_vertex_pa<Tag,Graph,Property>' being compiled
1>        with
1>        [
1>            Tag=boost::vertex_index_t,
1>            Graph=boost::adjacency_list<boost::listS,boost::listS,boost::undirectedS,pintk::VertexProperties,pintk::EdgeProperties>,
1>            Property=pintk::VertexProperties
1>        ]
1>        ...\boost_1_58_0\boost/graph/properties.hpp(208) : see reference to class template instantiation 'boost::adj_list_vertex_property_selector::bind_<Graph,Property,Tag>' being compiled
1>        with
1>        [
1>            Graph=boost::adjacency_list<boost::listS,boost::listS,boost::undirectedS,pintk::VertexProperties,pintk::EdgeProperties>,
1>            Property=pintk::VertexProperties,
1>            Tag=boost::vertex_index_t
1>        ]
1>        ...\boost_1_58_0\boost/graph/properties.hpp(217) : see reference to class template instantiation 'boost::detail::vertex_property_map<Graph,PropertyTag>' being compiled
1>        with
1>        [
1>            Graph=boost::adjacency_list<boost::listS,boost::listS,boost::undirectedS,pintk::VertexProperties,pintk::EdgeProperties>,
1>            PropertyTag=boost::vertex_index_t
1>        ]
1>        ...\boost_1_58_0\boost/graph/betweenness_centrality.hpp(562) : see reference to class template instantiation 'boost::property_map<Graph,Property,Enable>' being compiled
1>        with
1>        [
1>            Graph=boost::adjacency_list<boost::listS,boost::listS,boost::undirectedS,pintk::VertexProperties,pintk::EdgeProperties>,
1>            Property=boost::vertex_index_t,
1>            Enable=void
1>        ]
1>        ...\Visual Studio 2008\Projects\yapnl\yapnl\ProteinNetworks.h(82) : see reference to function template instantiation 'void boost::brandes_betweenness_centrality<pintk::DynamicNet,boost::iterator_property_map<RandomAccessIterator,IndexMap>,boost::iterator_property_map<RandomAccessIterator,EdgeIndexMap>>(const Graph &,CentralityMap,EdgeCentralityMap,boost::graph::detail::no_parameter)' being compiled
1>        with
1>        [
1>            RandomAccessIterator=std::_Vector_iterator<double,std::allocator<double>>,
1>            IndexMap=VertexIndexMap,
1>            Graph=pintk::DynamicNet,
1>            CentralityMap=boost::iterator_property_map<std::_Vector_iterator<double,std::allocator<double>>,VertexIndexMap>,
1>            EdgeCentralityMap=boost::iterator_property_map<std::_Vector_iterator<double,std::allocator<double>>,EdgeIndexMap>
1>        ]
1>...\boost_1_58_0\boost/graph/detail/adjacency_list.hpp(2544) : error C2182: 'const_reference' : illegal use of type 'void'
1>Build log was saved at "file://...\Visual Studio 2008\Projects\yapnl\testBetweenness\Release\BuildLog.htm"
1>testBetweenness - 2 error(s), 0 warning(s)
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========

answer帮助我在图表定义中添加boost::vertex_index_t属性,该属性允许使用boost::property<boost::vertex_index_t,size_t,VertexProperties>运行代码。

我希望有一种方法可以将vertex_index_t完全保留在图表外部,并在运行算法之前添加它。

用于设置edge_index的几乎相同的代码允许这样做。我错过了什么,或者这是MSVS的事情还是可能是一个错误?

我的具体问题是:我需要更改什么才能将vertex_index保留在图表定义之外,动态添加,仍然运行算法?

1 个答案:

答案 0 :(得分:5)

正如我在更新中所述,看起来问题在于中介中心性。挖掘source中的调度,并查看docs中的参数,我发现如果vertex_index_map未传递给算法,则默认为get(vertex_index, g)知道在这个特定的图表中不存在。

经过一段时间绕着名为bgl_named_params的头脑,我发现我可以将v_index变量作为命名参数传递。

以下代码可以解决问题:

brandes_betweenness_centrality(g,
            boost::centrality_map(v_centrality_map).edge_centrality_map(e_centrality_map).vertex_index_map(v_index));

我认为错误发生在brandes_betweenness_centrality尝试调用get(vertex_index,g)并失败listS图表。