它不是igraph中的直接函数,但是您当然可以对其进行编码。要查找循环,请从某个节点开始,转到某个相邻节点,然后找到返回原始节点的简单路径。由于您未提供任何示例数据,因此我将举一个简单的示例进行说明。
## Sample graph
library(igraph)
set.seed(1234)
g = erdos.renyi.game(7, 0.29, directed=TRUE)
plot(g, edge.arrow.size=0.5)
Run Code Online (Sandbox Code Playgroud)
让我从一个节点和一个邻居开始。节点2连接到节点4。因此某些周期可能看起来像2-> 4->(除2或4以外的节点)->2。让我们获得所有类似的路径。
v1 = 2
v2 = 4
lapply(all_simple_paths(g, v2,v1, mode="out"), function(p) c(v1,p))
[[1]]
[1] 2 4 2
[[2]]
[1] 2 4 3 5 7 6 2
[[3]]
[1] 2 4 7 6 2
Run Code Online (Sandbox Code Playgroud)
我们看到有三个周期从2开始,第二个节点为4。(我知道您说的长度大于3。我会再说一遍。)
现在我们只需要对v1的每个节点v1和每个邻居v2进行此操作。
Cycles = NULL
for(v1 in V(g)) {
for(v2 in neighbors(g, v1, mode="out")) {
Cycles = c(Cycles,
lapply(all_simple_paths(g, v2,v1, mode="out"), function(p) c(v1,p)))
}
}
Run Code Online (Sandbox Code Playgroud)
这在整个图中给出了17个循环。但是,根据您要如何使用它,可能需要查看两个问题。首先,您说过您想要长度大于3的循环,所以我假设您不希望看起来像2-> 4-> 2的循环。这些很容易消除。
LongCycles = Cycles[which(sapply(Cycles, length) > 3)]
Run Code Online (Sandbox Code Playgroud)
LongCycles有13个循环,消除了4个短循环
2 -> 4 -> 2
4 -> 2 -> 4
6 -> 7 -> 6
7 -> 6 -> 7
Run Code Online (Sandbox Code Playgroud)
但是该清单指出了另一个问题。您可能仍然认为有些循环是重复的。例如:
2 -> 7 -> 6 -> 2
7 -> 6 -> 2 -> 7
6 -> 2 -> 7 -> 6
Run Code Online (Sandbox Code Playgroud)
您可能要清除这些。要仅获得每个循环的一个副本,您始终可以选择以最小的顶点号开始的顶点序列。从而,
LongCycles[sapply(LongCycles, min) == sapply(LongCycles, `[`, 1)]
[[1]]
[1] 2 4 3 5 7 6 2
[[2]]
[1] 2 4 7 6 2
[[3]]
[1] 2 7 6 2
Run Code Online (Sandbox Code Playgroud)
这仅给出了不同的周期。
我提供的是我最初提供的代码的高效得多的版本。但是,主要出于争论的目的,除了非常简单的图形之外,您将无法产生所有循环。
这是一些更有效的代码。它消除了检查无法产生循环或将作为冗余循环消除的许多情况。为了使运行所需的测试变得容易,我将其设置为一个函数。
## More efficient version
FindCycles = function(g) {
Cycles = NULL
for(v1 in V(g)) {
if(degree(g, v1, mode="in") == 0) { next }
GoodNeighbors = neighbors(g, v1, mode="out")
GoodNeighbors = GoodNeighbors[GoodNeighbors > v1]
for(v2 in GoodNeighbors) {
TempCyc = lapply(all_simple_paths(g, v2,v1, mode="out"), function(p) c(v1,p))
TempCyc = TempCyc[which(sapply(TempCyc, length) > 3)]
TempCyc = TempCyc[sapply(TempCyc, min) == sapply(TempCyc, `[`, 1)]
Cycles = c(Cycles, TempCyc)
}
}
Cycles
}
Run Code Online (Sandbox Code Playgroud)
但是,除了非常简单的图之外,可能路径的组合爆炸式增长,因此找到所有可能的循环是完全不切实际的,我将用比您在评论中提到的图小得多的图来说明这一点。
首先,我将从一些小的图开始,其中边的数量大约是顶点数量的两倍。下面是生成示例的代码,但我想重点介绍周期数,因此我将从结果开始。
## ecount ~ 2 * vcount
Nodes Edges Cycles
10 21 15
20 41 18
30 65 34
40 87 424
50 108 3433
55 117 22956
Run Code Online (Sandbox Code Playgroud)
但是您报告说,数据的边数大约是顶点的5倍。让我们看一些类似的例子。
## ecount ~ 5 * vcount
Nodes Edges Cycles
10 48 3511
12 61 10513
14 71 145745
Run Code Online (Sandbox Code Playgroud)
随着周期数的增长,使用10K边缘和50K边缘的节点似乎是不可能的。顺便说一句,花了几分钟来计算具有14个顶点和71条边的示例。
为了重现性,这是我生成上述数据的方式。
set.seed(1234)
g10 = erdos.renyi.game(10, 0.2, directed=TRUE)
ecount(g10)
length(FindCycles(g10))
set.seed(1234)
g20 = erdos.renyi.game(20, 0.095 , directed=TRUE)
ecount(g20)
length(FindCycles(g20))
set.seed(1234)
g30 = erdos.renyi.game(30, 0.056 , directed=TRUE)
ecount(g30)
length(FindCycles(g30))
set.seed(1234)
g40 = erdos.renyi.game(40, 0.042 , directed=TRUE)
ecount(g40)
length(FindCycles(g40))
set.seed(1234)
g50 = erdos.renyi.game(50, 0.038 , directed=TRUE)
ecount(g50)
length(FindCycles(g50))
set.seed(1234)
g55 = erdos.renyi.game(55, 0.035 , directed=TRUE)
ecount(g55)
length(FindCycles(g55))
##########
set.seed(1234)
h10 = erdos.renyi.game(10, 0.55, directed=TRUE)
ecount(h10)
length(FindCycles(h10))
set.seed(1234)
h12 = erdos.renyi.game(12, 0.46, directed=TRUE)
ecount(h12)
length(FindCycles(h12))
set.seed(1234)
h14 = erdos.renyi.game(14, 0.39, directed=TRUE)
ecount(h14)
length(FindCycles(h14))
Run Code Online (Sandbox Code Playgroud)