迭代地添加由k常规游戏生成的图形中的一个边缘,保持过去的连接

时间:2018-04-24 07:02:13

标签: r igraph

我已经生成了一个无向的常规图,其中偶数个节点的度数相同,例如 k ,使用R包k.regular.game的函数igraph

现在我需要迭代地为每个节点添加一条边,这样在每次迭代中,每个节点的度数保持不变,它等于 k + i ,其中 i 是执行的迭代次数。

此外,我希望在每次迭代中保留连接,即:迭代 i 的代理 j 的邻居集应该与集合相同代理 j 的邻居用于迭代 i + 1 除了一个连接:例如,如果 j 连接到 w y k = 2 时, j 必须连接到 w y k <3 z

我的最终目标是获取(n-1)图,其中 n 等于常规图中的节点数。因此,我将获得第一个生成的图形具有 k = 1 ,并且最后生成的图形具有 k =(n-1)

有关如何执行此操作的任何建议吗?

1 个答案:

答案 0 :(得分:1)

这是一个很好的网络问题,下面有两个部分解决方案。

让我们假设有一个函数会将所有度为1的图g带到所有度为2的图形。它必须是具有偶数个节点的图形。

increment.k <- function(g){}

由此得出increment.k通过向其添加|V|/2个边缘将每个节点的度数增加一个 - 图中每两个节点一个边缘。根据我对您的问题规范的理解,任何这些边缘都必须连接已连接的两个节点。这使increment.k()成为一个难题,其中两个节点之间的随机边缘可能会使所有节点都达到新k - 度数值的可能性。如果一个图表有k = 1并且我们开始只是随机地添加边缘到达最后一个边缘但是发现只有两个仍然具有1度的节点已经连接了怎么办?!

我不能直观地掌握这是否允许图形无法递增的可能性,因为随机边缘的组合不允许在先前未连接的节点之间创建|V|/2边缘。但我可以想象存在这样的图表。

我在一个包含20个节点的图表上做了这个例子(因此可以在1到19之间有一个k):

g <- k.regular.game(no.of.nodes=20, k=1, directed=F)

如果您要生成具有更高k的随机k.regular.game,直到找到图形的边缘是高k随机图边缘的子集,该怎么办?它应该非常慢。

问题当然是你不想允许重复的拱门。如果没有,解决方案将非常简单:

increase.k.allowing.duplicates <- function(graph){
    if(length(V(graph))%%2!=0){
        stop("k can only be incremented for graphs with an even number of nodes.")
    }
    # Add random edges to the graph and allow dual edges just to increase k
    graph %>% add_edges(as.numeric(sample(1:length(V(graph)), length(V(graph)))))
}

上面的代码可以解决问题,如果允许双拱。这将返回更高k的图形,并且会让k走向无穷大,因为图形的节点数不会设置图表的任何最大平均度。

我已经在下面提出了这种蒙特卡罗方法。为了将k增加1,在节点之间逐个添加给定数量的边,但是如果在1)未连接的节点之间放置拱并且2)尚未递增到更高的k /度时,循环用尽了备选方案,创建具有更高k的新图的过程重新开始。该函数具有在maximum.tries中重新开始的最大尝试次数。

increase.k <- function(graph, maximum.tries=200){
    if(length(V(graph))%%2!=0){
        stop("k can only be incremented for graphs with an even number of nodes.")
    }
    k <- mean(degree(graph))
    if(k != round(k) ){
        stop("Nodes in graph do not have the same degree")
    }
    if(k >= length(V(graph))-1 ) {
        stop("This graph is complete")
    }

    # each node has the following available arches before starting the iteration:
    #posisble.arches <- lapply(neighbors(graph,1), function(x) setdiff(V(graph), x[2:length(x)]))

    # Here we must lay the puzzle. If we run into a one-way street with the edges we add, we'll have to start afresh
    original.graph <- graph
    for(it in 1:maximum.tries){
        # We might need many tries to get the puzzle right by brute-forcing

        # For each try we increment in a loop to avoid duplicate links
        for(e_ij in 1:(length(V(graph))/2)){
            # Note that while(mean(degree(graph)) < k + 1){} is a logical posibility, but less safe

            # Add a new edge between two nodes of degree k. i is any such node and j is any such node not already connected to i
            i <- sample(as.numeric(V(graph)[degree(graph)==k]), 1)
            js <- as.numeric(V(graph)[degree(graph) == k * !V(graph) %in% c(as.numeric(neighbors(graph,i)), i)])
            # Abandon this try if no node unconnected to i and with degree == k exists
            if(length(js)==0){break}

            j <- sample(c(js), 1); if(length(js)==1){j<-js}
            graph <- graph %>% add_edges(c(i,j))
        }

        # Did we lay the puzzle to completion successfully crating a random graph with a higher k?
        if(mean(degree(graph)) == k+1){
            # Success
            print(paste("Succeded at iteration ", it))
            break
        } else {
            # Failure, let's try again
            graph <- original.graph
            print("Failed")
        }
    }
    (graph)
}

# Compare the two approaches
g1 <- increase.k.allowing.duplicates(g)
g2 <- increase.k(g)
degree(g1) == degree(g2)
l <- layout_with_gem(g2)
par(mfrow=c(1,2))
plot(g1, layout=l, vertex.label="")
plot(g2,layout=l, vertex.label="")
dev.off()

# Note that increase.k() can be run incrementally up untill a complete graph:
is.complete <- function(graph){mean(degree(graph)) >= (length(V(graph))-1)}
while(!is.complete(g)){
    print(mean(degree(g)))
    g <- increase.k(g)
}
# and that increase.k() cannot increase k in already complete graphs.
g <- increase.k(g)

以上代码解决了某些图表的问题。拼图需要更多的迭代,图表越大。在仅具有20个节点的该示例中,可以相对快速地从1-19生成每个k级。我确实设法从k=1k=19获得了19个独立的网络。但我也设法陷入循环中,我将其视为现有网络结构的证据,其中k无法成功递增。特别是因为相同的起始规格有时会卡住,但在其他场合设法达到完整的图形。

为了测试该功能,我将maximum.tries设置为25并尝试从k=119 100次。它从来没有奏效。 k越高,拼图并找到合适的拱门就越困难,即使倒塌之前的倒数第二次迭代更快。在第15次和第18次迭代之间,达到25的上限的风险增加,并且大多数图表仅使其达到k=17

enter image description here

可以想象这个方法是从一个完整的图形开始向后执行,去除蒙特卡洛过程中的边缘,该过程试图去除边缘以获得所有度数均为k-1的图形。不过,它应该遇到类似的问题。

上面的代码实际上是试图强行解决这个问题而不进入这种类型图的基础数学。我不是数学家,缺乏技能,但也许创建一个故障安全k.increment() - 函数是一个真实且未解决的数学问题。如果有任何图形理论家来这篇文章,请启发我们。