递归:如何避免在迭代RuntimeError期间更改Python集

新秀:

背景和问题描述:

我有一些代码可以解决图形着色问题(广义地定义为将“颜色”分配给无向图的问题,请确保没有两个通过边连接的顶点具有相同的颜色)。我正在尝试使用约束传播来实现一种解决方案,以提高标准递归回溯算法的效率,但是却遇到以下错误:

  File "C:\Users\danisg\Desktop\coloring\Solver.py", 
  line 99, in solve
  for color in self.domains[var]:
  RuntimeError: Set changed size during iteration

在这里,对于每个顶点,我都会保留set该特定顶点可能的特定值:

  self.domains = { var: set(self.colors) for var in self.vars }

进行分配后,我将此约束传播到相邻域,以限制搜索空间:

  for key in node.neighbors:          # list of keys corresponding to adjacent vertices
      if color in self.domains[key]:  # remove now to prune possible choices
          self.domains[key].remove(color)

这不是引发实际错误的地方(在我的代码中,我指出了问题在哪里try-except),但可能是问题的根源。

我的问题:

如果没有正确的实施方法,我是否有正确的想法?更重要的是,我该如何解决?另外,是否有必要保留单独的domains词典?还是可以domain为图中的每个节点设置一个属性?

我的代码:

solve是调用此代码函数:

def solve(self):

    uncolored = [var for var in self.vars if self.map[var].color == None]
    if len(uncolored) == 0:
        return True

    var  = min(uncolored, key = lambda x: len(self.domains[var]))
    node = self.map[var]
    old  = { var: set(self.domains[var]) for var in self.vars }

    for color in self.domains[var]:

        if not self._valid(var, color):
            continue


        self.map[var].color = color
        for key in node.neighbors:

            if color in self.domains[key]:
                self.domains[key].remove(color)

        try:
            if self.solve():
                return True
        except:
            print('happening now')


        self.map[var].color = None
        self.domains = old


    return False

我的实现使用一个Node对象:

class Solver:

    class Node:

        def __init__(self, var, neighbors, color = None, domain = set()):

            self.var       = var
            self.neighbors = neighbors
            self.color     = color
            self.domain    = domain

        def __str__(self):
            return str((self.var, self.color))



    def __init__(self, graph, K):

        self.vars    = sorted( graph.keys(), key = lambda x: len(graph[x]), reverse = True )  # sort by number of links; start with most constrained
        self.colors  = range(K)
        self.map     = { var: self.Node(var, graph[var]) for var in self.vars }
        self.domains = { var: set(self.colors)           for var in self.vars }

这是另外两个有用/有用的功能:

def validate(self):

    for var in self.vars:
        node = self.map[var]

        for key in node.neighbors:
            if node.color == self.map[key].color:
                return False

    return True

def _valid(self, var, color):

    node = self.map[var]

    for key in node.neighbors:

        if self.map[key].color == None:
            continue

        if self.map[key].color == color:
            return False

    return True

代码失败的数据和示例:

我正在使用的示例图可以在这里找到

读取数据的功能:

def read_and_make_graph(input_data):

    lines = input_data.split('\n')

    first_line = lines[0].split()
    node_count = int(first_line[0])
    edge_count = int(first_line[1])

    graph = {}
    for i in range(1, edge_count + 1):
        line  = lines[i]
        parts = line.split()
        node, edge = int(parts[0]), int(parts[1])

        if node in graph:
            graph[node].add(edge)

        if edge in graph:
            graph[edge].add(node)

        if node not in graph:
            graph[node] = {edge}

        if edge not in graph:
            graph[edge] = {node}

    return graph

应该这样称呼:

file_location = 'C:\\Users\\danisg\\Desktop\\coloring\\data\\gc_50_3'
input_data_file = open(file_location, 'r')
input_data = ''.join(input_data_file.readlines())
input_data_file.close()

graph  = read_and_make_graph(input_data)
solver = Solver(graph, 6)  # a 6 coloring IS possible

print(solver.solve())      # True if we solved; False if we didn't
损伤:

我认为问题出在这里:

for color in self.domains[var]:

    if not self._valid(var, color):
        continue

    self.map[var].color = color
    for key in node.neighbors:

        if color in self.domains[key]:
            self.domains[key].remove(color)  # This is potentially bad.

如果调用key == varwhen,self.domains[key].remove(color)则更改当前正在迭代的set的大小。您可以通过使用

for color in self.domains[var].copy():

使用copy()将允许您遍历集合的副本,同时从原始对象中删除项目。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

在迭代期间更改字典的递归方法

如何避免“ RuntimeError:字典在迭代过程中更改大小”错误?

在迭代期间更改 MutableList

如何在迭代迭代期间避免具有 css 类的少数链接

Python:如何避免使用递归调用?

如何递归地迭代复杂的python对象?

如何在递归组件中“避免直接更改道具”

迭代地图和更改值时如何避免ConcurrentModificationException?

如何将此代码从递归更改为迭代

如何将迭代代码更改为递归代码?

如何避免财产递归

Reactor - 如何避免递归?

如何避免在列表迭代期间返回空值(应该是默认结果)?

递归函数中变量解包期间的Python“Int对象不可迭代”

如何在python中的for循环的迭代期间使异常

如何在从LinkedList进行基于递归迭代器的删除时避免ConcurrentModificationException?

如何最好地迭代具有更改ID的查询集?

Python 3.7:如何避免这种递归方法的stackoverflow?

在这种情况下,python如何避免无限递归?

如何避免python类方法中的无限递归

threading.Timer 如何避免 Python 中的递归?

如何在字典中通过数据集进行迭代期间创建和填充列

如何更改迭代片段的大小(Python(

如何在 Python 中将递归转化为迭代?

在循环期间更改可迭代变量

如果使用@Autowired + @Qualifier注入,如何避免在重构期间更改bean名称

如何避免递归函数的StackOverflowError

模板如何避免无限递归?

在递归算法中的 return 语句期间,我的变量如何更改值?