Пример #1
0
    def edge_style(self, head, tail, **kwargs):
        '''
        Modifies an edge style to the dot representation.
        '''
        if tail not in self.nodes:
            raise GraphError("invalid node %s" % (tail, ))

        try:
            if tail not in self.edges[head]:
                self.edges[head][tail] = {}
            self.edges[head][tail] = kwargs
        except KeyError:
            raise GraphError("invalid edge  %s -> %s " % (head, tail))
Пример #2
0
    def add_edge(self, head_id, tail_id, edge_data=1, create_nodes=True):
        """
        Adds a directed edge going from head_id to tail_id.
        Arbitrary data can be attached to the edge via edge_data.
        It may create the nodes if adding edges between nonexisting ones.

        :param head_id: head node
        :param tail_id: tail node
        :param edge_data: (optional) data attached to the edge
        :param create_nodes: (optional) creates the head_id or tail_id
            node in case they did not exist
        """
        # shorcut
        edge = self.next_edge

        # add nodes if on automatic node creation
        if create_nodes:
            self.add_node(head_id)
            self.add_node(tail_id)

        # update the corresponding incoming and outgoing lists in the nodes
        # index 0 -> incoming edges
        # index 1 -> outgoing edges

        try:
            self.nodes[tail_id][0].append(edge)
            self.nodes[head_id][1].append(edge)
        except KeyError:
            raise GraphError('Invalid nodes %s -> %s' % (head_id, tail_id))

        # store edge information
        self.edges[edge] = (head_id, tail_id, edge_data)

        self.next_edge += 1
Пример #3
0
 def inc_edges(self, node):
     """
     Returns a list of the incoming edges
     """
     try:
         return list(self.nodes[node][0])
     except KeyError:
         raise GraphError('Invalid node %s' % node)
Пример #4
0
 def out_edges(self, node):
     """
     Returns a list of the outgoing edges
     """
     try:
         return list(self.nodes[node][1])
     except KeyError:
         raise GraphError('Invalid node %s' % node)
Пример #5
0
    def edge_by_id(self, edge):
        """
        Returns the edge that connects the head_id and tail_id nodes
        """
        try:
            head, tail, data = self.edges[edge]
        except KeyError:
            head, tail = None, None
            raise GraphError('Invalid edge %s' % edge)

        return (head, tail)
Пример #6
0
 def restore_edge(self, edge):
     """
     Restores a previously hidden edge back into the graph.
     """
     try:
         self.edges[edge] = head_id, tail_id, data = self.hidden_edges[edge]
         self.nodes[tail_id][0].append(edge)
         self.nodes[head_id][1].append(edge)
         del self.hidden_edges[edge]
     except KeyError:
         raise GraphError('Invalid edge %s' % edge)
Пример #7
0
 def restore_node(self, node):
     """
     Restores a previously hidden node back into the graph and restores
     all of its incoming and outgoing edges.
     """
     try:
         self.nodes[node], all_edges = self.hidden_nodes[node]
         for edge in all_edges:
             self.restore_edge(edge)
         del self.hidden_nodes[node]
     except KeyError:
         raise GraphError('Invalid node %s' % node)
Пример #8
0
 def hide_edge(self, edge):
     """
     Hides an edge from the graph. The edge may be unhidden at some later
     time.
     """
     try:
         head_id, tail_id, edge_data = self.hidden_edges[edge] = self.edges[edge]
         self.nodes[tail_id][0].remove(edge)
         self.nodes[head_id][1].remove(edge)
         del self.edges[edge]
     except KeyError:
         raise GraphError('Invalid edge %s' % edge)
Пример #9
0
 def hide_node(self, node):
     """
     Hides a node from the graph.  The incoming and outgoing edges of the
     node will also be hidden.  The node may be unhidden at some later time.
     """
     try:
         all_edges = self.all_edges(node)
         self.hidden_nodes[node] = (self.nodes[node], all_edges)
         for edge in all_edges:
             self.hide_edge(edge)
         del self.nodes[node]
     except KeyError:
         raise GraphError('Invalid node %s' % node)
