Graph 从权重派生的特殊边属性

Graph 从权重派生的特殊边属性,graph,igraph,graph-theory,Graph,Igraph,Graph Theory,我(通过python)使用图形集群 我有一棵树(几何图的最小生成树)带有加权边,并想计算加权时间 两个组件的较小顶点数(如果边为 删除: 我的问题是: 这是图论中已知(并命名)的性质吗?如果是,原因是什么 是吗 如果我计算所有的时间,我的代码是非常低效的 边缘,如上所示。如果图形变为50000条边和顶点, 内存消耗变得巨大。你有什么建议吗 优化 我不知道你的第一个问题,但我可能知道第二个问题。 因为我们处理的是最小生成树,所以可以使用获得的关于一条边的信息来计算与其相邻的边所需的属性(从现在起,

我(通过python)使用图形集群

我有一棵树(几何图的最小生成树)带有加权边,并想计算加权时间 两个组件的较小顶点数(如果边为 删除:

我的问题是:

  • 这是图论中已知(并命名)的性质吗?如果是,原因是什么 是吗

  • 如果我计算所有的时间,我的代码是非常低效的 边缘,如上所示。如果图形变为50000条边和顶点, 内存消耗变得巨大。你有什么建议吗 优化


  • 我不知道你的第一个问题,但我可能知道第二个问题。
    因为我们处理的是最小生成树,所以可以使用获得的关于一条边的信息来计算与其相邻的边所需的属性(从现在起,对于边e,我将此属性称为f(e)。
    让我们看一下边(A,B)和(B,C)。当您计算
    f(A,B)
    时,让我们假设从图形中删除边后,您会发现较小的组件是A侧的组件,您知道:
    f(B,C)=(f(A,B)/权重(A,B)+1)*权重(B,C)

    这是真的,因为(B,C)与(A,B)相邻,移除它后,你会得到“几乎”相同的两个组件,唯一的区别是B从较大的组件移动到较小的组件。 这样,您可以对一条边进行完整计算(包括删除dge和发现组件及其大小),然后对连接到它的每一条边只进行一次简短计算。
    您需要特别注意较小的组件(沿边链增长)变大的情况

    更新:
    经过一番思考,我意识到如果你能在树中找到一个叶子节点,那么你根本不需要搜索组件及其大小。首先计算附加到此节点的边的f(e)。因为它是一片叶子:
    f(e)=权重(e)*1
    (1因为它是一个叶节点,在删除边后,您将得到一个只包含叶的组件和一个作为图形其余部分的组件。)
    从这里继续前面讨论的内容…
    除去查找叶节点所需的资源和时间,其余的计算将在O(m)(m是边数)内完成,并使用恒定内存。

    详细说明一下,我会这样做(也发布在igraph邮件列表上):

    我将使用两个属性,一个用于顶点,一个用于边。edge属性很简单,它将被称为
    cut\u value
    ,它要么是
    None
    ,要么包含您要查找的值。最初,所有这些值都是
    None
    s。我们将使用
    cut\u value=None
    调用未处理的边,以及“cut\u value未处理”的边

    顶点属性将被称为
    cut\u size
    ,它将仅对存在一条未处理事件边的顶点有效。由于您有一棵树,因此您将始终至少有一个这样的顶点,除非处理所有边(您可以在其中终止算法)。最初,对于所有顶点,
    cut_size
    将为1(但请记住,它们仅对正好有一条未处理事件边的顶点有效)

    我们还将有一个列表
    deg
    ,其中包含给定节点上未处理的边的数量。最初所有边都未处理,因此此列表包含顶点的度数

    到目前为止,我们有:

    n, m = graph.vcount(), graph.ecount()
    cut_values = [None] * m
    cut_sizes = [1] * n
    deg = graph.degree()
    
    我们将始终只处理一条未处理边的顶点。最初,我们将其放入队列中:

    from collections import deque
    q = deque(v for v, d in enumerate(deg) if d == 1)
    
    然后,我们按如下方式逐个处理队列中的顶点,直到队列变为空:

  • 首先,我们从队列中移除一个顶点v,并找到它唯一未处理的关联边。让这条边用e表示

  • e的
    cut\u值
    是e的重量乘以
    min(cut\u大小[v],n-cut\u大小[v])

  • 让e的另一个端点用u表示。由于e现在已被处理,入射到u上的未处理边的数量减少了1,因此我们必须将
    deg[u]
    减少1。如果
    deg[u]
    变为1,我们将u放入队列中。我们还将其
    cut_size
    增加1,因为v现在是图形的一部分,当我们稍后删除u上的最后一条边时,它将被分离

  • 在Python中,这应该类似于以下代码(未测试):


    你好,尤里布,非常感谢你友好的回答。在B是一个brenching节点[存在另一条边(B,D)]的情况下,
    f(B,C)=(f(a,B)/weight(a,B)+1)*weight(B,C)
    将不起作用。嗯…嗨,塔玛斯,非常感谢。我正在测试你的算法。最后一行应该是第一眼看到的
    cut\u size[u]+=cut\u size[v]
    ,我不这么认为;移除
    u-v
    边缘时,一个尺寸的切口的尺寸应正好高出一个,因为
    v
    现在位于切口的“另一侧”。至少我希望它是这样工作的:)假设一个图类似于
    a-B(E)-C-D
    ,E是一个通过B-E连接到B的顶点。a、D和E将得到一个剪切大小为1并按顺序排列,而B则在进入队列之前更新为2(=剪切大小[E]+1)。但是根据算法,切割尺寸[B]应该是3;问题是无论
    deg[u]=1与否,
    cut_size[u]
    都应该增加;将在一分钟内更新我的代码。谢谢您的输入。这两个问题是相关的,因为众所周知的算法意味着存在一个更好的优化例程。
    from collections import deque
    q = deque(v for v, d in enumerate(deg) if d == 1)
    
    weights = graph.es["weight"]
    while q:
        # Step 1
        v = q.popleft()
        neis = [e for e in graph.incident(v) if cut_value[e] is None]
        if len(neis) != 1:
            raise ValueError("this should not have happened")
        e = neis[0]
    
        # Step 2
        cut_values[e] = weights[e] * min(cut_sizes[v], n - cut_sizes[v])
    
        # Step 3
        endpoints = graph.es[e].tuple
        u = endpoints[1] if endpoints[0] == v else endpoints[0]
        deg[u] -= 1
        if deg[u] == 1:
            q.append(u)
        cut_sizes[u] += 1