【问题标题】:Generator comprehensions for look ahead algorithm in PythonPython中前瞻算法的生成器理解
【发布时间】:2014-08-22 15:14:33
【问题描述】:

我昨天就如何在 Python 中展望未来寻求帮助。我的问题是遍历所有可能的边以添加到网络中,并且对于添加了边的每个可能的网络,查看要添加的所有可能的边,依此类推(n 深度)。最后,将在深度 n 生成的所有网络与根网络进行比较,并实际添加最佳第一步(添加的最佳第一条边以在深度 n 处获得最佳结果)。添加第一条边后,再次进行深度搜索,依此类推,直到找到一个好的网络。我可以说就像一个移动的窗口(请参阅lookahead algorithm in Python 以获得对问题的更全面的解释)。

不幸的是,为了问题的清晰,代码需要 igraph,可在此处获得:http://igraph.org/python/#downloads

@Peter Gibson 及时回答,指导我了解生成器推导的逻辑,并帮助我生成以下代码:

from igraph import * # http://igraph.org/python/

def delta(g,gOld): # evaluates the improvement of the graph from one generation to the next 
   print "delta"
   return g.diameter()-gOld.diameter()

def possible_new_edges(G):
    print "Possible new edges"
    allPossibleNewEdges = []
    for n1 in range(50):
        for n2 in range(n1,50):
            if G.are_connected(G.vs[n1],G.vs[n2]) == False and n1 != n2:
                allPossibleNewEdges.append(G.vs[n1],G.vs[n2])
    return allPossibleNewEdges

def add_optimal_edge(graph, n=3):
    print "Add optimal edge"

    paths = [[graph]] # start off with just one graph path, which contains a single graph
    for generation in range(n):
        print "Generation:", generation

        # path[-1] is the latest graph for each generation
        paths = (path + path[-1].add_edge(e) for path in paths for e in path[-1].possible_new_edges())
    # select best path by comparison of final generation against original graph 
    best = max(paths, lambda path: comp_delta(path[-1],graph)) 
    return best[1] # returns the first generation graph

graph = Graph.Erdos_Renyi(50, .15, directed=False, loops=False) # create a random root graph of density 0.15

add_optimal_edge(graph)

生成器简洁优雅。让我们说对于我笨拙的 Python 风格来说有点过于优雅了,我需要了解一些事情才能使它工作。代码运行时出现此错误:

return best[1] # returns the first generation graph
TypeError: 'generator' object has no attribute '__getitem__'

我认为这是因为错误地使用了生成器的函数...

所以,我的问题是:在这样的生成器中使用函数的正确方法是什么?我需要调用 possible_new_edges() 和 delta(),我需要传递什么(图表?)以及如何传递?

非常感谢!

【问题讨论】:

  • 糟糕,由于引用了另一个问题,该问题被否决了?或者它只是不清楚或无用?请告诉我,然后我会相应地编辑
  • 不清楚您所说的“代码什么都不做”是什么意思。调用add_optimal_edge(graph) 后的返回值是多少?你有例外吗?我无法运行您的代码,因为它依赖于您未显示的一些代码(大概是一个库,尽管您没有为其应用标签或在问题文本中指定它的内容),所以没有办法我自己试试看。你需要深入地解释发生了什么。
  • 哦,好的...感谢您的精确度。所以调用的库是 igraph (igraph.org/python),它帮助创建和操作图形。这很棒。代码运行良好,没有引发异常,只是看起来它没有迭代。好像每次迭代都没有调用函数。这就是为什么我猜我的函数没有被正确调用。这是我第一次将手放在发电机中,对于缺乏精确或精确的词汇感到抱歉。干杯!
  • 你怎么知道函数没有被调用?您是否添加了一些您没有提到的调试内容?最后调用add_oprimal_edge 会返回什么?
  • 哦,我的错,我在计算机上运行的代码略有不同。代码在打印“添加最佳边缘生成:0 代:1 代:2”后确实会引发错误,请参阅编辑后的问题。抱歉浪费时间@Blckknght

标签: python algorithm generator list-comprehension igraph


【解决方案1】:

尝试your gist 中的代码,我发现了几个相当小的错误,这些错误阻止了代码运行。我在下面包含了固定代码。然而,这并不能真正解决问题。那是因为您的算法需要考虑真正大量的潜在图,而这在任何合理的时间内都无法做到。

在我的测试中,向前看一步效果很好,但看两步需要很长时间(至少 10 分钟,我从来没有等过它完成),而三步可能需要几天时间。这是因为您的 possible_new_edges 函数返回一千多个可能的边。每个都将添加到您的初始图表的副本中。然后对于每个后续步骤,该过程将在上一步的每个扩展图上重复。这会导致图表呈指数级增长,因为您必须按照 1000**n 图表的顺序评估某些内容,以查看哪个是最好的。

因此,要获得实际结果,您仍然需要进行更改。我不太了解图论或您的问题领域,无法提出建议。

无论如何,这是“工作”代码的更改部分(删除了原始 cmets,以便我对更改内容的注释更加清晰):

def possible_new_edges(G):

    print("Possible new edges")

    allPossibleNewEdges = []
    for n1 in range(50):
        for n2 in range(n1,50):
            if G.are_connected(G.vs[n1],G.vs[n2]) == False and n1 != n2:
                allPossibleNewEdges.append((G.vs[n1],G.vs[n2]))        # append a tuple
    return allPossibleNewEdges

def add_optimal_edge(graph, n=3):

    print("Add optimal edge")

    paths = [[graph]]
    for generation in range(n):

        print("Generation:", generation)

        paths = (path + [path[-1] + e]   # use + to add an edge, and to extend the path
                 for path in paths
                 for e in possible_new_edges(path[-1]))   # call this function properly
    best = max(paths, key=lambda path: comp_delta(path[-1],graph)) 
    return best[1]

如果循环中的生成器表达式让您感到困惑,用列表推导替换它可能会有所帮助(通过用方括号替换最外面的括号)。然后,您可以检查循环内的paths 列表(并执行诸如打印其len() 之类的操作)。无论哪种方式,代码的逻辑都是相同的,生成器表达式只是推迟计算扩展结果,直到 max 函数开始迭代 paths 以找到最佳得分。

使用列表推导当然适用于n=1,但是当你尝试n=2 时,你可能会开始耗尽内存(你肯定会使用n=3 或更多)。上面的版本不会耗尽​​内存(因为生成器表达式一次只扩展 O(n) 图形),但这并不意味着它运行速度足够快,可以在合理的时间内检查数十亿个图形。

【讨论】:

  • 这看起来非常好,我不能感谢你的所有努力。过几天我可以深入检查一下,然后我会回复评论...干杯!
  • 快速运行,它似乎工作得很好......不过它的 CPU 密集度很高......对于 10 个顶点的非常小的图形,查找深度 3 或 4 似乎是可行的。不过,我正在使用更大的图表,也许我需要看看更高效的 cpu 方法(蒙特卡罗?)。再次感谢您!
  • @Rodolphe 或许可以尝试在 pypy.org 中运行它——如果你能让所有依赖项都运行起来,它往往会快得多
猜你喜欢
  • 2013-04-13
  • 2010-12-03
  • 2017-12-27
  • 2014-06-08
  • 2022-01-12
  • 1970-01-01
  • 2016-10-04
  • 2022-01-17
  • 1970-01-01
相关资源
最近更新 更多