如何在Snap.py中复制Graph对象?

2 投票
2 回答
1180 浏览
提问于 2025-04-18 03:07

我尝试使用 copy.deepcopy(graph) 但遇到了一个错误:

我的代码:

new_graph = TNEANet.New()
....
# some define for new_graph
....
copy_graph = copy.deepcopy(new_graph)

执行错误:

TypeError: object.__new__(SwigPyObject) is not safe, use SwigPyObject.__new__()

我还发现这个API有一个定义,API文档。所以我尝试使用 TNEANet(Graph) 来完成这个任务:

new_graph = TNEANet.New()
....
# some define for new_graph
....
copy_graph = TNEANet(new_graph)

执行错误:

TypeError: in method 'new_TNEANet', argument 1 of type 'TSIn &'

2 个回答

1

简短回答

最好的办法是自己复制节点、边和属性。我发现把数据导出到文件再重新加载也能很好地工作,不过如果你在使用PNEANet,那么属性就不会被复制。这里有一个我用来复制图的方便函数(比逐个遍历要快):

def copy_graph(graph):
    tmpfile = '.copy.bin'

    # Saving to tmp file
    FOut = snap.TFOut(tmpfile)
    graph.Save(FOut)
    FOut.Flush()

    # Loading to new graph
    FIn = snap.TFIn(tmpfile)
    graphtype = type(graph)
    new_graph = graphtype.New()
    new_graph = new_graph.Load(FIn)

    return new_graph

详细回答

有一种方法可以深度复制你的图:

import snap
new_graph = snap.TNEANet.New()
....
# some define for new_graph
....
copy_graph = snap.TNEANet(new_graph())

(这适用于任何类型的图) 问题在于它返回的是snap.TNEANet,而我们需要的是snap.PNEANet。后者在C++实现中只是前者的一个指针,但我们在Python中无法创建这个指针。因此,copy_graph的功能会比new_graph少。

解释

SNAP在Python中使用了一种代理表示,这在某种程度上使得深度复制过程变得复杂。复制构造函数期望的是非代理类型,而你给它的是Python的代理类型。 这会引发一个TypeError,显示它所知道的第一个构造函数的签名(这个和我们的问题完全无关)。

为了解决这个问题,我们需要给构造函数提供底层的C++类型,这可以通过使用self.__call__()方法来获得。

但由于C++的(不太好?)实现,snap.TNEANet(new_graph())输出的是snap.TNEANet。这意味着这个函数的输出将是一个非代理类型。因此,它将无法与大多数SNAP功能正常工作……

3

你可以使用 ConvertGraph 方法来复制一个图(图在这里指的是一种数据结构)。只需要确保你用的图的类型和你想要的目标类型是一样的就可以了:

graph = snap.TNEANet.New()

graph.AddNode(1)
graph.AddNode(2)
graph.AddEdge(1,2)

copy_graph = snap.ConvertGraph(type(graph), graph)

撰写回答