1. 程式人生 > >使用boost graph library計算圖中點和邊的betweenness

使用boost graph library計算圖中點和邊的betweenness

專案中用到的東西,betweenness是社交網路裡的概念。基於的思想是betweenness高的點和邊在網路中更重要。betweenness具體定義見這裡

搜了一下發現boost已經有實現,但是用起來也真是費了牛勁。模版類一不小心就寫錯,而且編譯出錯資訊完全看不出來什麼。

搜了文件和例子才算寫好了。。

下面是一個星狀圖的例子:

input:
0 1 1 // an edge from 0 to 1, weight 1
0 2 1
0 3 1
0 4 1
0 5 1
0 6 1
6 7 1
output:
edge centrality:
(0 1): 7
(0 2): 7
(0 3): 7
(0 4): 7
(0 5): 7
(0 6): 12
(6 7): 7
vertex centrality:
0: 20
1: 0
2: 0
3: 0
4: 0
5: 0
6: 6
7: 0

下面是程式碼:

程式碼中實現了對點的重新編碼,而且只需要修改一下圖的typedef就可以切換有向無向圖

#include <boost/config.hpp>
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <fstream>
#include <set>
#include <vector>
#include <cstdio>
#include <map>

#include <boost/graph/graph_traits.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/dijkstra_shortest_paths.hpp>
#include <boost/property_map/property_map.hpp>
#include <boost/format.hpp>

#include <boost/graph/graphviz.hpp>

//For clustering
#include <boost/graph/bc_clustering.hpp>
#include <boost/graph/iteration_macros.hpp>
#include <boost/property_tree/ptree.hpp>


using namespace boost;

typedef adjacency_list < listS, vecS, undirectedS,
    no_property, property < edge_weight_t, double > > graph_t;
typedef std::pair<int, int> Edge;
typedef boost::property_tree::ptree Properties;

int transformNode2Num(int node, std::map<int, int> &node2num, std::vector<int>& num2node) {
    std::map<int, int>::iterator it = node2num.find(node);
    if(it == node2num.end()) {
        num2node.push_back(node);
        node2num[node] = num2node.size() - 1;
        return num2node.size() - 1;
    } else {
        return it->second;
    }
}
void getGraphInfo(std::istream &in, std::vector<Edge>& graphEdges, std::vector<double> &weights,
        std::map<int, int> &node2num, std::vector<int>& num2node, bool NODIS = false) {
    std::string line;
    int from, to;
    double dis;
    int node_num = 0;
    while(std::getline(in, line)) {
        sscanf(line.c_str(), "%d%d%lf", &from, &to, &dis);
        if(NODIS) {
            dis = 1;
        }
        from = transformNode2Num(from, node2num, num2node);
        to = transformNode2Num(to, node2num, num2node);
        graphEdges.push_back(std::make_pair(from, to));
        weights.push_back(dis);
    }
}

void getoptions(int argc, char **argv, Properties & options) {
    const std::string opt_string = "i:o:Nh";
    int opt = -1;
    while((opt = getopt(argc, argv, opt_string.c_str())) != -1) {
        std::string key = std::string(1, char(opt));
        if(optarg == NULL) {
            options.put(key, NULL);
        } else {
            std::string val = optarg;
            options.put(key, val);
        }
    }
}
int printHelp() {
    std::cerr << "Usage: betweenness -i graph.in -o graph.dot [-N(set distance=1)]" << std::endl;
    return 256;
}
int main(int argc, char ** argv) {
    Properties options;
    getoptions(argc, argv, options);
    if(options.find("i") == options.not_found()
            || options.find("h") != options.not_found()) {
        return printHelp();
    }
    typedef graph_traits < graph_t >::vertex_descriptor vertex_descriptor;
    typedef graph_t::edge_descriptor edge_descriptor;;

    std::vector<Edge> graphEdges;
    std::vector<double> weights;
    std::map<int, int> node2num;
    std::vector<int> num2node;
    std::ifstream in(options.get<std::string>("i").c_str());
    bool NODIS = options.find("N") != options.not_found();
    getGraphInfo(in, graphEdges, weights, node2num, num2node, NODIS);
    graph_t g(graphEdges.begin(), graphEdges.end(), weights.begin(), num2node.size());

    // std::map used for convenient initialization
    typedef std::map<edge_descriptor, int> StdEdgeIndexMap;
    StdEdgeIndexMap my_e_index;
    // associative property map needed for iterator property map-wrapper
    typedef boost::associative_property_map< StdEdgeIndexMap > EdgeIndexMap;
    EdgeIndexMap e_index(my_e_index);

    // We use setS as edge-container -> no automatic indices
    // -> Create and set it explicitly
    int i = 0;
    BGL_FORALL_EDGES(edge, g, graph_t) {
        my_e_index.insert(std::pair< edge_descriptor, int >(edge, i));
        ++i;
    }

    // Define EdgeCentralityMap
    std::vector< double > e_centrality_vec(boost::num_edges(g), 0.0);
    // Create the external property map
    boost::iterator_property_map< std::vector< double >::iterator, EdgeIndexMap >
        e_centrality_map(e_centrality_vec.begin(), e_index);

    // Define VertexCentralityMap
    typedef boost::property_map< graph_t, boost::vertex_index_t>::type VertexIndexMap;
    VertexIndexMap v_index = get(boost::vertex_index, g);
    std::vector< double > v_centrality_vec(boost::num_vertices(g), 0.0);
    // Create the external property map
    boost::iterator_property_map< std::vector< double >::iterator, VertexIndexMap >
        v_centrality_map(v_centrality_vec.begin(), v_index);
    brandes_betweenness_centrality( g, v_centrality_map, e_centrality_map );
    {
        std::cout << "edge centrality:" << std::endl;
        BGL_FORALL_EDGES(edge, g, graph_t) {
            int from = num2node[ source(edge, g) ];
            int to = num2node[ target(edge, g) ];
            std::cout << boost::str(boost::format("(%d %d): %d") % from % to % e_centrality_map[edge]) << std::endl;
        }
        std::cout << "vertex centrality:" << std::endl;
        BGL_FORALL_VERTICES(vertix, g, graph_t) {
            std::cout << boost::str(boost::format("%d: %d") % num2node[vertix] % v_centrality_map[vertix]) << std::endl;
        }
    }
    //write graph in graphviz format
    property_map<graph_t, edge_weight_t>::type weightmap = get(edge_weight, g);
    {
        std::string dotfile = options.get<std::string>("o", "graph.dot");
        std::string filename(dotfile.c_str());
        std::ofstream os;
        os.open(filename.c_str());
        os << "digraph{" << std::endl;
        BGL_FORALL_VERTICES(vertix, g, graph_t) {
            os << boost::str(boost::format("%d[label=\"%d[%d]\"];") % num2node[vertix] % num2node[vertix] % v_centrality_map[vertix]) << std::endl;
        }
        BGL_FORALL_EDGES(edge, g, graph_t) {
            int from = num2node[ source(edge, g) ];
            int to = num2node[ target(edge, g) ];
            os << boost::str(boost::format("%d->%d[label=\"%.0lf[%.0lf]\"];") % from % to % get(weightmap, edge) % e_centrality_map[edge]) << std::endl;
        }
        os << "}" << std::endl;
        os.close();
    }
    return EXIT_SUCCESS;
}