Python 寻找超大图的分量

Python 寻找超大图的分量,python,algorithm,Python,Algorithm,我有一个非常大的图形,在一个大小约为1TB的文本文件中表示,每个边如下所示 From-node to-node 我想把它分成弱连接的部分。如果它更小,我可以将它加载到networkx并运行他们的组件查找算法。例如 有没有办法在不将整个内容加载到内存的情况下执行此操作?如果节点数足够少(例如,数亿个),则可以使用存储在内存中的节点通过文本文件的一次传递计算连接的组件 此数据结构仅存储每个节点的秩和父指针,因此,如果节点足够少,则应将其放入内存中 对于更多的节点,您可以尝试相同的想法,但将数据结

我有一个非常大的图形,在一个大小约为1TB的文本文件中表示,每个边如下所示

From-node to-node
我想把它分成弱连接的部分。如果它更小,我可以将它加载到networkx并运行他们的组件查找算法。例如


有没有办法在不将整个内容加载到内存的情况下执行此操作?

如果节点数足够少(例如,数亿个),则可以使用存储在内存中的节点通过文本文件的一次传递计算连接的组件

此数据结构仅存储每个节点的秩和父指针,因此,如果节点足够少,则应将其放入内存中

对于更多的节点,您可以尝试相同的想法,但将数据结构存储在磁盘上(并可能通过在内存中使用缓存来存储经常使用的项来改进)

下面是一些Python代码,它实现了不相交集林的简单内存版本:

N=7 # Number of nodes
rank=[0]*N
parent=range(N)

def Find(x):
    """Find representative of connected component"""
    if  parent[x] != x:
        parent[x] = Find(parent[x])
    return parent[x]

def Union(x,y):
    """Merge sets containing elements x and y"""
    x = Find(x)
    y = Find(y)
    if x == y:
        return
    if rank[x]<rank[y]:
        parent[x] = y
    elif rank[x]>rank[y]:
        parent[y] = x
    else:
        parent[y] = x
        rank[x] += 1

with open("disjointset.txt","r") as fd:
    for line in fd:
        fr,to = map(int,line.split())
        Union(fr,to)

for n in range(N):
    print n,'is in component',Find(n)
它打印

0 is in component 3
1 is in component 1
2 is in component 1
3 is in component 3
4 is in component 3
5 is in component 3
6 is in component 6

不使用秩数组可以节省内存,但可能会增加计算时间。

外部内存图遍历很难获得性能。我建议不要编写自己的代码,实现细节决定了几个小时的运行时间和几个月的运行时间。您应该考虑使用像这样的现有库。有关使用它计算连接组件的文章,请参阅。

如果节点的数量太大而无法放入内存,您可以分而治之,并使用外部内存排序来完成大部分工作(例如,Windows和Unix附带的
sort
命令可以对比内存大得多的文件进行排序):

  • 选择一些阈值顶点k
  • 读取原始文件并将其每个边写入3个文件中的一个:
    • a
      ,如果其最大编号顶点
    • 如果其最小编号顶点>=k,则转到
      b
    • c
      否则(即,如果它有一个顶点=k)
  • 如果
    a
    足够小,可以在内存中(使用例如)求解(查找连接的组件),则执行此操作,否则递归求解。解决方案应该是一个文件,其每行由两个数字组成
    xy
    ,并按
    x
    排序。每个
    x
    都是一个顶点编号,
    y
    是其代表-
    x
    所在组件中编号最低的顶点
  • b
    也要这样做
  • 按边的最小编号端点对
    c
    中的边进行排序
  • 遍历
    c
    中的每条边,将a的解决方案中找到。这可以通过使用线性时间合并算法与子问题
    a
    的解决方案合并来有效地实现。调用结果文件
    d
  • 按边的最大编号端点对
    d
    中的边进行排序。(事实上,我们已经重命名了编号最小的端点,这并不意味着这是不安全的,因为重命名永远不会增加顶点的编号。)
  • 通过
    d
    中的每条边,将>=k的端点重命名为其代表,如前所述,使用线性时间合并从子问题
    b
    的解决方案中找到。调用生成的文件
    e
  • 求解
    e
    。(与
    a
    b
    一样,如果可能的话,直接在内存中执行此操作,否则会递归。如果需要递归,则需要找到一种不同的边分区方式,因为
    e
    中的所有边都已“跨接”k.例如,您可以使用顶点编号的随机排列对顶点重新编号,递归以解决产生的问题,然后重新命名它们。)此步骤是必要的,因为可能存在一条边(1,k)、另一条边(2,k+1)和第三条边(2,k),这意味着组件1,2,k和k+1需要组合成单个组件
  • 检查子问题
    a
    解决方案中的每一行,如有必要,使用子问题
    e
    解决方案更新此顶点的代表。这可以使用线性时间合并有效地完成。将新的代表列表(由于我们是从
    a
    的解决方案创建的,因此已按顶点编号排序)写入文件
    f
  • 对子问题
    b
    的解决方案中的每一行执行类似操作,创建文件
    g
  • 连接
    f
    g
    以生成最终答案。(为了提高效率,只需让步骤11将其结果直接附加到
    f

  • 上面使用的所有线性时间合并操作都可以直接从磁盘文件中读取,因为它们只按递增顺序访问每个列表中的项目(即不需要慢速随机访问)。

    您是否估计可能涉及多少节点、边和组件?另外,你需要完美的精度,或者近似值可以接受吗?这很好。如果可用内存仅为此解决方案所需内存的一半,您会怎么做?不使用rank可以大致将内存减半。通过使用,您可以节省更多内存。之后,我可能会考虑将数据结构部分存储在磁盘上,如果您对节点的可能结构有更多的了解,那么您可能可以设计一种有效的分页结构来缓存当前重要的部分。顺便问一下,如果你不介意我问的话,这么大的图形的应用程序是什么?这是一个很好的建议,但我遗憾地发现stxxl没有python接口。
    0 is in component 3
    1 is in component 1
    2 is in component 1
    3 is in component 3
    4 is in component 3
    5 is in component 3
    6 is in component 6