【发布时间】:2013-01-10 00:40:44
【问题描述】:
如何将有向无环图转换为散列值,以使任意两个同构图散列到相同的值?两个同构图散列到不同的值是可以接受的,但不可取,这就是我在下面的代码中所做的。我们可以假设图中的顶点数最多为 11 个。
我对 Python 代码特别感兴趣。
这就是我所做的。如果self.lt 是从节点到后代(不是孩子!)的映射,那么我会根据修改后的拓扑排序重新标记节点(如果可以的话,它更喜欢首先对具有更多后代的元素进行排序)。然后,我对排序后的字典进行哈希处理。一些同构图会散列成不同的值,尤其是随着节点数量的增长。
我已经包含了所有代码来激发我的用例。我正在计算找到 7 个数字的中位数所需的比较次数。同构图哈希到相同值的次数越多,需要重做的工作就越少。我考虑过先放置更大的连接组件,但没有看到如何快速做到这一点。
from tools.decorator import memoized # A standard memoization decorator
class Graph:
def __init__(self, n):
self.lt = {i: set() for i in range(n)}
def compared(self, i, j):
return j in self.lt[i] or i in self.lt[j]
def withedge(self, i, j):
retval = Graph(len(self.lt))
implied_lt = self.lt[j] | set([j])
for (s, lt_s), (k, lt_k) in zip(self.lt.items(),
retval.lt.items()):
lt_k |= lt_s
if i in lt_k or k == i:
lt_k |= implied_lt
return retval.toposort()
def toposort(self):
mapping = {}
while len(mapping) < len(self.lt):
for i, lt_i in self.lt.items():
if i in mapping:
continue
if any(i in lt_j or len(lt_i) < len(lt_j)
for j, lt_j in self.lt.items()
if j not in mapping):
continue
mapping[i] = len(mapping)
retval = Graph(0)
for i, lt_i in self.lt.items():
retval.lt[mapping[i]] = {mapping[j]
for j in lt_i}
return retval
def median_known(self):
n = len(self.lt)
for i, lt_i in self.lt.items():
if len(lt_i) != n // 2:
continue
if sum(1
for j, lt_j in self.lt.items()
if i in lt_j) == n // 2:
return True
return False
def __repr__(self):
return("[{}]".format(", ".join("{}: {{{}}}".format(
i,
", ".join(str(x) for x in lt_i))
for i, lt_i in self.lt.items())))
def hashkey(self):
return tuple(sorted({k: tuple(sorted(v))
for k, v in self.lt.items()}.items()))
def __hash__(self):
return hash(self.hashkey())
def __eq__(self, other):
return self.hashkey() == other.hashkey()
@memoized
def mincomps(g):
print("Calculating:", g)
if g.median_known():
return 0
nodes = g.lt.keys()
return 1 + min(max(mincomps(g.withedge(i, j)),
mincomps(g.withedge(j, i)))
for i in nodes
for j in nodes
if j > i and not g.compared(i, j))
g = Graph(7)
print(mincomps(g))
【问题讨论】:
-
Goggling “图的哈希值”让我看到了 Ashish Kundu 和 Elisa Bertino 撰写的这篇有趣的论文,名为“On Hashing Graph”,关于哈希 DAG 的解决方案(使用 2 O(1) 操作) .我还没有达到可以将这篇论文提炼成你问题的答案的水平,但我读起来很开心:)
-
还有一个叫做“Merkle Signature Schemes”的东西,如果有帮助的话,Kundu & Bertino 论文网站可以作为起始解决方案
-
顶点或边上是否有标签?如果不是,同构图是否应该散列到相同的值?
-
需要散列唯一,还是通常唯一? (后者是 Python 对象散列函数所需的全部内容。)
-
@NeilG 您是否暗示您正在使用一种可以有效检测两个图是否同构(GI)的算法?你知道不知道 GI 是在
P还是NP(假设NP != P),对吧?我不知道有什么比 nauty (cs.anu.edu.au/~bdm/nauty) 更正确的事情。我记得几年前的一些事情证明了 GI 在P中(作者还包括了一个O(n^5)算法),但是证明是有缺陷的,我不确定它是否最终被发布。
标签: python algorithm hash directed-acyclic-graphs