Пример #10
0
def dijkstra(graph, start, end=None):
    """
    Dijkstra's algorithm for shortest paths

    `David Eppstein, UC Irvine, 4 April 2002
        <http://www.ics.uci.edu/~eppstein/161/python/>`_

    `Python Cookbook Recipe
        <http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/119466>`_

    Find shortest paths from the  start node to all nodes nearer than or
    equal to the end node.

    Dijkstra's algorithm is only guaranteed to work correctly when all edge
    lengths are positive.  This code does not verify this property for all
    edges (only the edges examined until the end vertex is reached), but will
    correctly compute shortest paths even for some graphs with negative edges,
    and will raise an exception if it discovers that a negative edge has
    caused it to make a mistake.

    Adapted to altgraph by Istvan Albert, Pennsylvania State University -
    June, 9 2004
    """
    D = {}  # dictionary of final distances
    P = {}  # dictionary of predecessors
    Q = _priorityDictionary()  # estimated distances of non-final vertices
    Q[start] = 0

    for v in Q:
        D[v] = Q[v]
        if v == end:
            break

        for w in graph.out_nbrs(v):
            edge_id = graph.edge_by_node(v, w)
            vwLength = D[v] + graph.edge_data(edge_id)
            if w in D:
                if vwLength < D[w]:
                    raise GraphError(
                        "Dijkstra: found better path to already-final vertex")
            elif w not in Q or vwLength < Q[w]:
                Q[w] = vwLength
                P[w] = v

    return (D, P)
Пример #11
0
    def __init__(self, edges=None):
        """
        Initialization
        """

        self.next_edge = 0
        self.nodes, self.edges = {}, {}
        self.hidden_edges, self.hidden_nodes = {}, {}

        if edges is not None:
            for item in edges:
                if len(item) == 2:
                    head, tail = item
                    self.add_edge(head, tail)
                elif len(item) == 3:
                    head, tail, data = item
                    self.add_edge(head, tail, data)
                else:
                    raise GraphError("Cannot create edge from %s" % (item, ))
Пример #12
0
def generate_random_graph(node_num,
                          edge_num,
                          self_loops=False,
                          multi_edges=False):
    '''
    Generates and returns a :py:class:`~altgraph.Graph.Graph` instance with *node_num* nodes
    randomly connected by *edge_num* edges.
    '''
    g = Graph.Graph()

    if not multi_edges:
        if self_loops:
            max_edges = node_num * node_num
        else:
            max_edges = node_num * (node_num - 1)

        if edge_num > max_edges:
            raise GraphError(
                "inconsistent arguments to 'generate_random_graph'")

    nodes = range(node_num)

    for node in nodes:
        g.add_node(node)

    while 1:
        head = random.choice(nodes)
        tail = random.choice(nodes)

        # loop defense
        if head == tail and not self_loops:
            continue

        # multiple edge defense
        if g.edge_by_node(head, tail) is not None and not multi_edges:
            continue

        # add the edge
        g.add_edge(head, tail)
        if g.number_of_edges() >= edge_num:
            break

    return g
Пример #13
0
    def iterdot(self):
        # write graph title
        if self.type == 'digraph':
            yield 'digraph %s {\n' % (self.name, )
        elif self.type == 'graph':
            yield 'graph %s {\n' % (self.name, )

        else:
            raise GraphError("unsupported graphtype %s" % (self.type, ))

        # write overall graph attributes
        for attr_name, attr_value in self.attr.iteritems():
            yield '%s="%s";' % (attr_name, attr_value)
        yield '\n'

        # some reusable patterns
        cpatt = '%s="%s",'  # to separate attributes
        epatt = '];\n'  # to end attributes

        # write node attributes
        for node_name, node_attr in self.nodes.iteritems():
            yield '\t"%s" [' % (node_name, )
            for attr_name, attr_value in node_attr.iteritems():
                yield cpatt % (attr_name, attr_value)
            yield epatt

        # write edge attributes
        for head in self.edges:
            for tail in self.edges[head]:
                if self.type == 'digraph':
                    yield '\t"%s" -> "%s" [' % (head, tail)
                else:
                    yield '\t"%s" -- "%s" [' % (head, tail)
                for attr_name, attr_value in self.edges[head][tail].iteritems(
                ):
                    yield cpatt % (attr_name, attr_value)
                yield epatt

        # finish file
        yield '}\n'
