简体   繁体   中英

Error in the algorithm of ordering nodes in the undirected graph

The idea is to construct a list of the nodes in the undirected graph ordered by their degrees. Graph is given in the form {node: (set of its neighbours) for node in the graph}

The code raises KeyError exception at the line "graph[neighbor].remove(node)". It seems like the node have already been deleted from the set, but I don't see where.

Can anyone please point out at the mistake?

Edit: This list of nodes is used in the simulation of the targeted attack in order of values of nodes in the graph. So, after an attack on the node with the biggest degree, it is removed from the node, and the degrees of the remaining nodes should be recalculated accordingly.

def fast_targeted_order(graph):
    """returns an orderedv list of the nodes in the graph in decreasing 
    order of their degrees"""

    number_of_nodes = len(graph)  
    # initialise a list of sets of every possible degree
    degree_sets = [set() for dummy_ind in range(number_of_nodes)]

    #group nodes in sets according to their degrees
    for node in graph:
        degree = len(graph[node])
        degree_sets[degree] |= {node}

    ordered_nodes = []
    #starting from the set of nodes with the maximal degree
    for degree in range(number_of_nodes - 1, -1, -1):

        #copy the set to avoid raising the exception "set size changed 
        during the execution
        copied_degree_set = degree_sets[degree].copy()
        while degree_sets[degree]:

            for node in copied_degree_set:
                degree_sets[degree] -= {node}
                for neighbor in graph[node]:
                    neighbor_degree = len(graph[neighbor])
                    degree_sets[neighbor_degree] -= {neighbor}
                    degree_sets[neighbor_degree - 1] |= {neighbor}
                    graph[neighbor].remove(node)

            ordered_nodes.append(node)
            graph.pop(node)

    return ordered_nodes

My previous answer (now deleted) was incorrect, the issue was not in using set, but in deleting items in any sequence during iteration through the same sequence.

Python tutorial for version 3.1 clearly warns:

It is not safe to modify the sequence being iterated over in the loop (this can only happen for mutable sequence types, such as lists). If you need to modify the list you are iterating over (for example, to duplicate selected items) you must iterate over a copy.

However, tutorial for Python 3.5. (which I use) only advises:

If you need to modify the sequence you are iterating over while inside the loop (for example to duplicate selected items), it is recommended that you first make a copy.

It appears that this operation is still very unpredictable in Python 3.5, producing different results with the same input.

From my point of view, the previous version of the tutorial is preferred to the current one.

@PetarPetrovic and @jdehesa, thanks for the valuable advice.

Working solution:

def fast_targeted_order(ugraph):
    """
    input: undirected graph in the form {node: set of node's neighbors)
    returns an ordered list of the nodes in V in decresing order of their degrees
    """

    graph = copy_graph(ugraph)
    number_of_nodes = len(graph)

    degrees_dict = {degree: list() for degree in range(number_of_nodes)}

    for node in graph:
        degree = len(graph[node])
        degrees_dict[degree].append(node)

    ordered_degrees = OrderedDict(sorted(degrees_dict.items(), 
                                  key = lambda key_value: key_value[0],
                                  reverse = True))
    ordered_nodes = []

    for degree, nodes in ordered_degrees.items():
        nodes_copy = nodes[:]
        for node in nodes_copy:
            if node in nodes:

                for neighbor in graph[node]:
                    neighbor_degree = len(graph[neighbor])
                    ordered_degrees[neighbor_degree].remove(neighbor)
                    if neighbor_degree:
                        ordered_degrees[neighbor_degree - 1].append(neighbor)
                    graph[neighbor].remove(node)

                graph.pop(node)
                ordered_degrees[degree].remove(node)
                ordered_nodes.append(node)

    return ordered_nodes

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM