influenceR/0000755000176200001440000000000014431373442012351 5ustar liggesusersinfluenceR/NAMESPACE0000644000176200001440000000026014431230301013550 0ustar liggesusers# Generated by roxygen2: do not edit by hand export(betweenness) export(bridging) export(constraint) export(csv.to.igraph) export(ens) export(keyplayer) useDynLib(influenceR) influenceR/README.md0000644000176200001440000000253714431251425013633 0ustar liggesusers# influenceR influenceR: Software tools to quantify structural importance of nodes in a network. Algorithms include Betweenness Centrality, Bridging, Constraint Index, Effective Network Size, and Key Players. Currently, algorithms are implemented only for undirected graphs; work on directed graphs is in progress. #### Installation The current release version can be found on CRAN and installed with: install.packages("influenceR") #### Citation If using this package, please cite Jacobs SD, Khanna AS (2015). *influenceR: Software tools to quantify structural importance of nodes in a network* R Package Version 1.0.0.5. URL https://github.com/khanna-lab/influenceR. #### Funding Development of this software package was supported by NIH grant R01 DA033875. [![R-CMD-check](https://github.com/khanna-lab/influenceR/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/khanna-lab/influenceR/actions/workflows/R-CMD-check.yaml) [![](http://cranlogs.r-pkg.org/badges/grand-total/influenceR)](https://cran.r-project.org/package=influenceR) [![CRAN_Status_Badge](http://www.r-pkg.org/badges/version/influenceR)](https://cran.r-project.org/package=influenceR) [![License: GPL v2](https://img.shields.io/badge/License-GPL%20v2-blue.svg)](https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html) influenceR/man/0000755000176200001440000000000014431200046013111 5ustar liggesusersinfluenceR/man/constraint.Rd0000644000176200001440000000126114431230302015562 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/graph_metrics.R \name{constraint} \alias{constraint} \title{Burt's Constraint Index.} \usage{ constraint(g, v = igraph::V(g)) } \arguments{ \item{g}{The igraph object to analyze.} \item{v}{vertices over which to compute constraint (default to all)} } \value{ A numeric vector with the constraint score for each vertex in v } \description{ The igraph package provides an implementation of Constraint; this is an alternate implementation. } \examples{ ig.ex <- igraph::erdos.renyi.game(100, p.or.m=0.3) # generate an undirected 'igraph' object constraint(ig.ex) # constraint scores for each node in the graph } influenceR/man/csv.to.igraph.Rd0000644000176200001440000000072214431230301016063 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/graph_metrics.R \name{csv.to.igraph} \alias{csv.to.igraph} \title{Convert a CSV file to an igraph graph object.} \usage{ csv.to.igraph(fname) } \arguments{ \item{fname}{A filename} } \value{ An igraph graph object built from the filename. } \description{ The first column should be sources, the second should be targets. } \examples{ \dontrun{ig.csv <- csv.to.igraph("edgelist.csv") } } influenceR/man/ens.Rd0000644000176200001440000000204014431230302014157 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/graph_metrics.R \name{ens} \alias{ens} \title{Burt's Effective Network Size and Constraint index. The next two functions below provide ways to measure the actors' access to structural holes in a network. Structural holes "provide opportunities to broker connections between people" (Burt 2008).} \usage{ ens(g) } \arguments{ \item{g}{The igraph object to analyze.} } \value{ A numeric vector with the effective network size for each vertex } \description{ Burt's Effective Network Size and Constraint index. The next two functions below provide ways to measure the actors' access to structural holes in a network. Structural holes "provide opportunities to broker connections between people" (Burt 2008). } \examples{ ig.ex <- igraph::erdos.renyi.game(100, p.or.m=0.3) # generate an undirected 'igraph' object ens(ig.ex) # Effective Network Size scores for each node in the graph } \references{ \url{https://www.sciencedirect.com/science/article/abs/pii/S0378873397000038} } influenceR/man/keyplayer.Rd0000644000176200001440000000627314431230302015413 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/graph_metrics.R \name{keyplayer} \alias{keyplayer} \title{Compute a KPP-Pos set for a given graph.} \usage{ keyplayer(g, k, prob = 0, tol = 1e-04, maxsec = 120, roundsec = 30) } \arguments{ \item{g}{The igraph object to analyze.} \item{k}{The size of the KP-set} \item{prob}{probability of accepting a state with a lower value} \item{tol}{tolerance within which to stop the optimization and accept the current value} \item{maxsec}{The total computation budget for the optimization, in seconds} \item{roundsec}{Number of seconds in between synchronizing workers' answer} } \value{ a vector with the vertex number of each vertex in the selected set S. } \description{ The "Key Player" family of node importance algorithms (Borgatti 2006) involves the selection of a metric of node importance and a combinatorial optimization strategy to choose the set S of vertices of size k that maximize that metric. } \details{ This function implements KPP-Pos, a metric intended to identify k nodes which optimize resource diffusion through the network. We sum over all vertices not in S the reciprocal of the shortest distance to a vertex in S. According to Borgatti, a number of off-the-shelf optimization algorithms may be suitable to find S, such as tabu-search, K-L, simulated annealing, or genetic algorithms. He presents a simple greedy algorithm, which we excerpt here: \enumerate{ \item Select k nodes at random to populate set S \item Set F = fit using appropriate key player metric. \item For each node u in S and each node v not in S: \itemize{\item DELTAF = improvement in fit if u and v were swapped} \item Select pair with largest DELTAF \itemize{ \item If DELTAF <= [tolerance] then terminate \item Else, swap pair with greatest improvement in fit and set F = F + DELTAF } \item Go to step 3. } Our implementation uses a different optimization method which we call stochastic gradient descent. In tests on real world data, we found that our method discovered sets S with larger fits in less computation time. The algorithm is as follows: \enumerate{ \item Select k nodes at random to populate set S \item Set F = fit using appropriate key player metric (KPP-Pos in our case) \item Get a new state: \itemize{ \item Pick a random u in S and v not in S. \item F' = fit if u and v were swapped \item If F' > F, swap u and v in S. Else, repeat step 3. (Alternatively, if a positive value is given for the `prob' parameter, a swap will be accepted with a small probability regardless of whether it improves the fit). } \item If F' - F < tolerance or our maximum computation time is exceeded, return S. Else, go to step 3. } This implementation uses OpenMP (if available on the host system) so that multiple workers can explore the solution space in parallel. After a given of time, the workers synchronize their sets S to the one which maximizes the metric. } \examples{ ig.ex <- igraph::erdos.renyi.game(100, p.or.m=0.3) # generate an undirected 'igraph' object keyplayer(ig.ex, k=10) # key-player set consisting of 10 actors } \references{ \url{https://link.springer.com/article/10.1007/s10588-006-7084-x} } influenceR/man/betweenness.Rd0000644000176200001440000000203514431236365015737 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/graph_metrics.R \name{betweenness} \alias{betweenness} \title{Vertex Betweenness centrality measure.} \usage{ betweenness(g, snap = T) } \arguments{ \item{g}{The igraph object to analyze} \item{snap}{True to use the SNAP betweenness code, False to use igraph::betweenness} } \value{ A numeric vector with the betweenness centrality score for each vertex } \description{ The Betweenness centrality score of a node u is the sum over all pairs s,t of the proportion of shortest paths between s and t that pass through u. This function allows the use of either the SNAP betweenness implementation (default), or the igraph betweenness function. The SNAP version makes use of OpenMP for parallelization, and may be faster in some circumstances. } \examples{ ig.ex <- igraph::erdos.renyi.game(100, p.or.m=0.3) # generate an undirected 'igraph' object betweenness(ig.ex) # betweenness scores for each node in the graph } \references{ \url{https://snap-graph.sourceforge.net/} } influenceR/man/influenceR.Rd0000644000176200001440000000211214431243721015475 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/influenceR.R \docType{package} \name{influenceR} \alias{influenceR} \title{influenceR: Software tools to quantify structural importance of nodes in a network.} \description{ The influenceR package includes functions to quantify the structural importance of nodes in a network. Algorithms include Betweenness Centrality, Bridging, Constraint Index, Effective Network Size, and Key Players. Currently, algorithms are only guaranteed to work on undirected graphs; work on directed graphs is in progress. These functions run on graph objects from the igraph package. } \details{ In addition to igraph, this package makes use of the SNAP framework for a high-performance graph data structure and an OpenMP-parallelized implementation of Betweenness Centrality. See \url{https://snap-graph.sourceforge.net} } \section{Funding}{ Development of this software package was supported by NIH grant R01 DA033875. } \section{References}{ The website and source code is located at \url{https://github.com/khanna-lab/influenceR}. } influenceR/man/bridging.Rd0000644000176200001440000000146014431236365015203 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/graph_metrics.R \name{bridging} \alias{bridging} \title{Valente's Bridging vertex measure.} \usage{ bridging(g) } \arguments{ \item{g}{The igraph object to analyze.} } \value{ A numeric vector with the bridging score for each vertex } \description{ Edges that reduces distances in a network are important structural bridges. Here we implement Valente and Fujimoto's metric, where a node's bridging score is the average decrease in cohesiveness if each of its edges were removed from the graph. } \examples{ ig.ex <- igraph::erdos.renyi.game(100, p.or.m=0.3) # generate an undirected 'igraph' object bridging(ig.ex) # bridging scores for each node in the graph } \references{ \url{https://www.ncbi.nlm.nih.gov/pmc/articles/PMC2889704/} } influenceR/DESCRIPTION0000644000176200001440000000236114431373442014061 0ustar liggesusersPackage: influenceR Title: Software Tools to Quantify Structural Importance of Nodes in a Network Version: 0.1.5 Author: Simon Jacobs [aut], Aditya Khanna [aut, cre], Kamesh Madduri [ctb], David Bader [ctb] Maintainer: Aditya Khanna Description: Provides functionality to compute various node centrality measures on networks. Included are functions to compute betweenness centrality (by utilizing Madduri and Bader's SNAP library), implementations of constraint and effective network size by Burt (2000) ; algorithm to identify key players by Borgatti (2006) ; and the bridging algorithm by Valente and Fujimoto (2010) . On Unix systems, the betweenness, Key Players, and bridging implementations are parallelized with OpenMP, which may run faster on systems which have OpenMP configured. Depends: R (>= 3.2.0) License: GPL-2 Imports: igraph (>= 1.0.1), Matrix (>= 1.1-4), methods, utils NeedsCompilation: yes Suggests: testthat URL: https://github.com/khanna-lab/influenceR RoxygenNote: 7.2.3 Packaged: 2023-05-17 22:29:21 UTC; adityakhanna Repository: CRAN Date/Publication: 2023-05-18 10:00:02 UTC influenceR/tests/0000755000176200001440000000000014431200046013500 5ustar liggesusersinfluenceR/tests/testthat/0000755000176200001440000000000014431373442015353 5ustar liggesusersinfluenceR/tests/testthat/test_metrics.R0000755000176200001440000000063214431200046020174 0ustar liggesuserslibrary(testthat) context("tests") load("flo_results.RData") test_that("metrics work as expected", { expect_less_than(sum(abs(influenceR::betweenness(flo_graph) - flo_bet)), 0.1) # some instability in betweenness results expect_equal(influenceR::ens(flo_graph), flo_ens) expect_equal(influenceR::constraint(flo_graph), flo_constraint) expect_equal(influenceR::bridging(flo_graph), flo_bridge) }) influenceR/tests/testthat/test_reference.R0000644000176200001440000000330314431250756020474 0ustar liggesuserslibrary(testthat) load("flo_results.RData") context("ref-tests") ens_test <- function(g) { ens <- vector("numeric", length(igraph::V(g))) for (i in igraph::V(g)) { s <- 0 ni <- igraph::neighbors(g, i) di <- igraph::degree(g, i) for (j in ni) { t <- 0 Q <- igraph::intersection(ni, igraph::neighbors(g, j)) for (q in Q) { t <- t + 1/di } s <- s + 1 - t } ens[i] <- s } ens } bridge_test <- function(g) { n <- length(igraph::V(g)) cohesion <- function(g) { D <- igraph::distances(g) Dr <- 1/D Dr[Dr==Inf] <- 0 s <- sum(Dr) s/(n*(n-1)) } C <- cohesion(g) bridge <- NULL for (v in igraph::V(g)) { edges <- igraph::incident(g, v) s <- 0 for (e in edges) { eset <- igraph::E(g)[igraph::E(g) != e] g_ <- igraph::subgraph.edges(g, eset) C_ <- cohesion(g_) s <- s + (C - C_) } bridge <- c(bridge, s) } bridge / (2*igraph::degree(g)) } test_that("ens matches reference function", { expect_equal(influenceR::ens(flo_graph), ens_test(flo_graph)) }) test_that("influenceR::constraint matches igraph", { ig_constraint <- igraph::constraint(flo_graph) ig_constraint[is.nan(ig_constraint)] <- 0 expect_less_than(sum(abs(influenceR::constraint(flo_graph) - ig_constraint)), 0.1) }) test_that("influenceR::betweenness is 2x igraph version", { expect_less_than(sum(abs(influenceR::betweenness(flo_graph) - 2*igraph::betweenness(flo_graph))), 0.0001) }) test_that("bridging matches reference function", { flo_bridge <- bridge_test(flo_graph) flo_bridge[is.nan(flo_bridge)] <- 0 expect_less_than(sum(abs(influenceR::bridging(flo_graph) - flo_bridge)), 0.0001) })influenceR/tests/testthat/flo_results.RData0000644000176200001440000000161114431200046020615 0ustar liggesuserskHSaǏs` /(d,Q8 Rۗ}ylv60 BS.4/F WPTbeB3X(jܶqOHTMtKǕh3Ks"<7o+H?O\uڗR߫\E޺wG sSQ@FZrYuW4OȍVv ysVH}Zɣ7%,s;cIƶwowxS4.U[F*Σp8yA#"acFDF,XJτ5uIEyvͧI/5@z{TdUmkq햫Ds{`[qި  5jI/$MQA'&ؚF☩߲) %vglP`1 o f<**摼@slJ7J 2LJi:̥}l`= q űϋcޤPT_|K\_GUC5ѺD8p#& ) U,JHUh4U3^?y8?,ZyNr q^x -\- n.<|!U#e9ZU03.\ȂJ\̻__q TNu-%fĬįB_ #include #include #include #include #include #include #ifdef _OPENMP #undef match #include #define match Rf_match #define OMP(x) _Pragma(x) #else #define OMP(x) #endif #if ENABLE_64BIT_VID typedef long attr_id_t; #else typedef int attr_id_t; #endif #define ARRAY_INIT_SIZE 8 #if !HAVE_LOG2 #ifndef log2 #define log2(d) (log(d)/log(2.0)) #endif #endif typedef struct { attr_id_t* vals; attr_id_t* aux_info; long count; long max_size; } dyn_array_t; typedef struct { /* value is the key */ attr_id_t *vals; attr_id_t count; attr_id_t max_size; } adj_bheap_t; typedef struct { attr_id_t dest; attr_id_t eid; attr_id_t mask; double cval; } c_edge_t; typedef struct { attr_id_t num_edges; attr_id_t comm_id; } c_vert_t; typedef struct { attr_id_t p; double a; double e; attr_id_t mbc_eid; double mbc_val; attr_id_t mbc_esrc; } comm_list_bc_t; typedef struct { attr_id_t src; attr_id_t dest; attr_id_t eid; } edge_t; typedef struct { dyn_array_t* neighbors; attr_id_t degree; } vert_t; typedef struct { attr_id_t* list; attr_id_t count; attr_id_t degree; } plist_t; typedef struct struct_node { int id; int aux_val; struct struct_node *next; } node_t; typedef struct { node_t *head; node_t *tail; int size; } list_t; /* The graph data structure*/ typedef struct { /*** The minimal graph repesentation consists of: n -- the number of vertices m -- the number of edges endV -- an array of size 2*m (m for directed graphs) that stores the destination ID of an edge dest>. numEdges -- an array of size n+1 that stores the degree (out-degree in case of directed graphs) and pointers to the endV array. The degree of vertex i is given by numEdges[i+1]-numEdges[i], and the edges out of i are stored in the contiguous block endV[numEdges[i] .. numEdges[i+1]]. Vertices are ordered from 0 in our internal representation ***/ long n; long m; attr_id_t* endV; attr_id_t* numEdges; int undirected; int zero_indexed; /*** Other useful constructs that can be initialized when needed ***/ edge_t* elist; edge_t* elist_aux; vert_t* vlist; vert_t* vlist_aux; /* An internal id for each edge, useful in case of undirected networks */ attr_id_t* edge_id; /* For directed graphs, endBackV can be used to store edges pointing into a vertex, and numBackEdges the in-degree */ attr_id_t* endBackV; attr_id_t* numBackEdges; /* Data representation used in some centrality and community identification * routines */ c_vert_t* cvl; c_edge_t* cel; /* Vertex weights */ int* int_weight_v; float* fl_weight_v; double* dbl_weight_v; long* l_weight_v; /* Edge weights */ int weight_type; int* int_weight_e; float* fl_weight_e; double* dbl_weight_e; long* l_weight_e; double min_weight; double max_weight; /* Fine-grained locking support, currently using OpenMP mutex locks */ #ifdef _OPENMP omp_lock_t* vLock; omp_lock_t* eLock; #endif } graph_t; #endif influenceR/src/bridging.c0000755000176200001440000003006314431200046015063 0ustar liggesusers/* bridging.c: Implementation of the bridging centrality metric See also: http://www.ncbi.nlm.nih.gov/pmc/articles/PMC2889704/ AUTHOR: Simon Jacobs LICENSE: GPLv2 Bridging can be parallelized with the following method, given a graph G: for each edge e in parallel: compute cohesiveness of G\e for each vertex v in parallel: compute average cohesiveness of E(v) OpenMP parallelization is available. Compile with OpenMP flags (usually "-fopenmp"). Parallelization with MPI is experimental and will not compile by default. In order to compile with MPI: * an MPI implementation, such as OpenMPI, must be installed on your system * compile with the -DUSE_MPI flag, and use the mpicc compiler. Then,use the MPI function by starting R with "mpirun -n 1 R", load the Rmpi and snow packages, and use the following code (assuming an igraph object `g'): el <- get.edgelist(g, names=F) el_i <- as.integer(t(el)) n <- as.integer(max(el_i)) m <- as.integer(length(el_i)/2) np <- mpi.universe.size() - 1 cl <- makeMPIcluster(np) x <- clusterApply(cl, 0:(np-1), function(rank, el_i, n, m) { library(influenceR) .Call("snap_bridging_R", el_i, n, m, as.integer(TRUE), as.integer(rank), PACKAGE="influenceR") }, el_i, n, m) # ensure these values are exported. stopCluster(cl) mpi.exit() bridging_values = x[1] names(bridging_values) <- V(g)$name */ #include #include #include "graph_defs.h" #ifdef USE_MPI #include #endif double bridging_vertex_precomp(graph_t *G, long v, double cls, double *closeness); double *main_bridging(graph_t *G, int *edgelist, double *scores); double closeness(graph_t *G, long ignore_edge0, long ignore_edge1); long BFS_parallel_frontier_expansion_bridging(graph_t* G, long src, long diameter, double *distance, long ignore_edge0, long ignore_edge1 ); double *bridging(graph_t *G, int *edgelist, double *scores) { int n = G->n; /* number of nodes */ int m = G->m; /* number of edges */ long u, v, j, k; /* 1) compute closeness by edge in file */ double *closeness_by_edge = (double *) R_alloc(m, sizeof(double)); #ifdef _OPENMP #pragma omp parallel for private(u, v, j, k) #endif for (int i = 0; i < m/2; i++) { u = edgelist[i*2] - 1; v = edgelist[i*2+1] - 1; /* Find edge numbers */ for (j=G->numEdges[u]; v != G->endV[j] && jnumEdges[u+1]; j++); for (k=G->numEdges[v]; u != G->endV[k] && knumEdges[v+1]; k++); assert(j != G->numEdges[u+1]); assert(k != G->numEdges[v+1]); /* Calculate closeness */ double c = closeness(G, j, k); closeness_by_edge[j] = c; closeness_by_edge[k] = c; } /* 2) Compute closeness by vertex */ double cls = closeness(G, -1, -1); // normal closeness (use all edges) #ifdef _OPENMP #pragma omp parallel for private(v) #endif for (v = 0; v < n; v++) scores[v] = bridging_vertex_precomp(G, v, cls, closeness_by_edge); return scores; } #ifdef USE_MPI double *bridging_MPI(graph_t *G, int *edgelist, double *scores) { // Get the number of processes int size, rank; MPI_Comm_size(MPI_COMM_WORLD, &size); MPI_Comm_rank(MPI_COMM_WORLD, &rank); #ifdef VERBOSE REprintf("hello from main_brdiging, process %d\n", rank); #endif int n = G->n; /* number of nodes */ int m = G->m; /* number of edges */ /* 1) compute closeness by edge in file */ int bufsize = ceil(((double)m) / size), delta = bufsize/2; int start = rank * delta, end = start + delta; end = end > m/2 ? m/2 : end; #ifdef VERBOSE REprintf("%d range: %d-%d\n", rank, start, end); #endif double *buf = (double *) R_alloc(bufsize, sizeof(double)); int *edgeidx = (int *) R_alloc(bufsize, sizeof(int)); assert(buf); assert(edgeidx); int i=0, u, v; long j, k; for (int ii = start; ii < end; ii++) { u = edgelist[ii*2] - 1; v = edgelist[ii*2+1] - 1; /* Find edge numbers */ for (j=G->numEdges[u]; v != G->endV[j] && jnumEdges[u+1]; j++); for (k=G->numEdges[v]; u != G->endV[k] && knumEdges[v+1]; k++); assert(j != G->numEdges[u+1]); assert(k != G->numEdges[v+1]); /* Calculate closeness */ buf[i] = closeness(G, j, k); edgeidx[i] = j; buf[i+1] = buf[i]; edgeidx[i+1] = k; i+=2; //fprintf(stderr, "%d: CBE %d %d %g\n", rank, j, k, buf[i]); } #ifdef VERBOSE REprintf("Rank %d done reading edges\n", rank); #endif double *closeness_buf = NULL; int *edge_indices = NULL; if (rank == 0) { closeness_buf = (double *) R_alloc(bufsize*size, sizeof(double)); edge_indices = (int *) R_alloc(bufsize*size, sizeof(int)); } MPI_Barrier(MPI_COMM_WORLD); MPI_Gather(buf, bufsize, MPI_DOUBLE, closeness_buf, bufsize, MPI_DOUBLE, 0, MPI_COMM_WORLD); MPI_Gather(edgeidx, bufsize, MPI_INT, edge_indices, bufsize, MPI_INT, 0, MPI_COMM_WORLD); double *closeness_by_edge = (double *) R_alloc(m, sizeof(double)); /* Fill REAL closeness_by_edge matrix */ if (rank == 0) { for (int i = 0; i < m; i++) { closeness_by_edge[edge_indices[i]] = closeness_buf[i]; #ifdef VERBOSE REprintf("CBE %d %g\n", edge_indices[i], closeness_buf[i]); #endif } //free(closeness_buf); //free(edge_indices); } MPI_Barrier(MPI_COMM_WORLD); MPI_Bcast(closeness_by_edge, m, MPI_DOUBLE, 0, MPI_COMM_WORLD); //free(buf); //free(edgeidx); /* 2) compute bridging score by NODE. Parallization here may be more trouble than it's worth. But we already have the resources. */ delta = ceil(((double)n) / size); start = rank * delta, end = start + delta; end = end > n ? n : end; double cls = closeness(G, -1, -1); // normal closeness (use all edges) buf = (double *) R_alloc(delta, sizeof(double)); for (int v = start; v < end; v++) buf[v-start] = bridging_vertex_precomp(G, v, cls, closeness_by_edge); MPI_Gather(buf, delta, MPI_DOUBLE, scores, delta, MPI_DOUBLE, 0, MPI_COMM_WORLD); MPI_Barrier(MPI_COMM_WORLD); return scores; } #endif double bridging_vertex_precomp(graph_t *G, long v, double cls, double *closeness) { int degree = 0; double sum = 0; for (long j=G->numEdges[v]; jnumEdges[v+1]; j++) { double cls_ = closeness[j]; sum += cls - cls_; degree++; } if (degree == 0) return 0; return sum/((double) degree); } // Two edges correspond to the same edge. double closeness(graph_t *G, long ignore_edge0, long ignore_edge1) { int n = G->n; // Must be thread-safe for OpenMP. R_alloc is not thread-safe. double *distance = (double *) malloc(sizeof(double) * n); if (distance == NULL) { REprintf("Ran out of memory"); } double sum = 0; for (int i = 0; i < n; i++) { /* memset */ for (int j = 0; j < n; j++) distance[j] = INFINITY; BFS_parallel_frontier_expansion_bridging(G, i, 75, distance, ignore_edge0, ignore_edge1); for (int j = 0; j < i; j++) { /* sum upper triangular part */ sum += (1/distance[j]); } } free(distance); return sum / (n*n - n); } /* * OpenMP is disabled because we're parallelizing over graph edges and computing multiple BFS at once. * To enable, set the following macro directive: * DEFINE _OPENMP_BRIDGING _OPENMP * */ long BFS_parallel_frontier_expansion_bridging(graph_t* G, long src, long diameter, double *distance, long ignore_edge0, long ignore_edge1 ) { attr_id_t* S; long *start; char* visited; long *pSCount; #ifdef DIAGNOSTIC double elapsed_time; #endif #ifdef _OPENMP_BRIDGING omp_lock_t* vLock; #endif long phase_num, numPhases; long count; #ifdef _OPENMP_BRIDGING OMP("omp parallel") { #endif attr_id_t *pS, *pSt; long pCount, pS_size; long v, w; int tid, nthreads; long start_iter, end_iter; long j, k, vert, n; #ifdef _OPENMP_BRIDGING int myLock; #endif #ifdef _OPENMP_BRIDGING long i; tid = omp_get_thread_num(); nthreads = omp_get_num_threads(); #else tid = 0; nthreads = 1; #endif #ifdef DIAGNOSTIC if (tid == 0) elapsed_time = get_seconds(); #endif if (tid == 0) numPhases = diameter + 1; n = G->n; pS_size = n/nthreads + 1; pS = (attr_id_t *) malloc(pS_size*sizeof(attr_id_t)); assert(pS != NULL); if (tid == 0) { S = (attr_id_t *) malloc(n*sizeof(attr_id_t)); visited = (char *) calloc(n, sizeof(char)); start = (long *) calloc((numPhases+2), sizeof(long)); pSCount = (long *) malloc((nthreads+1)*sizeof(long)); #ifdef _OPENMP_BRIDGING vLock = (omp_lock_t *) malloc(n*sizeof(omp_lock_t)); #endif } #ifdef _OPENMP_BRIDGING OMP("omp barrier") OMP("omp for") for (i=0; i 0) { pCount = 0; start_iter = start[phase_num]; end_iter = start[phase_num+1]; #ifdef _OPENMP_BRIDGING OMP("omp for") #endif for (vert=start_iter; vertnumEdges[v]; jnumEdges[v+1]; j++) { if(j == ignore_edge0 || j == ignore_edge1) { continue; } w = G->endV[j]; if (v == w) continue; #ifdef _OPENMP_BRIDGING myLock = omp_test_lock(&vLock[w]); if (myLock) { #endif if (visited[w] != (char) 1) { distance[w] = distance[v] + 1; visited[w] = (char) 1; if (pCount == pS_size) { /* Resize pS */ pSt = (attr_id_t *) malloc(2*pS_size*sizeof(attr_id_t)); memcpy(pSt, pS, pS_size*sizeof(attr_id_t)); free(pS); pS = pSt; pS_size = 2*pS_size; } pS[pCount++] = w; } #ifdef _OPENMP_BRIDGING omp_unset_lock(&vLock[w]); } #endif } } #ifdef _OPENMP_BRIDGING OMP("omp barrier") #endif pSCount[tid+1] = pCount; #ifdef _OPENMP_BRIDGING OMP("omp barrier") #endif if (tid == 0) { pSCount[0] = start[phase_num+1]; for(k=1; k<=nthreads; k++) { pSCount[k] = pSCount[k-1] + pSCount[k]; } start[phase_num+2] = pSCount[nthreads]; count = pSCount[nthreads]; phase_num++; } #ifdef _OPENMP_BRIDGING OMP("omp barrier") #endif for (k = pSCount[tid]; k < pSCount[tid+1]; k++) { S[k] = pS[k-pSCount[tid]]; } #ifdef _OPENMP_BRIDGING OMP("omp barrier") #endif } /* End of search */ #ifdef DIAGNOSTIC if (tid == 0) { REPrintf("Search from vertex %ld," " No. of vertices visited: %ld\n", src, count); } #endif free(pS); #ifdef _OPENMP_BRIDGING OMP("omp barrier") OMP("omp for") for (i=0; i LICENSE: GPLv2 */ #include #include double * process_sparse(int *I, int *J, double *X, double *Ai, double *deg, int n, double *out) { for(int p = 0; p < n; p++) { int j = J[p]; int i = I[p]; out[p] = X[p] * Ai[j] * Ai[i] * deg[j]; //out[p] = (out[p] == 0 ? 0 : 1/out[p]); } return out; } SEXP process_sparse_R(SEXP sI, SEXP sJ, SEXP sX, SEXP sAi, SEXP sdeg, SEXP sn) { int n = INTEGER(sn)[0]; SEXP sres = PROTECT(allocVector(REALSXP, n)); /*Coerce inputs*/ int *I = INTEGER(sI), *J = INTEGER(sJ); double *X = REAL(sX), *Ai = REAL(sAi), *deg = REAL(sdeg), *res = REAL(sres); process_sparse(I, J, X, Ai, deg, n, res); UNPROTECT(1); return sres; } influenceR/src/process_sparse.h0000644000176200001440000000030214431200046016324 0ustar liggesusers/* Header file for process_sparse.c */ #include #ifndef PROCESS_SPARSE_H #define PROCESS_SPARSE_H SEXP process_sparse_R(SEXP sI, SEXP sJ, SEXP sX, SEXP sAi, SEXP sdeg, SEXP sn) #endif influenceR/src/keyplayer.c0000755000176200001440000000750114431200046015304 0ustar liggesusers/* keyplayer.c: Key Player implementation See also: http://www.bebr.ufl.edu/sites/default/files/Borgatti%20-%202006%20-%20Identifying%20sets%20of%20key%20players%20in%20a%20social%20networ.pdf AUTHOR: Simon Jacobs LICENSE: GPLv2 Implementation of optimization part of Key Player algorithm. Includes a version parallelized with OpenMP. */ #include #include #include #include #include "graph_defs.h" #include "keyplayer-utils.h" /* single core version: compute better solutions for T seconds */ /* Return code: * 0 if converges * 1 if does not converge */ int keyplayer_driver(graph_t *g, int n, int k, double p, double tol, long maxsec, int *KP) { int np, rank, new_rank = 0, stop; double *fits; int *allsets; time_t start; GetRNGstate(); // rather than srand problem_t problem; problem.graph = g; problem.distance = NULL; problem.round = 0; double fit, oldfit=-1; int ret = 1; int s[n]; gen_starting_set(n, k, s); start = time(0); do { int u, v; fit = get_next_state_graph(&problem, n, s, k, p, &u, &v, 0); if (u >= 0) s[u] = 0; if (v >= 0) s[v] = 1; if (fit - oldfit < tol) { ret = 0; break; } oldfit = fit; } while(difftime(time(0), start) < maxsec); for (int i = 0; i < n; i++) KP[i] = s[i]; PutRNGstate(); return ret; } /* While we're working: * compute better solutions for T seconds * send my fit back to the master process. * get a number back. if it's my rank, broadcast my s array to everyone! */ int keyplayer_driver_omp(graph_t *g, int n, int k, double p, double tol, long maxsec, long sec, int *KP) { #ifndef _OPENMP int ret = keyplayer_driver(g, n, k, p, tol, maxsec, KP); #else int np, rank, new_rank = 0, stop; double *fits; int *allsets; time_t start, fullstart; int ret = 1; #pragma omp parallel shared(fits, allsets, new_rank, g, np, stop) private(rank, start, fullstart) { GetRNGstate(); // instead of srand np = omp_get_num_threads(); rank = omp_get_thread_num(); if (rank == 0) { allsets = (int *) R_alloc(n * np, sizeof(int)); fits = (double *) R_alloc(np, sizeof(double)); } problem_t problem; problem.graph = g; problem.distance = NULL; problem.round = 0; #pragma omp barrier int *s = &allsets[rank * n]; gen_starting_set(n, k, s); start = time(0), fullstart = start; double *fit = &fits[rank]; *fit = 0; double oldfit = -1; int run = 0; do { start = time(0); do { int u, v; *fit = get_next_state_graph(&problem, n, s, k, p, &u, &v, run); if (u >= 0) s[u] = 0; if (v >= 0) s[v] = 1; if (*fit - oldfit < tol) { ret = 0; break; } oldfit = *fit; } while(difftime(time(0), start) < sec); //printf("Run %d, rank %d, fit %g\n", run, rank, *fit); new_rank = 0; #pragma omp barrier /* Master process: find best fit. */ if (rank == 0) { double max = 0; for (int i = 0; i < np; i++) { //printf("Run %d, rank %d, fit %g\n", run, i, fits[i]); if (fits[i] > max) { max = fits[i]; new_rank = i; } } if (max - oldfit < tol || (difftime(time(0), fullstart) > maxsec)) { stop = 1; } oldfit = max; } #pragma omp barrier /* update s, or send it */ if (rank != new_rank) { int *best_s = &allsets[n * new_rank]; for (int i = 0; i < n; i++) s[i] = best_s[i]; } run++; #pragma omp barrier } while(!stop); } int *s = &allsets[0]; // s set for rank 0, which contains the best (as do all &allsets[i*n]) for (int i = 0; i < n; i++) KP[i] = s[i]; PutRNGstate(); #endif return ret; } influenceR/src/vertex_betweenness_centrality.h0000644000176200001440000000077514431200046021464 0ustar liggesusers/* AUTHOR: D.A. Bader and K. Madduri LICENSE: GPLv2 See: http://snap-graph.sourceforge.net/ Renamed from `graph_metrics.h' (and removed other functions) Header file for vertex_betweenness_centrality.c */ #ifndef _GRAPH_METRICS_H #define _GRAPH_METRICS_H void vertex_betweenness_centrality(graph_t* G, double* BC, long numSrcs); void vertex_betweenness_centrality_simple(graph_t* G, double* BC, long numSrcs); void vertex_betweenness_centrality_parBFS(graph_t* G, double* BC, long numSrcs); #endif influenceR/src/snap_wrapper.c0000755000176200001440000001407114431200046016000 0ustar liggesusers/* snap_wrapper.c: Interface R code to C code that utilizes SNAP data structures. AUTHOR: Simon Jacobs LICENSE: GPLv2 */ #include "graph_defs.h" #include "bridging.h" #include "keyplayer.h" #include "vertex_betweenness_centrality.h" #include #include /* Adapted from SNAP code by D.A. Bader and K. Madduri */ int read_graph_from_edgelist(graph_t* G, int *EL, long n, long m) { long i; long count, offset; int int_wt=1, *int_weight; // maybe some graphs have weights. long u, v; attr_id_t *src; attr_id_t *dest; attr_id_t *degree; // R will free this memory on return from .Call // see: http://cran.r-project.org/doc/manuals/r-release/R-exts.html#Memory-allocation src = (attr_id_t *) R_alloc (m, sizeof(attr_id_t)); dest = (attr_id_t *) R_alloc(m, sizeof(attr_id_t)); degree = (attr_id_t *) R_alloc(n, sizeof(attr_id_t)); for (int i = 0; i < n; i++) degree[i] = 0; for (int i = 0; i < m; i++) { src[i] = 0; dest[i] = 0; } assert(src != NULL); assert(dest != NULL); assert(degree != NULL); int_weight = (int *) R_alloc(m, sizeof(int)); assert(int_weight != NULL); for (int i = 0; i < m; i++) int_weight[i] = 0; count = 0; for (int i = 0; i < m; i++) { u = EL[2*i]; v = EL[2*i+1]; if ((u <= 0) || (u > n) || (v <= 0) || (v > n)) { REprintf("Error reading edge # %ld (%ld, %ld) in the input file." " Please check the input graph file.\n", count+1, u, v); return 1; } src[count] = u-1; dest[count] = v-1; degree[u-1]++; degree[v-1]++; int_weight[count] = int_wt; count++; } if (count != m) { REprintf("Error! Number of edges specified in problem line (%ld)" " does not match the total number of edges (%ld) in file." " Please check" " the graph input file.\n", m, count); return 1; } /* for (i=0; iendV = (attr_id_t *) R_alloc(2*m, sizeof(attr_id_t)); //calloc assert(G->endV != NULL); for (int i = 0; i < 2*m; i++) G->endV[i] = 0; G->edge_id = (attr_id_t *) R_alloc(2*m, sizeof(attr_id_t)); //calloc assert(G->edge_id != NULL); for (int i = 0; i < 2*m; i++) G->edge_id[i] = 0; G->numEdges = (attr_id_t *) R_alloc((n+1), sizeof(attr_id_t)); assert(G->numEdges != NULL); for (int i = 0; i < n+1; i++) G->numEdges[i] = 0; G->undirected = 1; G->weight_type = 1; G->zero_indexed = 0; G->n = n; G->m = 2*m; G->int_weight_e = (int *) R_alloc(G->m, sizeof(int)); assert(G->int_weight_e != NULL); for (int i = 0; i < G->m; i++) G->int_weight_e[i] = 0; /* ToDo: parallelize this step */ G->numEdges[0] = 0; for (i=1; i<=G->n; i++) { G->numEdges[i] = G->numEdges[i-1] + degree[i-1]; } for (i=0; iendV[G->numEdges[u]+offset-1] = v; G->int_weight_e[G->numEdges[u]+offset-1] = int_weight[i]; G->edge_id[G->numEdges[u]+offset-1] = i; offset = degree[v]--; G->endV[G->numEdges[v]+offset-1] = u; G->int_weight_e[G->numEdges[v]+offset-1] = int_weight[i]; G->edge_id[G->numEdges[v]+offset-1] = i; } /* for (i=0; in; i++) { for (j=G->numEdges[i]; jnumEdges[i+1]; j++) { fprintf(stderr, "<%ld %ld %d> ", i+1, G->endV[j]+1, G->int_weight_e[j]); } } */ // No need to free code allocated with R_alloc //free(buf); //free(degree); //free(src); //free(dest); return 0; } int snap_betweenness(int *E, long n, long m, double *BC) { graph_t G; int r = read_graph_from_edgelist(&G, E, n, m); if (r) { REprintf("Error reading graph from edgelist\n"); return 1; } vertex_betweenness_centrality(&G, BC, n); return 0; } SEXP snap_betweenness_R(SEXP sE, SEXP sn, SEXP sm) { int n = INTEGER(sn)[0], m = INTEGER(sm)[0]; SEXP sBC = PROTECT(allocVector(REALSXP, n)); int *E = INTEGER(sE); double *BC = REAL(sBC); memset(BC, 0, n * sizeof(double)); snap_betweenness(E, n, m, BC); UNPROTECT(1); return sBC; } SEXP snap_keyplayer_R(SEXP sE, SEXP sn, SEXP sm, SEXP sk, SEXP sprob, SEXP stol, SEXP sMaxsec, SEXP sRoundsec, SEXP cvg) { int n = INTEGER(sn)[0], m = INTEGER(sm)[0], k = INTEGER(sk)[0]; double prob = REAL(sprob)[0], tol = REAL(stol)[0]; long maxsec = INTEGER(sMaxsec)[0], roundsec = INTEGER(sRoundsec)[0]; int *E = INTEGER(sE); graph_t G; int r = read_graph_from_edgelist(&G, E, n, m); SEXP sKP = PROTECT(allocVector(INTSXP, n)); int *KP = INTEGER(sKP); #ifdef _OPENMP int ret = keyplayer_driver_omp(&G, n, k, prob, tol, maxsec, roundsec, KP); #else int ret = keyplayer_driver(&G, n, k, prob, tol, maxsec, KP); #endif /* did it converge? */ INTEGER(cvg)[0] = ret; UNPROTECT(1); return sKP; } /* Rank is rank if this is an MPI call, 0 else */ SEXP snap_bridging_R(SEXP sE, SEXP sn, SEXP sm, SEXP sMPI, SEXP srank) { int n = INTEGER(sn)[0], m = INTEGER(sm)[0], rank = INTEGER(srank)[0], mpi = INTEGER(sMPI)[0]; // use mpi? int *E = INTEGER(sE); graph_t G; int r = read_graph_from_edgelist(&G, E, n, m); SEXP sBC = PROTECT(allocVector(REALSXP, rank==0 ? n : 0)); if (rank == 0) { //sBC = PROTECT(allocVector(REALSXP, n)); #ifdef VERBOSE Rprintf("Rank %d: allocated memory for %d doubles\n", rank, n); #endif if (REAL(sBC) == NULL) { REprintf("Rank %d: error!\n", rank); UNPROTECT(1); return NULL; } } else { Rprintf("Rank %d: Did not allocate memory\n", rank); } double *BC = REAL(sBC); #ifdef USE_MPI if (mpi != 0) bridging_MPI(&G, E, BC); else bridging(&G, E, BC); #else bridging(&G, E, BC); #endif UNPROTECT(1); return sBC; } influenceR/src/Makevars0000755000176200001440000000010714431200046014622 0ustar liggesusersPKG_CFLAGS = $(SHLIB_OPENMP_CFLAGS) PKG_LIBS = $(SHLIB_OPENMP_CFLAGS) influenceR/src/vertex_betweenness_centrality.c0000644000176200001440000005465214431200046021462 0ustar liggesusers/* AUTHOR: D.A. Bader and K. Madduri LICENSE: GPLv2 See: http://snap-graph.sourceforge.net/ This has been modified to use R print functions and random number generation. */ #include "graph_defs.h" #include "vertex_betweenness_centrality.h" #include "prefix_sums.h" /* The following macros allow the use of R print functions and RNG functions without major changes to the SNAP code. Specifically, fprintf is replaced by REprintf, and calls to sprng library are replaced by GetRNGstate, PutRNGstate, and unif_rand. Known issue: R RNG is not intended to be used by multithreaded code. If OpenMP is available, all threads will use the same random number stream (with RNG state protected by a lock). This is not optimal. This may be addressed in future with calls to the rlecuyer package (see https://cran.r-project.org/package=rlecuyer). */ #include #define SPRNG_DEFAULT 0 #ifdef _OPENMP #define init_sprng(a, b, c, d, e) NULL; omp_set_lock(&rnglock); GetRNGstate(); omp_unset_lock(&rnglock) #define free_sprng(a) omp_set_lock(&rnglock); PutRNGstate(); omp_unset_lock(&rnglock) #else #define init_sprng(a, b, c, d, e) NULL; GetRNGstate() #define free_sprng(a) PutRNGstate() #endif #define sprng(a) unif_rand() #define fprintf(a, ...) REprintf(__VA_ARGS__) #define exit(x) error("SNAP code exited with error: %d\n", x) void vertex_betweenness_centrality_parBFS(graph_t* G, double* BC, long numSrcs) { #ifdef _OPENMP omp_lock_t rnglock; omp_init_lock(&rnglock); #endif attr_id_t *S; /* stack of vertices in the order of non-decreasing distance from s. Also used to implicitly represent the BFS queue */ plist_t* P; /* predecessors of a vertex v on shortest paths from s */ double* sig; /* No. of shortest paths */ attr_id_t* d; /* Length of the shortest path between every pair */ double* del; /* dependency of vertices */ attr_id_t *in_degree, *numEdges, *pSums; attr_id_t* pListMem; #if RANDSRCS attr_id_t* Srcs; #endif attr_id_t *start, *end; long MAX_NUM_PHASES; attr_id_t *psCount; #ifdef _OPENMP omp_lock_t* vLock; long chunkSize; #endif #ifdef DIAGNOSTIC double elapsed_time; #endif int seed = 2387; #ifdef _OPENMP OMP("omp parallel firstprivate(G)") { #endif attr_id_t *myS, *myS_t; attr_id_t myS_size; long i, j, k, p, count, myCount; long v, w, vert; long k0, k1; long numV, num_traversals, n, m, phase_num; long start_iter, end_iter; long tid, nthreads; int* stream; #ifdef DIAGNOSTIC double elapsed_time_part; #endif #ifdef _OPENMP int myLock; tid = omp_get_thread_num(); nthreads = omp_get_num_threads(); #else tid = 0; nthreads = 1; #endif #ifdef DIAGNOSTIC if (tid == 0) { elapsed_time = get_seconds(); elapsed_time_part = get_seconds(); } #endif /* numV: no. of vertices to run BFS from = numSrcs */ numV = numSrcs; n = G->n; m = G->m; /* Permute vertices */ if (tid == 0) { #if RANDSRCS Srcs = (attr_id_t *) malloc(n*sizeof(attr_id_t)); #endif #ifdef _OPENMP vLock = (omp_lock_t *) malloc(n*sizeof(omp_lock_t)); #endif } #ifdef _OPENMP OMP("omp barrier") OMP("omp for") for (i=0; iendV[i]; #ifdef _OPENMP omp_set_lock(&vLock[v]); #endif in_degree[v]++; #ifdef _OPENMP omp_unset_lock(&vLock[v]); #endif } prefix_sums(in_degree, numEdges, pSums, n); if (tid == 0) { pListMem = (attr_id_t *) malloc(m*sizeof(attr_id_t)); } #ifdef _OPENMP OMP("omp barrier") OMP("omp for") #endif for (i=0; inumEdges[i+1] - G->numEdges[i] == 0) { continue; } else { num_traversals++; } if (num_traversals == numV + 1) { break; } if (tid == 0) { sig[i] = 1; d[i] = 0; S[0] = i; start[0] = 0; end[0] = 1; } count = 1; phase_num = 0; #ifdef _OPENMP OMP("omp barrier") #endif while (end[phase_num] - start[phase_num] > 0) { myCount = 0; start_iter = start[phase_num]; end_iter = end[phase_num]; #ifdef _OPENMP OMP("omp barrier") OMP("omp for schedule(dynamic) nowait") #endif for (vert = start_iter; vert < end_iter; vert++) { v = S[vert]; for (j=G->numEdges[v]; jnumEdges[v+1]; j++) { w = G->endV[j]; if (v != w) { #ifdef _OPENMP myLock = omp_test_lock(&vLock[w]); if (myLock) { #endif /* w found for the first time? */ if (d[w] == -1) { if (myS_size == myCount) { /* Resize myS */ myS_t = (attr_id_t *) malloc(2*myS_size*sizeof(attr_id_t)); memcpy(myS_t, myS, myS_size*sizeof(attr_id_t)); free(myS); myS = myS_t; myS_size = 2*myS_size; } myS[myCount++] = w; d[w] = d[v] + 1; sig[w] = sig[v]; P[w].list[P[w].count++] = v; } else if (d[w] == d[v] + 1) { sig[w] += sig[v]; P[w].list[P[w].count++] = v; } #ifdef _OPENMP omp_unset_lock(&vLock[w]); } else { if ((d[w] == -1) || (d[w] == d[v]+ 1)) { omp_set_lock(&vLock[w]); sig[w] += sig[v]; P[w].list[P[w].count++] = v; omp_unset_lock(&vLock[w]); } } #endif } } } /* Merge all local stacks for next iteration */ phase_num++; if (tid == 0) { if (phase_num >= MAX_NUM_PHASES) { fprintf(stderr, "Error: Max num phases set to %ld\n", MAX_NUM_PHASES); fprintf(stderr, "Diameter of input network greater than" " this value. Increase MAX_NUM_PHASES" " in vertex_betweenness_centrality_parBFS()\n"); exit(-1); } } psCount[tid+1] = myCount; #ifdef _OPENMP OMP("omp barrier") #endif if (tid == 0) { start[phase_num] = end[phase_num-1]; psCount[0] = start[phase_num]; for(k=1; k<=nthreads; k++) { psCount[k] = psCount[k-1] + psCount[k]; } end[phase_num] = psCount[nthreads]; } #ifdef _OPENMP OMP("omp barrier") #endif k0 = psCount[tid]; k1 = psCount[tid+1]; for (k = k0; k < k1; k++) { S[k] = myS[k-k0]; } count = end[phase_num]; } phase_num--; while (phase_num > 0) { start_iter = start[phase_num]; end_iter = end[phase_num]; #ifdef _OPENMP OMP("omp for schedule(static) nowait") #endif for (j=start_iter; jn; m = G->m; /* Permute vertices */ if (tid == 0) { #if RANDSRCS Srcs = (attr_id_t *) malloc(n*sizeof(attr_id_t)); #endif #ifdef _OPENMP vLock = (omp_lock_t *) malloc(n*sizeof(omp_lock_t)); #endif } #ifdef _OPENMP OMP("omp barrier") OMP("omp for") for (i=0; iendV[i]; #ifdef _OPENMP omp_set_lock(&vLock[v]); #endif in_degree[v]++; #ifdef _OPENMP omp_unset_lock(&vLock[v]); #endif } prefix_sums(in_degree, numEdges, pSums, n); P = (plist_t *) calloc(n, sizeof(plist_t)); pListMem = (attr_id_t *) malloc(m*sizeof(attr_id_t)); for (i=0; inumEdges[i+1] - G->numEdges[i] == 0) { continue; } else { num_traversals++; } sig[i] = 1; d[i] = 0; S[0] = i; start[0] = 0; end[0] = 1; count = 1; phase_num = 0; while (end[phase_num] - start[phase_num] > 0) { for (vert = start[phase_num]; vert < end[phase_num]; vert++) { v = S[vert]; for (j=G->numEdges[v]; jnumEdges[v+1]; j++) { w = G->endV[j]; if (v != w) { /* w found for the first time? */ if (d[w] == -1) { S[count++] = w; d[w] = d[v] + 1; sig[w] = sig[v]; P[w].list[P[w].count++] = v; } else if (d[w] == d[v] + 1) { sig[w] += sig[v]; P[w].list[P[w].count++] = v; } } } } phase_num++; start[phase_num] = end[phase_num-1]; end[phase_num] = count; } phase_num--; while (phase_num > 0) { for (j=start[phase_num]; jn == numSrcs) { if (G->n < 5000) { vertex_betweenness_centrality_simple(G, BC, numSrcs); } else { vertex_betweenness_centrality_parBFS(G, BC, numSrcs); } } else if (numSrcs < 50) { vertex_betweenness_centrality_simple(G, BC, numSrcs); } else { vertex_betweenness_centrality_parBFS(G, BC, numSrcs); } #else vertex_betweenness_centrality_simple(G, BC, numSrcs); #endif } influenceR/src/bridging.h0000755000176200001440000000037714431200046015075 0ustar liggesusers/* Header file for bridging.c */ #include "graph_defs.h" #ifndef BRIDGING_H #define BRIDGING_H double *bridging(graph_t *G, int *edgelist, double *scores); #ifdef USE_MPI double *bridging_MPI(graph_t *G, int *edgelist, double *scores); #endif #endif influenceR/src/Makevars.win0000644000176200001440000000000014431200046015403 0ustar liggesusersinfluenceR/src/keyplayer-utils.c0000644000176200001440000002555214431247461016461 0ustar liggesusers/* keyplayer-utils.c: Utilities and functions for Key Player implementation See also: http://www.bebr.ufl.edu/sites/default/files/Borgatti%20-%202006%20-%20Identifying%20sets%20of%20key%20players%20in%20a%20social%20networ.pdf AUTHOR: Simon Jacobs LICENSE: GPLv2 Contains a fast version of the KPP-NEG metric (metric 9 in Borgatti 2006). */ #include "graph_defs.h" #include #include #include "keyplayer-utils.h" #define X(i, j, n) ((i) * (n) + (j)) double * BFS_multiple(graph_t *g, int *src, int k, double *res); double * BFS_single(graph_t *g, int src, double *res); long BFS_parallel_frontier_expansion_with_distance(graph_t* G, long src, long diameter, double *distance); void regen(int *gen, int *s, int *t, int n, int k); int int_rand(void) { return (int) (unif_rand() * INT_MAX); } void gen_starting_set(int n, int k, int *s) { memset(s, 0, n * sizeof(int)); for(int i = 0; i < k; i++) { int t = int_rand() % n; while(s[t] != 0) t = (t + 1) % n; s[t] = 1; } } /* D is a matrix where D[si,j] is the distance from s[si] to j. */ double kpmetric_graph(graph_t *g, double *D, int n, int *s, int *t, int k, int *argmin) { double sum = 0; if (argmin != NULL) for (int i = 0; i < n; i++) argmin[i] = -1; for(int ti = 0; ti < n-k; ti++) { int i = t[ti]; double min = INFINITY; for (int si = 0; si < k; si++) { double m = D[X(si, i, n)]; if (m < min) { if (argmin != NULL) argmin[i] = si; min = m; } } if (min != 0 && min < INFINITY) sum += 1.0/min; } return sum/((double)n); } double kpmetric_graph_check(graph_t *g, double *D, int n, int *s, int *t, int k, int *prevargmin, int u, int v) { double distance_v_to_all[n]; BFS_single(g, v, distance_v_to_all); double sum = 0; for(int ti = 0; ti < n-k; ti++) { int i = t[ti]; if (i == v) i = u; double min = INFINITY; int si = prevargmin[i]; if (si != -1 && s[si] != u) { min = D[X(si, i, n)]; double m = distance_v_to_all[i]; if (m < min) min = m; } else { for (int si = 0; si < k; si++) { double m; if (s[si] != u) m = D[X(si, i, n)]; else m = distance_v_to_all[i]; if (m < min) { min = m; } } } if (min != 0 && min < INFINITY) sum += 1.0/min; } return sum/((double)n); } /* Compute Metric 15 in Borghatti (19) */ /* D is a n-by-n matrix */ /* s is a list of indices, kp-set */ /* compute: X = sum(min(v not in s)(distance to w, w in s)) */ /* sum(1/X) / n */ double kpmetric_st(double *D, int n, int *s, int *t, int k, int *argmin) { double sum = 0; if (argmin != NULL) for (int i = 0; i < n; i++) argmin[i] = -1; for(int ti = 0; ti < n-k; ti++) { int i = t[ti]; double min = INFINITY; for (int si = 0; si < k; si++) { int j = s[si]; double m = D[X(i, j, n)]; if (m < min) { if (argmin != NULL) argmin[i] = j; min = m; } } if (min != 0 && min < INFINITY) /* This node is in s */ sum += 1.0/((double)min); } return sum/((double) n); } /* Get next state function, probabilistically */ /* Method: pick a u randomly, and a v randomly. If fit improves, go for it. Otherwise, go for it with probability p. */ /* t = which(s) */ double get_next_state_graph(problem_t *this, int n, int *gen, int k, double p, int *ua, int *va, int round) { int argmin[n]; int s[k], t[n-k]; regen(gen, s, t, n, k); graph_t *graph = this->graph; if (round != this->round) { free(this->distance); this->distance = NULL; this->round = round; } if (this->distance == NULL) { this->distance = (double *) malloc(n*k*sizeof(double)); if (!this->distance) { return 0; } BFS_multiple(graph, s, k, this->distance); } double fit = kpmetric_graph(graph, this->distance, n, s, t, k, argmin); int tries = 0, u, v; while (1) { u = s[int_rand() % k]; #ifdef DEBUG // we want to match how we get a random v in the non-graph code. this sucks. v = int_rand % n; while(gen[v] != 0) v = (v + 1) % n; #else v = t[int_rand() % (n-k)]; #endif double fit_ = kpmetric_graph_check(graph, this->distance, n, s, t, k, argmin, u, v); if (fit_ > fit || unif_rand() < p) { *ua = u; *va = v; fit = fit_; break; } if (tries > 10000) { *ua = -1; *va = -1; break; } tries++; } /* replace row u with row v */ double * new_distance = (double *) malloc(n*k*sizeof(double)); if (! new_distance) { //printf("error with malloc!"); //exit(1); return 0; } int j = 0; // index into new_distance int vdone = 0; for (int i = 0; i < k; i++) { if (!vdone && s[i] > v) { BFS_single(graph, v, &new_distance[j*n]); j++; vdone = 1; } if (s[i] == u) continue; // copy for (int a = 0; a < n; a++) new_distance[X(j, a, n)] = this->distance[X(i, a, n)]; j++; } if (j != k) { BFS_single(graph, v, &new_distance[j*n]); j++; } if (j != k) { //printf("fatal error!\n"); //exit(1); return 0; } double *tmp = this->distance; this->distance = new_distance; free(tmp); return fit; } /* TODO: what's a good diameter value? */ double * BFS_multiple(graph_t *g, int *src, int k, double *res) { int n = g->n; for (int i = 0; i < k*n; i++) res[i] = INFINITY; for (int i = 0; i < k; i++) { BFS_parallel_frontier_expansion_with_distance(g, (long) src[i], 75, &res[i*n]); } return res; } double * BFS_single(graph_t *g, int src, double *res) { int n = g->n; for (int i = 0; i < n; i++) res[i] = INFINITY; BFS_parallel_frontier_expansion_with_distance(g, (long) src, 75, res); return res; } /* gen[i] = 0 if i in t, 1 if in s*/ void regen(int *gen, int *s, int *t, int n, int k) { int si = 0, ti = 0; for (int i = 0; i < n; i++) { if(gen[i] == 1) { s[si] = i; si++; } else { t[ti] = i; ti++; } } return; } /* Adapted from SNAP project, authors D.A. Bader and K. Madduri, see snap-graph.sourceforge.net See breadth_first_search.c : BFS_parallel_frontier_expansion */ long BFS_parallel_frontier_expansion_with_distance(graph_t* G, long src, long diameter, double *distance) { attr_id_t* S; long *start; char* visited; long *pSCount; #ifdef DIAGNOSTIC double elapsed_time; #endif #ifdef _OPENMP_KP omp_lock_t* vLock; #endif long phase_num, numPhases; long count; #ifdef _OPENMP_KP OMP("omp parallel") { #endif attr_id_t *pS, *pSt; long pCount, pS_size; long v, w; int tid, nthreads; long start_iter, end_iter; long j, k, vert, n; #ifdef _OPENMP_KP int myLock; #endif #ifdef _OPENMP_KP long i; tid = omp_get_thread_num(); nthreads = omp_get_num_threads(); #else tid = 0; nthreads = 1; #endif #ifdef DIAGNOSTIC if (tid == 0) elapsed_time = get_seconds(); #endif if (tid == 0) numPhases = diameter + 1; n = G->n; pS_size = n/nthreads + 1; pS = (attr_id_t *) malloc(pS_size*sizeof(attr_id_t)); assert(pS != NULL); if (tid == 0) { S = (attr_id_t *) malloc(n*sizeof(attr_id_t)); visited = (char *) calloc(n, sizeof(char)); start = (long *) calloc((numPhases+2), sizeof(long)); pSCount = (long *) malloc((nthreads+1)*sizeof(long)); #ifdef _OPENMP_KP vLock = (omp_lock_t *) malloc(n*sizeof(omp_lock_t)); #endif } #ifdef _OPENMP_KP OMP("omp barrier") OMP("omp for") for (i=0; i 0) { pCount = 0; start_iter = start[phase_num]; end_iter = start[phase_num+1]; #ifdef _OPENMP_KP OMP("omp for") #endif for (vert=start_iter; vertnumEdges[v]; jnumEdges[v+1]; j++) { w = G->endV[j]; if (v == w) continue; #ifdef _OPENMP_KP myLock = omp_test_lock(&vLock[w]); if (myLock) { #endif if (visited[w] != (char) 1) { distance[w] = distance[v] + 1; visited[w] = (char) 1; if (pCount == pS_size) { /* Resize pS */ pSt = (attr_id_t *) malloc(2*pS_size*sizeof(attr_id_t)); memcpy(pSt, pS, pS_size*sizeof(attr_id_t)); free(pS); pS = pSt; pS_size = 2*pS_size; } pS[pCount++] = w; } #ifdef _OPENMP_KP omp_unset_lock(&vLock[w]); } #endif } } #ifdef _OPENMP_KP OMP("omp barrier") #endif pSCount[tid+1] = pCount; #ifdef _OPENMP_KP OMP("omp barrier") #endif if (tid == 0) { pSCount[0] = start[phase_num+1]; for(k=1; k<=nthreads; k++) { pSCount[k] = pSCount[k-1] + pSCount[k]; } start[phase_num+2] = pSCount[nthreads]; count = pSCount[nthreads]; phase_num++; } #ifdef _OPENMP_KP OMP("omp barrier") #endif for (k = pSCount[tid]; k < pSCount[tid+1]; k++) { S[k] = pS[k-pSCount[tid]]; } #ifdef _OPENMP_KP OMP("omp barrier") #endif } /* End of search */ #ifdef DIAGNOSTIC if (tid == 0) { REprintf("Search from vertex %ld," " No. of vertices visited: %ld\n", src, count); } #endif free(pS); #ifdef _OPENMP_KP OMP("omp barrier") OMP("omp for") for (i=0; i #include #include // for NULL #include /* FIXME: Check these declarations against the C/Fortran source code. */ /* .Call calls */ extern SEXP process_sparse_R(SEXP, SEXP, SEXP, SEXP, SEXP, SEXP); extern SEXP snap_betweenness_R(SEXP, SEXP, SEXP); extern SEXP snap_bridging_R(SEXP, SEXP, SEXP, SEXP, SEXP); extern SEXP snap_keyplayer_R(SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP, SEXP); static const R_CallMethodDef CallEntries[] = { {"process_sparse_R", (DL_FUNC) &process_sparse_R, 6}, {"snap_betweenness_R", (DL_FUNC) &snap_betweenness_R, 3}, {"snap_bridging_R", (DL_FUNC) &snap_bridging_R, 5}, {"snap_keyplayer_R", (DL_FUNC) &snap_keyplayer_R, 9}, {NULL, NULL, 0} }; void R_init_influenceR(DllInfo *dll) { R_registerRoutines(dll, NULL, CallEntries, NULL, NULL); R_useDynamicSymbols(dll, FALSE); } influenceR/src/prefix_sums.c0000644000176200001440000000212314431200046015633 0ustar liggesusers/* AUTHOR: D.A. Bader and K. Madduri LICENSE: GPLv2 See: http://snap-graph.sourceforge.net/ Taken from utils.c */ #include "prefix_sums.h" void prefix_sums(attr_id_t *input, attr_id_t* result, attr_id_t* p, attr_id_t n) { #ifdef _OPENMP attr_id_t i, j, r, start, end, add_value; int tid, nthreads; tid = omp_get_thread_num(); nthreads = omp_get_num_threads(); r = n/nthreads; result[0] = 0; OMP("omp for") for (i=1; i0) { add_value=p[tid-1]; for (j=start-1; j # LICENSE: GPLv2 #' Convert a CSV file to an igraph graph object. #' #' The first column should be sources, the second should be targets. #' #' @param fname A filename #' @return An igraph graph object built from the filename. #' #' @examples #' \dontrun{ig.csv <- csv.to.igraph("edgelist.csv") } #' #' @export csv.to.igraph <- function(fname) { x <- utils::read.csv(fname) # this may be dangerous because of users' settings. # See: https://r-pkgs.had.co.nz/r.html el <- as.matrix(x[c(1,2)]) if(!is.character(el)) el <- apply(el, 2, as.character) igraph::graph.edgelist(el, directed=F) } #' Vertex Betweenness centrality measure. #' #' The Betweenness centrality score of a node u is the sum over all pairs s,t of the #' proportion of shortest paths between s and t that pass through u. This #' function allows the use of either the SNAP betweenness implementation (default), or #' the igraph betweenness function. The SNAP version makes use of OpenMP for #' parallelization, and may be faster in some circumstances. #' #' @references \url{https://snap-graph.sourceforge.net/} #' #' @param g The igraph object to analyze #' @param snap True to use the SNAP betweenness code, False to use igraph::betweenness #' @return A numeric vector with the betweenness centrality score for each vertex #' #' @examples #' ig.ex <- igraph::erdos.renyi.game(100, p.or.m=0.3) # generate an undirected 'igraph' object #' betweenness(ig.ex) # betweenness scores for each node in the graph #' #' @export betweenness <- function(g, snap=T) { if (!igraph::is_igraph(g)) { stop("Not a graph object") } # 1/2 the values of our betweenness code, which is because this is UNDIRECTED for real if (!snap) return(igraph::betweenness(g)) el <- igraph::get.edgelist(g, names=F) el_i <- as.integer(t(el)) n <- as.integer(max(el)) m <- as.integer(length(el)/2) # TODO: for directed too? vals <- .Call("snap_betweenness_R", el_i, n, m, PACKAGE="influenceR") vals[vals<2^-128] <- 0 vals[is.nan(vals)] <- 0 names(vals) <- igraph::V(g)$name vals } #' Compute a KPP-Pos set for a given graph. #' #' @description #' The "Key Player" family of node importance algorithms (Borgatti 2006) involves the selection #' of a metric of node importance and a combinatorial optimization strategy to #' choose the set S of vertices of size k that maximize that metric. #' #' @details #' This function implements KPP-Pos, a metric intended to identify k nodes which #' optimize resource diffusion through the network. We sum over all vertices #' not in S the reciprocal of the shortest distance to a vertex in S. #' #' According to Borgatti, a number of off-the-shelf optimization algorithms may #' be suitable to find S, such as tabu-search, K-L, simulated annealing, or #' genetic algorithms. He presents a simple greedy algorithm, which we excerpt #' here: #' #' \enumerate{ #' \item Select k nodes at random to populate set S #' \item Set F = fit using appropriate key player metric. #' \item For each node u in S and each node v not in S: #' \itemize{\item DELTAF = improvement in fit if u and v were swapped} #' \item Select pair with largest DELTAF #' \itemize{ #' \item If DELTAF <= [tolerance] then terminate #' \item Else, swap pair with greatest improvement in fit and set F = F + DELTAF #' } #' \item Go to step 3. #' } #' #' Our implementation uses a different optimization method which we call #' stochastic gradient descent. In tests on real world data, we found that #' our method discovered sets S with larger fits in less computation time. #' The algorithm is as follows: #' #' \enumerate{ #' \item Select k nodes at random to populate set S #' \item Set F = fit using appropriate key player metric (KPP-Pos in our case) #' \item Get a new state: #' \itemize{ #' \item Pick a random u in S and v not in S. #' \item F' = fit if u and v were swapped #' \item If F' > F, swap u and v in S. Else, repeat step 3. (Alternatively, if a positive value is given for the `prob' parameter, a swap will be accepted with a small probability regardless of whether it improves the fit). #' } #' \item If F' - F < tolerance or our maximum computation time is exceeded, return S. Else, go to step 3. #' } #' #' This implementation uses OpenMP (if available on the host system) so that #' multiple workers can explore the solution space in parallel. After a given #' of time, the workers synchronize their sets S to the one which maximizes #' the metric. #' #' @references \url{https://link.springer.com/article/10.1007/s10588-006-7084-x} #' #' @param g The igraph object to analyze. #' @param k The size of the KP-set #' @param prob probability of accepting a state with a lower value #' @param tol tolerance within which to stop the optimization and accept the current value #' @param maxsec The total computation budget for the optimization, in seconds #' @param roundsec Number of seconds in between synchronizing workers' answer #' @return a vector with the vertex number of each vertex in the selected set S. #' #' @examples #' ig.ex <- igraph::erdos.renyi.game(100, p.or.m=0.3) # generate an undirected 'igraph' object #' keyplayer(ig.ex, k=10) # key-player set consisting of 10 actors #' #' @export keyplayer <- function(g, k, prob = 0.0, tol = 0.0001, maxsec = 120, roundsec = 30) { if (!igraph::is_igraph(g)) { stop("Not a graph object") } if (roundsec > maxsec) roundsec <- maxsec el <- igraph::get.edgelist(g, names=F) el_i <- as.integer(t(el)) n <- as.integer(max(el)) m <- as.integer(length(el)/2) converges <- vector("integer", 1) # just allocate space for an integer s <- .Call("snap_keyplayer_R", el_i, n, m, as.integer(k), prob, tol, as.integer(maxsec), as.integer(roundsec), converges, PACKAGE="influenceR") if (converges == 1) warning("Maximum computation time (arg 'maxsec') exceeded!") igraph::V(g)[which(s>0)] } #' Valente's Bridging vertex measure. #' #' Edges that reduces distances in a network are important structural bridges. Here we implement Valente and Fujimoto's metric, #' where a node's bridging score is the average decrease in cohesiveness if each of #' its edges were removed from the graph. #' #' @references \url{https://www.ncbi.nlm.nih.gov/pmc/articles/PMC2889704/} #' #' @param g The igraph object to analyze. #' @return A numeric vector with the bridging score for each vertex #' #' @examples #' ig.ex <- igraph::erdos.renyi.game(100, p.or.m=0.3) # generate an undirected 'igraph' object #' bridging(ig.ex) # bridging scores for each node in the graph #' #' @export bridging <- function(g) { if (!igraph::is_igraph(g)) { stop("Not a graph object") } el <- igraph::get.edgelist(g, names = F) el_i <- as.integer(t(el)) n <- as.integer(max(el_i)) m <- as.integer(length(el_i) / 2) x <- .Call("snap_bridging_R", el_i, n, m, as.integer(FALSE), as.integer(0), PACKAGE = "influenceR") names(x) <- igraph::V(g)$name x } #' Burt's Effective Network Size and Constraint index. #' The next two functions below provide ways to measure the actors' access to structural holes in a network. Structural holes #' "provide opportunities to broker connections between people" (Burt 2008). #' @param g The igraph object to analyze. #' @return A numeric vector with the effective network size for each vertex #' #' @examples #' ig.ex <- igraph::erdos.renyi.game(100, p.or.m=0.3) # generate an undirected 'igraph' object #' ens(ig.ex) # Effective Network Size scores for each node in the graph #' #' @references \url{https://www.sciencedirect.com/science/article/abs/pii/S0378873397000038} #' @export ens <- function(g) { if (!igraph::is_igraph(g)) { stop("Not a graph object") } A <- igraph::get.adjacency(g) # This will be sparse, which is great. S <- Matrix::crossprod(A) # S[i,j] = # of shared neighbors between i,j Q <- A * S # Q[i,j] = # of shared neighbors if i and j are neighbors, 0 else qsum <- Matrix::rowSums(Q) deg <- Matrix::rowSums(A) ens <- deg - (qsum / deg) ens[is.nan(ens)] <- 0 # If a vertex has no neighbors, make its ENS 0 names(ens) <- igraph::V(g)$name ens } #' Burt's Constraint Index. #' #' The igraph package provides an implementation of Constraint; this is an alternate implementation. #' #' @param g The igraph object to analyze. #' @param v vertices over which to compute constraint (default to all) #' @return A numeric vector with the constraint score for each vertex in v #' #' @examples #' ig.ex <- igraph::erdos.renyi.game(100, p.or.m=0.3) # generate an undirected 'igraph' object #' constraint(ig.ex) # constraint scores for each node in the graph #' #' @export constraint <- function(g, v=igraph::V(g)) { if (!igraph::is_igraph(g)) { stop("Not a graph object") } process_sparse <- function(A, Ai, deg) { M <- methods::as(A, 'TsparseMatrix') x <- .Call("process_sparse_R", M@i, M@j, M@x, Ai, deg, Matrix::nnzero(M), PACKAGE = "influenceR") M@x <- x M } A <- igraph::get.adjacency(g, sparse=T) n <- dim(A)[1] deg <- Matrix::rowSums(A) constraint_i <- function(i) { # process sparse does this: jq <- drop0(t(A*A[,i]) * A[,i]); jqd <- drop0(jq * deg) jqd <- process_sparse(A, A[i, ], deg) jqd <- Matrix::drop0(jqd) jqd@x <- (1 / jqd@x) * (1 / deg[i]) Sj <- Matrix::colSums(jqd) idx <- as.numeric(igraph::neighbors(g, i)) Sj[idx] <- Sj[idx] + (1 / deg[i]) Sj2 <- Sj * Sj sum(Sj2) } vals <- sapply(v, constraint_i) names(vals) <- v$name vals } influenceR/R/influenceR.R0000644000176200001440000000202714431243677014776 0ustar liggesusers #' influenceR: Software tools to quantify structural importance of nodes in a network. #' #' The influenceR package includes functions to quantify the structural #' importance of nodes in a network. Algorithms include Betweenness Centrality, #' Bridging, Constraint Index, Effective Network Size, and Key Players. #' Currently, algorithms are only guaranteed to work on undirected graphs; work #' on directed graphs is in progress. These functions run on graph objects from #' the igraph package. #' #' In addition to igraph, this package makes use of the SNAP framework for a #' high-performance graph data structure and an OpenMP-parallelized #' implementation of Betweenness Centrality. See #' \url{https://snap-graph.sourceforge.net} #' #' @section Funding: #' Development of this software package was supported by NIH grant R01 DA033875. #' #' @section References: #' The website and source code is located at \url{https://github.com/khanna-lab/influenceR}. #' #' @docType package #' @name influenceR #' @useDynLib influenceR NULL #> NULLinfluenceR/NEWS.md0000644000176200001440000000060614431251425013445 0ustar liggesusers# influenceR 0.1.5 * Add badges to README * Update documentation with Rd. * include prototype in int_rand() function declaration in keyplayer-utils.c * fixed compatibility in graphs_defs.h * Updated maintainer email * Changed GitHub repository location to https://github.com/khanna-lab/influenceR * Fixed broken links # influenceR 0.1.2 * Fixed RChecks package. Current version is 0.2.0 influenceR/MD50000644000176200001440000000341614431373442012665 0ustar liggesusers206b645cc7b83db50785312bf7d6f059 *DESCRIPTION fa8d0fdc9887cdd931ce55b8f107b7f8 *NAMESPACE d1fa37577099b502e98a9b4052f4bab0 *NEWS.md 4c57cd3981bb0bf31801a9a2d72c875e *R/graph_metrics.R 1748391d1822b2a0899532d72c4c2e0d *R/influenceR.R 838c7d32d6f571f2f07ea1825f1cb8d6 *README.md af26b5c0179e800b1271c59d7cdf18d1 *man/betweenness.Rd 68c63bc9b7e26d0e1df3c1ef2d5f67de *man/bridging.Rd 0a20389d8408e7a6d6ead7df38b513d0 *man/constraint.Rd f30676ace15a808d523734ffd03a1f0d *man/csv.to.igraph.Rd 4a9aaf5d75aeb1f01d20974604481cf7 *man/ens.Rd 86123d5e252e202097e3eb4b2f767189 *man/influenceR.Rd c2d53c9d0c0307b30d9aabbbbc0d45bf *man/keyplayer.Rd d40b118333be5678e2c45b03acc49b41 *src/Makevars d41d8cd98f00b204e9800998ecf8427e *src/Makevars.win 7b6709eefe64fd74c53a34b654f9c60b *src/bridging.c ff0aa8977be870bd0e5bd900f06182f7 *src/bridging.h 34f8fc3c074d5d7d3fcfa1e7989d38f6 *src/graph_defs.h adc2444ca23b694a682ff4d0c433239c *src/keyplayer-utils.c 7b083f1d14fbf87e1ef5a7f5a2dcd7ef *src/keyplayer-utils.h daa7cd8a4014b6918b08d0cb8687c0e6 *src/keyplayer.c d99b533d972fa41afa144ddb18962f09 *src/keyplayer.h aafdbf9360552a7afca88c0a97dc0fde *src/packagename_init.c 47b3dd936e62959faaeb570b38514a14 *src/prefix_sums.c ca41ddd4cf2ad2bcf0548f3829cd88ec *src/prefix_sums.h b6cbfd167c02d0a8346a663c333e4d7d *src/process_sparse.c 2abc2fd30bab6140f1808e9d9da5ced6 *src/process_sparse.h da7c9469687ec66d7c44eed96f90f937 *src/snap_wrapper.c 52547425e88e6c81096625f4528181e2 *src/vertex_betweenness_centrality.c 56a576decd7418f62f96c78267f0331f *src/vertex_betweenness_centrality.h b14c5078939ce876e40755ed04432f35 *tests/testthat.R f6c5319c970f11a8c0fc1c91d9ef8da3 *tests/testthat/flo_results.RData 627525d27b7950df5c539d11cf38b5d8 *tests/testthat/test_metrics.R 1437518807a7d72e98705fce369d487f *tests/testthat/test_reference.R