Skip to content

Commit 8b5c0a3

Browse files
committed
first commit
0 parents  commit 8b5c0a3

File tree

9 files changed

+679
-0
lines changed

9 files changed

+679
-0
lines changed

.Rbuildignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
^.*\.Rproj$
2+
^\.Rproj\.user$

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
.Rproj.user
2+
.Rhistory
3+
.RData
4+
**Rproj

DESCRIPTION

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
Package: gbnorm
2+
Title: What the Package Does (one line, title case)
3+
Version: 0.0.0.9000
4+
Authors@R: person("First", "Last", email = "[email protected]", role = c("aut", "cre"))
5+
Description: What the package does (one paragraph).
6+
Depends: R (>= 3.4.4)
7+
License: What license is it under?
8+
Encoding: UTF-8
9+
LazyData: true

NAMESPACE

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# Generated by roxygen2: fake comment so roxygen2 overwrites silently.
2+
exportPattern("^[^\\.]")

R/graphUtils.R

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
#' Community internal strength
2+
#' @import igraph
3+
community.strength.internal <- function(graph, community) {
4+
# weighted sum of edges that have both ends inside the community
5+
gC = igraph::induced_subgraph(graph, community)
6+
return(Reduce(sum, igraph::edge_attr(gC,'weight',index=igraph::E(gC))))
7+
}
8+
9+
#' @import igraph
10+
community.internal.density <- function(graph, community, weighted=FALSE) {
11+
gC = igraph::induced_subgraph(graph, community)
12+
nC = igraph::vcount(gC)
13+
avgW = ifelse(weighted,
14+
Reduce(sum, igraph::edge_attr(graph, 'weight', index=igraph::E(graph)))/ igraph::ecount(graph),
15+
1)
16+
intW = ifelse(weighted,
17+
Reduce(sum, igraph::edge_attr(gC, 'weight', index=igraph::E(gC))),
18+
igraph::ecount(gC))
19+
maxDensity = ifelse(igraph::is.directed(gC),
20+
nC*(nC-1),
21+
nC*(nC-1)/2)
22+
return(intW / avgW / maxDensity)
23+
}
24+
25+
#' calculate M measure, defined as
26+
#'
27+
#' M(C) = (vol(C) - cut(C)) / (2 * cut(C))
28+
#' graph an igraph object
29+
#' community a vector of vertex indices
30+
measure.M <- function(graph, community) {
31+
ccut = community.cut(graph, community,weighted = TRUE)
32+
return((community.volume(graph, community,weighted = TRUE) - ccut)/ (2. * ccut))
33+
}
34+
35+
#' Community volume
36+
#' @import igraph
37+
community.volume <- function(graph, community, weighted=FALSE) {
38+
if (weighted) {
39+
return(Reduce(sum,igraph::strength(graph, community)))
40+
} else {
41+
return(Reduce(sum,igraph::degree(graph, community)))
42+
}
43+
}
44+
45+
#' Community cut
46+
#'
47+
#' @import igraph
48+
community.cut <- function(graph, community, weighted=FALSE) {
49+
shell = community.shell(graph, community)
50+
possibleEdges = expand.grid(shell,community)
51+
cut = 0
52+
if (nrow(possibleEdges) >= 1) {
53+
for (i in 1:nrow(possibleEdges)) {
54+
tryCatch({eIdx = igraph::get.edge.ids(graph, vp=possibleEdges[i,])},
55+
error = function(e) {
56+
message(possibleEdges[i,])
57+
stop(e)
58+
})
59+
if (eIdx != 0) {
60+
if (weighted) {
61+
cut=cut+igraph::get.edge.attribute(graph, 'weight', eIdx)
62+
} else {
63+
cut = cut + 1
64+
}
65+
}
66+
}
67+
}
68+
return(cut)
69+
}
70+
71+
#' community.shell
72+
#'
73+
#' @import igraph
74+
#' @export
75+
community.shell <- function(graph, community) {
76+
neighs = (lapply(community, function(i) {return(igraph::neighbors(graph,i))}))
77+
shell = setdiff(Reduce(union,neighs),community)
78+
return(shell)
79+
}
80+
81+
#' Community detection by GCE
82+
#'
83+
#' Starting from a set of seeds, a vertex in the shell is added to the community if it increases community quality metric M
84+
#' @import parallel
85+
#' @export
86+
community.gce <- function(graph, seed,ncores=1, version=1) {
87+
indicator = rep(0, igraph::vcount(graph))
88+
indicator[seed] = 1
89+
if (version == 1) {
90+
if (ncores > 1) {
91+
cl = parallel::makeCluster(ncores)
92+
parallel::clusterExport(cl,c('measure.M', 'community.cut', 'community.volume', 'community.shell'))
93+
return(community.gce.ind(graph, indicator,cl=cl))
94+
} else {
95+
return(community.gce.ind(graph, indicator))
96+
}
97+
} else {
98+
return(community.gce.ind2(graph, indicator))
99+
}
100+
}
101+
102+
103+
community.gce.ind <- function(graph, commIndicator, cluster=NULL) {
104+
comm = which(commIndicator == 1)
105+
shell = community.shell(graph,comm)
106+
if (length(shell) < 1) {
107+
# this check is pretty stupid, but must be here because R unpredictably loop through the vector 1:0 for once
108+
return(comm)
109+
} else {
110+
cQuality = measure.M(graph,comm)
111+
if (is.null(cluster)) {
112+
improvements = sapply(1:length(shell),FUN = function(i) {
113+
return(measure.M(graph, c(comm,shell[i])))
114+
})
115+
} else {
116+
improvements = parallel::parSapply(cluster, 1:length(shell),FUN = function(i) {
117+
return(measure.M(graph, c(comm,shell[i])))
118+
})
119+
}
120+
improvements = improvements - cQuality
121+
if (all(improvements <= 0)) {
122+
# parallel::stopCluster(cluster)
123+
return(which(commIndicator == 1))
124+
} else {
125+
commIndicator[shell[which(improvements == max(improvements))]] = 1
126+
community.gce.ind(graph, commIndicator)
127+
}
128+
}
129+
}
130+
131+
community.gce.ind2 <- function(graph, commIndicator) {
132+
comm = which(commIndicator == 1)
133+
shell = community.shell(graph, comm)
134+
135+
if (length(shell) < 1) {
136+
return(comm)
137+
}
138+
# equivalent to maximize M(seed +v) - M(seed)
139+
mdiff = rep(0,length(shell))
140+
for (i in 1:length(shell)) {
141+
insideConn = 0
142+
outsideConn = 0
143+
iNeighbors = igraph::neighbors(graph, shell[i])
144+
for (j in iNeighbors) {
145+
w = igraph::get.edge.attribute(graph, 'weight', index=igraph::get.edge.ids(graph, vp=c(shell[i],j)))
146+
if (j %in% comm) {
147+
insideConn = insideConn + w
148+
} else {
149+
outsideConn = outsideConn + w
150+
}
151+
}
152+
mdiff[i] = (insideConn + outsideConn) / (outsideConn - insideConn)
153+
}
154+
print(shell)
155+
print(mdiff)
156+
if (all(mdiff <= 0)) {
157+
return(which(commIndicator == 1))
158+
} else {
159+
commIndicator[shell[which(mdiff == max(mdiff))]] = 1
160+
community.gce.ind2(graph, commIndicator)
161+
}
162+
}

0 commit comments

Comments
 (0)