使用boost graph library計算圖中點和邊的betweenness
阿新 • • 發佈:2019-02-13
專案中用到的東西,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; }