我有一个无向的彩色(相邻节点具有不同的颜色)图,我需要计算一个哈希值,以便如果两个图是同构的,则它们具有相同的哈希值(该图也是平面的,我不知道它是否可以有所不同)。
我的数据结构是这样的:
class Node:
def __init__(self, id, color):
self.id = id # int
self.color = color # string
self.adjacentNodes = set()
id
属性用于程序逻辑,因此在比较图形时不应将其考虑在内。
我的想法是对图的节点进行排序,然后从第一个节点开始,探索相邻的节点,以生成图的树。 然后,我从树上生成一个唯一的字符串(实际上,我是在探索过程中生成的)。 因此,我要尝试的是找到一种图形规范化。
说明
我首先按 degree 排序节点,然后按 color 属性名称按升序排序。 我选择第一个节点并开始探索相邻节点,并先进行深度搜索,然后以相同的方式对其进行排序。 我会跟踪已经访问过的节点,以避免扩展旧节点。
我的字符串是这样生成的:使用深度优先搜索,每次到达新节点时,都会在图字符串上附加以下内容:
也许是多余的,但我认为这些信息足以保证正确的正典化。
真正的问题是两个节点在排序过程中具有相同的 degree 和相同的 color 。 我所做的应该保证规范化,但是效率不高。 采取一组相似的节点(度数和颜色相同),我为每个节点生成一个子树,并为该子树生成关联的字符串,然后在节点排序中选择最大的一个(按降序排列)。 然后,我删除最后一个节点,并重复该操作,直到该组为空。 之所以需要这样做,是因为在选择了第一个节点之后,我可能已经更改了访问节点的列表,然后新的字符串可能有所不同。
当前,此实现效率很低:
# actually this function return the unique string associated with the graph
# that will be hashed with the function hash() in a second moment
def new_hash(graph, queue=[]): # graph: list of Node
if not queue: # first call: find the root of the tree
graph.sort(key = lambda x: (len(x.adjacentNodes), x.color), reverse=True)
groups = itertools.groupby(graph, key = lambda x: (len(x.adjacentNodes), x.color))
roots = []
result_hash = ''
for _, group in groups:
roots = [x for x in group]
break # I just need the first (the candidates roots)
temp_hashes = []
for node in roots:
temp_queue = [node.id]
temp_hash = node.color + str(len(node.adjacentNodes)) + str(temp_queue.index(node.id))
temp_hash += new_hash(list(node.adjacentNodes), temp_queue)
temp_hashes.append((node, temp_hash, temp_queue))
temp_hashes.sort(key = lambda x: x[1], reverse=True)
queue = temp_hashes[0][2]
result_hash += temp_hashes[0][1]
result_hash += new_hash(list(temp_hashes[0][0].adjacentNodes), queue=queue)
else:
graph.sort(key = lambda x: (len(x.adjacentNodes), x.color), reverse=True)
groups = itertools.groupby(graph, key = lambda x: (len(x.adjacentNodes), x.color))
grouped_nodes = []
result_hash = ''
for _, group in groups:
grouped_nodes.append([x for x in group])
for group in grouped_nodes:
while len(group) > 0:
temp_hashes = []
for node in group:
if node.id in queue:
temp_hash = node.color + str(len(node.adjacentNodes)) + str(queue.index(node.id))
temp_hashes.append((node, temp_hash, queue))
else:
temp_queue = queue[:]
temp_queue.append(node.id)
temp_hash = node.color + str(len(node.adjacentNodes)) + str(temp_queue.index(node.id))
temp_hash += new_hash(list(node.adjacentNodes), queue=temp_queue)
temp_hashes.append((node, temp_hash, temp_queue))
temp_hashes.sort(key = lambda x: x[1], reverse=True)
queue = temp_hashes[0][2]
result_hash += temp_hashes[0][1]
group.remove(temp_hashes[0][0])
return result_hash
问题
因此,我有两个问题: