def calculate(self, graph): ''' Calculate the minimum spanning tree of the given graph. @type graph: graph @param graph: Graph of which the minimum spanning tree is calculated. @rtype graph @return the minimum spanning tree ''' # create emty graph to store the mst mst = Graph(graph.distance_lookup, graph.node_s, graph.node_t) # create priority queue neighbour_edges = PQueue() # take the first node as start node start_node = min(graph.nodes) # add first node to mst mst.add_node(start_node) #neighbour_edges = graph.neighbour_edges(start_node) for new_edge in graph.neighbour_edges(start_node): neighbour_edges.add_item(new_edge.weight, new_edge) # get size of the current graph graph_size = graph.size # lookup antoher edge as long as the two graphs are the same size while mst.size < graph_size: # take next edge next_edge = neighbour_edges.get_top_priority() # remove edge from the original graph graph.remove_edge(next_edge) # if both nodes are already in the mst we skip the edge if not(mst.contains_node(next_edge.node_1) and \ mst.contains_node(next_edge.node_2)): # add new reachable edges to the neighbour_edges list if mst.contains_node(next_edge.node_1): next_edges = graph.neighbour_edges(next_edge.node_2) for new_edge in next_edges: neighbour_edges.add_item(new_edge.weight, new_edge) mst.add_node(next_edge.node_2) else: next_edges = graph.neighbour_edges(next_edge.node_1) for new_edge in next_edges: neighbour_edges.add_item(new_edge.weight, new_edge) mst.add_node(next_edge.node_1) # add edge to mst mst.add_edge(next_edge) return mst
def calculate(self, graph, tour=True): ''' Calculate the euler tour in a given graph @type graph: graph @param graph: Graph to calculate eulerian tour/path. @type tour: boolean @param tour: If True, an eulerian tour is calculated, if false an eulerian path is calculated. @rtype: list @return: A list of nodes in order of the eulerian tour/path. ''' euler = list() euler_graph = Graph() # save start node, so we can check if we did a cycle start_node = min(graph.nodes) # for the first walk our start_node is the current_node current_node = start_node # we want wo walk at least once condition = True # get size of the current graph graph_size = graph.size while euler_graph.size < graph_size: # list to store nodes for each cycle euler_sub = list() # list to store a copy of the original euler list, needed to merge euler # with euler_sub euler_tmp = list() # loop until we hit the start_node, but at least once while condition: # add the current node to the euler tour euler_sub.append(current_node) # take a neighbour neighbours = graph.neighbour_nodes(current_node) next_node = min(list(neighbours.copy().keys())) # get the edge between the current node an our new node # if there is more than one edge, just take the first one edge_list = graph.edge_by_nodes(current_node, next_node) current_edge = min(edge_list) # delete the edge from the graph, we don't want to the the same edge twice graph.remove_edge(current_edge) # add nodes and edges to the graph that represents the euler cycle if not euler_graph.contains_node(current_node): euler_graph.add_node(current_node) if not euler_graph.contains_node(next_node): euler_graph.add_node(next_node) euler_graph.add_edge(current_edge) # start agein with the next_node as current_node current_node = next_node # check if we hit the start_node condition = (current_node != start_node) # edge to the last node euler_sub.append(current_node) # merge current cycle with the already computed one euler = self.merge_cycles(euler, euler_sub, current_node) for node in euler: if graph.contains_node(node): neighbours = graph.neighbour_nodes(node) if len(neighbours) > 0: start_node = node current_node = start_node condition = True break if tour == False: euler = self.euler_path(euler, graph.node_s, graph.node_t) # return a list of nodes in the order of the euler tour return euler
def euclidean(self, file_location, node_s_nr = -1, node_t_nr = -1): ''' Read a file that contains nodes and theire coordinates. Create a complete undirected graph. File format: ID_Node Position_1 Position_2 Position_3 ... @type file_location: string @param file_location: location to save the file @type node_s_nr: int @param node_s_nr: Number to identify node s @type node_t_nr: int @param node_t_nr: Number to identify node t ''' graph = Graph() dimension = 0 euc_dimension = 0 nodes = list() f = open(file_location, 'r') # read id, x-coordinate and y-coordinate for line in f: line_data = line.split() # skip header information if line_data[0].isdigit(): # the first column is the node nr. node_nr = line_data[0] # all other rows are coordinates node_coordinates = line_data[1:] # check if euclidean dimensions match if euc_dimension != len(node_coordinates): raise EuclideanDimensionMissmatchError(euc_dimension, \ len(node_coordinates)) # convert coordinates to float node_coordinates = [float(i) for i in node_coordinates] else: line_data = line.split(':') if line_data[0].strip() == 'EDGE_WEIGHT_TYPE': match = re.search('\d+',line_data[1]) euc_dimension = int(match.group(0)) if line_data[0].strip() == 'DIMENSION': dimension = int(line_data[1]) continue temp_node = Node(node_nr, node_coordinates) nodes.append(temp_node) # set node s if temp_node.nr == int(node_s_nr): graph.node_s = temp_node # set node t if temp_node.nr == int(node_t_nr): graph.node_t = temp_node # check if dimensions match if dimension != len(nodes): raise DimensionMissmatchError(dimension, len(nodes)) # calculate distance and add nodes and edges to the graph for node_1 in nodes: graph.add_node(node_1) for node_2 in nodes: if node_1 != node_2: if not graph.contains_node(node_2): graph.add_node(node_2) # calculate distance for n dimensions total = 0 for i in range(0, len(node_1.coordinates)): total += ((node_1.coordinates[i]-node_2.coordinates[i])**2) temp_distance = math.sqrt(total) temp_edge = Edge(node_1, node_2, temp_distance) graph.add_edge(temp_edge) else: # break, because the graph is undirected # when we add an edge it will create both directions # e.g. node_1 node_2 with weight 5 was added, then # node_2 node_1 with weight 5 is added too break f.close() return graph