Пример #14
0
    def __init__(self, edges=None):
        """
        Initialization
        """

        self.next_edge = 0
        self.nodes, self.edges = {}, {}
        self.hidden_edges, self.hidden_nodes = {}, {}

        try:
            # instantiate graph from iterable data
            if edges:
                cols = len(edges[0])
                if cols == 2:
                    for head, tail in edges:
                        self.add_edge(head, tail)
                elif cols == 3:
                    for head, tail, data in edges:
                        self.add_edge(head, tail, data)
        except Exception, exc:
            raise GraphError('%s -> Cannot create graph from edges=%s' %
                             (exc, edges))
Пример #15
0
    def dijkstra(self, graph, start, end=None, usedByYenKSP=False, car_speed=0, usedByScheduler=False):
        """
        Dijkstra's algorithm for shortest paths

        `David Eppstein, UC Irvine, 4 April 2002
            <http://www.ics.uci.edu/~eppstein/161/python/>`_

        `Python Cookbook Recipe
            <http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/119466>`_

        Find shortest paths from the  start node to all nodes nearer than or
        equal to the end node.

        Dijkstra's algorithm is only guaranteed to work correctly when all edge
        lengths are positive.  This code does not verify this property for all
        edges (only the edges examined until the end vertex is reached), but will
        correctly compute shortest paths even for some graphs with negative edges,
        and will raise an exception if it discovers that a negative edge has
        caused it to make a mistake.

        Adapted to altgraph by Istvan Albert, Pennsylvania State University -
        June, 9 2004
        """
        D = {}    # dictionary of final distances
        P = {}    # dictionary of predecessors
        Q = self._priorityDictionary()    # estimated distances of non-final vertices
        Q[start] = 0

        for v in Q:
            D[v] = Q[v]
            if v == end:
                break

            # graph.out_nbrs(v): Return a list of all nodes connected by outgoing edges.
            for w in graph.out_nbrs(v):
                edge_id = graph.edge_by_node(v, w)
                # edge_weight = road_length/speed_limit/channel_number
                # max_speed = min(car_speed, graph.edge_data(edge_id)[2])
                # vwLength = D[v] + graph.edge_data(edge_id)[1] / max_speed / graph.edge_data(edge_id)[3]
                # vwLength = D[v] + graph.edge_data(edge_id)[1] / graph.edge_data(edge_id)[2] / graph.edge_data(edge_id)[3]
                vwLength = D[v] + graph.edge_data(edge_id)[1] / graph.edge_data(edge_id)[3]
                # vwLength = D[v] + graph.edge_data(edge_id)
                if usedByScheduler:
                    (id, length, speed, channel, num) = graph.edge_data(edge_id)
                    vwLength = D[v] + (num + length) / channel
                # vwLength = D[v] + graph.edge_data(edge_id)
                if w in D:
                    if vwLength < D[w]:
                        raise GraphError(
                            "Dijkstra: found better path to already-final vertex")
                elif w not in Q or vwLength < Q[w]:
                    Q[w] = vwLength
                    P[w] = v


        if usedByYenKSP:
            if end:
                if end not in graph.forw_bfs(start):  # can not reach end_node from start_node
                    return {'cost': D[start],
                            'path': []}
                return {'cost': D[end],
                        'path': self.path(P, start, end)}
            else:
                return (D, P)
        else:
            return (D, P)