Beispiel #1
0
    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
Beispiel #2
0
    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
Beispiel #3
0
    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