传递闭包python元组
有人知道是否有python内置的用于计算元组传递闭包的工具吗 我有形式为传递闭包python元组,python,closures,Python,Closures,有人知道是否有python内置的用于计算元组传递闭包的工具吗 我有形式为(1,2)、(2,3)、(3,4)的元组,我试图得到(1,2)、(2,3)、(3,4)、(1,3)(2,4) 谢谢。请快速尝试: def transitive_closure(elements): elements = set([(x,y) if x < y else (y,x) for x,y in elements]) relations = {} for x,y in elements:
(1,2)、(2,3)、(3,4)
的元组,我试图得到(1,2)、(2,3)、(3,4)、(1,3)(2,4)
谢谢。请快速尝试:
def transitive_closure(elements):
elements = set([(x,y) if x < y else (y,x) for x,y in elements])
relations = {}
for x,y in elements:
if x not in relations:
relations[x] = []
relations[x].append(y)
closure = set()
def build_closure(n):
def f(k):
for y in relations.get(k, []):
closure.add((n, y))
f(y)
f(n)
for k in relations.keys():
build_closure(k)
return closure
传递闭包没有内置函数 不过,它们的实现非常简单 以下是我对它的看法:
def transitive_closure(a):
closure = set(a)
while True:
new_relations = set((x,w) for x,y in closure for q,w in closure if q == y)
closure_until_now = closure | new_relations
if closure_until_now == closure:
break
closure = closure_until_now
return closure
电话:
传递闭包([(1,2)、(2,3)、(3,4)])
结果:
set([(1,2)、(1,3)、(1,4)、(2,3)、(3,4)、(2,4)])
电话:
传递闭包([(1,2),(2,1)])
结果:
set([(1,2),(1,1),(2,1),(2,2)])
我们可以从给定的“开始节点”执行“闭合”操作,方法是从当前“端点”重复获取“图边”的并集,直到找不到新端点为止。我们最多需要这样做(节点数-1)次,因为这是路径的最大长度。(这样做可以避免在存在循环的情况下陷入无限递归;在一般情况下,这将浪费迭代,但可以避免检查我们是否完成的工作,即在给定迭代中没有进行任何更改。)
(我实际上测试过一次;)次优,但概念上简单的解决方案:
def transitive_closure(a):
closure = set()
for x, _ in a:
closure |= set((x, y) for y in dfs(x, a))
return closure
def dfs(x, a):
"""Yields single elements from a in depth-first order, starting from x"""
for y in [y for w, y in a if w == x]:
yield y
for z in dfs(y, a):
yield z
当关系中存在一个循环,即自反点时,这将不起作用。这里有一个与@soulcheck中的一个基本相同的循环,它适用于邻接列表而不是边列表:
def inplace_transitive_closure(g):
"""g is an adjacency list graph implemented as a dict of sets"""
done = False
while not done:
done = True
for v0, v1s in g.items():
old_len = len(v1s)
for v2s in [g[v1] for v1 in v1s]:
v1s |= v2s
done = done and len(v1s) == old_len
如果你有很多TUPEL(5000以上),你可能想考虑使用SIMPY代码来处理矩阵幂(也见)
在最好的情况下,如果你对你的关系/图有一点了解,你可以明智地选择n
——这就是最长路径的长度。否则,您必须选择M.shape[0]
,它可能会在您的脸上爆炸
这种迂回也有其局限性,特别是您应该确保闭包不会变得太大(连接性不是太强),但在python实现中也会遇到同样的问题。您可以从这些元组创建一个图,然后从创建的图使用连接组件算法。是支持连接组件算法的库。这里的“可传递”和“闭包”是什么意思?(1,3)和(2,4)的出现原理是什么?元组的长度总是一样的吗?“计算元组”是什么意思?更多关于传递闭包的内容。基本上,原则是如果在元组的原始列表中有两个元组,形式为
(a,b)
和(c,z)
,并且b
等于c
,那么我们添加元组(a,z)
元组将始终有两个条目,因为它是一个二进制关系。“计算元组”是指扩展元组的原始列表,使之成为可传递闭包。谢谢。我完全不知道这个概念。既然它出现了(2,4),那么(1,4)是否也应该出现在(1,2)和新的(2,4)中?如果有内置的东西,它就会出现,但它似乎不存在(内置的)。也许关系不是正确的名称;它只是为每个数字存储其他“可到达”的数字,构建一个DAG。递归函数build\u closure
创建访问图的所有匹配项(此解决方案具有很强的输入假设,更灵活(和复杂)的输入可能更适合其他输入)[duh,注释已删除..将此答案留作参考]如果输入中存在循环,则将运行无限递归。(我第一次误解了代码,不知何故认为您在构建关系时是在迭代成对的元素,而不是解包单个元素的元组)我希望传递闭包([(1,2),(2,1)]
在输出中包括(像我一样)(1,1)
和(2,2)
,但我不知道OP到底想要什么…@KarlKnechtel:这就是传递性和反身性闭包。你说得对,karl。我刚刚点击了RuntimeError:cmp中超过了最大递归深度,非常优雅。不要介意我之前的评论:)顺便说一句,new_relations
严格地用集合论的术语来表示关系,或者用图的术语来表示边。在第二次调用的结果中我们不应该有(2,2)
。@Duke是的,你应该(2,2)=(2,1)*(1,2)@Duke:如果xRy和yRz,那么R的传递闭包包括(x,z)。在这种情况下,x=z=2,y=1,所以应该包括(2,2)。这是Warshall算法吗?它在循环中会失败。@soulcheck:你说得对。证明;已经有很多更好的解决方案发布了。它很容易纠正,就像在典型的dfs中一样。看到循环后,返回创建循环的节点并回溯。
def transitive_closure(a):
closure = set()
for x, _ in a:
closure |= set((x, y) for y in dfs(x, a))
return closure
def dfs(x, a):
"""Yields single elements from a in depth-first order, starting from x"""
for y in [y for w, y in a if w == x]:
yield y
for z in dfs(y, a):
yield z
def inplace_transitive_closure(g):
"""g is an adjacency list graph implemented as a dict of sets"""
done = False
while not done:
done = True
for v0, v1s in g.items():
old_len = len(v1s)
for v2s in [g[v1] for v1 in v1s]:
v1s |= v2s
done = done and len(v1s) == old_len
from scipy.sparse import csr_matrix as csr
def get_closure(tups):
index2id = list(set([tup[0] for tup in tups]) | set([tup[1] for tup in tups]));
id2index = {index2id[i]:i for i in xrange(len(index2id))};
tups_re = tups + [(index2id[i],index2id[i],) for i in xrange(len(index2id))]; # Unfortunately you have to make the relation reflexive first - you could also add the diagonal to M
M = csr( ([True for tup in tups_re],([id2index[tup[0]] for tup in tups_re],[id2index[tup[1]] for tup in tups_re])),shape=(len(index2id),len(index2id)),dtype=bool);
M_ = M**n; # n is maximum path length of your relation
temp = M_.nonzero();
#TODO: You might want to remove the added reflexivity tupels again
return [(index2id[temp[0][i]],index2id[temp[1][i]],) for i in xrange(len(temp[0]))];