Ticket #12306: trac_12306.patch

File trac_12306.patch, 28.4 KB (added by ncohen, 9 years ago)
  • doc/en/reference/graphs.rst

    # HG changeset patch
    # User Nathann Cohen <nathann.cohen@gmail.com>
    # Date 1326474149 -3600
    # Node ID 4e16c6842694ad41bc2fbb34bbf1c8ab738c1d31
    # Parent  4ae344273876527a385aae7ad91c38aed0f33c0a
    Static sparse graphs for fast low-level computations
    
    diff -r 4ae344273876 -r 4e16c6842694 doc/en/reference/graphs.rst
    a b  
    3434   sage/graphs/base/c_graph
    3535   sage/graphs/base/sparse_graph
    3636   sage/graphs/base/dense_graph
     37   sage/graphs/base/static_sparse_graph
    3738
    3839
    3940Libraries of algorithms
  • module_list.py

    diff -r 4ae344273876 -r 4e16c6842694 module_list.py
    a b  
    332332    Extension('sage.graphs.distances_all_pairs',
    333333              sources = ['sage/graphs/distances_all_pairs.pyx']),
    334334
     335    Extension('sage.graphs.base.static_sparse_graph',
     336              sources = ['sage/graphs/base/static_sparse_graph.pyx']),
     337
    335338    Extension('sage.graphs.modular_decomposition.modular_decomposition',
    336339              sources = ['sage/graphs/modular_decomposition/modular_decomposition.pyx'],
    337340              depends = ['sage/graphs/modular_decomposition/src/dm.c',
  • sage/graphs/base/all.py

    diff -r 4ae344273876 -r 4e16c6842694 sage/graphs/base/all.py
    a b  
    11from sparse_graph import SparseGraph
    22from dense_graph import DenseGraph
     3import sage.graphs.base.static_sparse_graph
  • sage/graphs/base/c_graph.pyx

    diff -r 4ae344273876 -r 4e16c6842694 sage/graphs/base/c_graph.pyx
    a b  
    14081408                d += 1
    14091409        return self._cg._out_degree(v_int) + d
    14101410
     1411
     1412    def out_degree(self, v):
     1413        r"""
     1414        Returns the out-degree of v
     1415
     1416        INPUT:
     1417
     1418        - ``v`` -- a vertex of the graph.
     1419
     1420        - ``directed`` -- boolean; whether to take into account the
     1421          orientation of this graph in counting the degree of ``v``.
     1422
     1423
     1424        EXAMPLE::
     1425
     1426                                                                                                                                                                                                             
     1427            sage: D = DiGraph( { 0: [1,2,3], 1: [0,2], 2: [3], 3: [4], 4: [0,5], 5: [1] } )
     1428            sage: D.out_degree(1)
     1429            2
     1430        """
     1431        cdef v_int = get_vertex(v,
     1432                                self.vertex_ints,
     1433                                self.vertex_labels,
     1434                                self._cg)
     1435        if self._directed:
     1436            return self._cg._out_degree(v_int)
     1437        d = 0
     1438        if self._loops and self.has_edge(v, v, None):
     1439            if self._multiple_edges:
     1440                d += len(self.get_edge_label(v, v))
     1441            else:
     1442                d += 1
     1443
     1444        return self._cg._out_degree(v_int) + d
     1445
     1446
    14111447    def add_vertex(self, object name):
    14121448        """
    14131449        Add a vertex to ``self``.
  • sage/graphs/base/sparse_graph.pxd

    diff -r 4ae344273876 -r 4e16c6842694 sage/graphs/base/sparse_graph.pxd
    a b  
    3535    cpdef del_arc_label(self, int u, int v, int l)
    3636    cdef int has_arc_label_unsafe(self, int, int, int)
    3737    cpdef bint has_arc_label(self, int u, int v, int l)
     38    cpdef int out_degree(self, int u)
     39    cpdef int in_degree(self, int u)
    3840   
    3941cdef int new_edge_label(object l, dict edge_labels)
  • sage/graphs/base/sparse_graph.pyx

    diff -r 4ae344273876 -r 4e16c6842694 sage/graphs/base/sparse_graph.pyx
    a b  
    815815        sage_free(neighbors)
    816816        return output
    817817
     818    cpdef int out_degree(self, int u):
     819        """
     820        Returns the out-degree of ``v``
     821
     822        INPUT:
     823         - ``u`` - integer
     824       
     825        EXAMPLES::
     826
     827            sage: from sage.graphs.base.sparse_graph import SparseGraph
     828            sage: G = SparseGraph(5)
     829            sage: G.add_arc(0,1)
     830            sage: G.add_arc(1,2)
     831            sage: G.add_arc(1,3)
     832            sage: G.out_degree(0)
     833            1
     834            sage: G.out_degree(1)
     835            2
     836        """
     837        return self.out_degrees[u]
     838
     839
    818840    cdef int in_neighbors_unsafe(self, int v, int *neighbors, int size):
    819841        """
    820842        Gives all u such that (u, v) is an arc of the graph.
     
    880902        sage_free(neighbors)
    881903        return output
    882904
     905    cpdef int in_degree(self, int u):
     906        """
     907        Returns the in-degree of ``v``
     908
     909        INPUT:
     910         - ``u`` - integer
     911       
     912        EXAMPLES::
     913
     914            sage: from sage.graphs.base.sparse_graph import SparseGraph
     915            sage: G = SparseGraph(5)
     916            sage: G.add_arc(0,1)
     917            sage: G.add_arc(1,2)
     918            sage: G.add_arc(1,3)
     919            sage: G.in_degree(0)
     920            0
     921            sage: G.in_degree(1)
     922            1
     923        """
     924        return self.in_degrees[u]
     925
     926
    883927    ###################################
    884928    # Labeled arc functions
    885929    ###################################
  • new file sage/graphs/base/static_sparse_graph.pxd

    diff -r 4ae344273876 -r 4e16c6842694 sage/graphs/base/static_sparse_graph.pxd
    - +  
     1ctypedef unsigned short ushort
     2
     3include "../../misc/bitset_pxd.pxi"
     4
     5ctypedef struct short_digraph_s:
     6   ushort n
     7   ushort * edges
     8   ushort ** neighbors
     9
     10ctypedef short_digraph_s short_digraph[1]
     11
     12cdef int init_short_digraph(short_digraph g, G) except -1
     13cdef void free_short_digraph(short_digraph g)
  • new file sage/graphs/base/static_sparse_graph.pyx

    diff -r 4ae344273876 -r 4e16c6842694 sage/graphs/base/static_sparse_graph.pyx
    - +  
     1r"""
     2Static Sparse Graphs
     3
     4What is the point ?
     5-------------------
     6
     7This class implements a Cython (di)graph structure made for efficiency. The
     8graphs are *static*, i.e. no add/remove vertex/edges methods are available, nor
     9can they easily or efficiently be implemented within this data structure.
     10
     11The data structure, however, is made to save the maximum amount of computations
     12for graph algorithms whose main operation is to *list the out-neighbours of a
     13vertex* (which is precisely what BFS, DFS, distance computations and the
     14flow-related stuff waste their life on).
     15
     16The code contained in this module is written C-style. While Sage needs a class
     17for static graphs (not available today, i.e. 2012-01-13) it is not what we try
     18to address here. The purpose is efficiency and simplicity.
     19
     20Author:
     21
     22- Nathann Cohen (2011)
     23
     24Data structure
     25--------------
     26
     27.. MATH::
     28
     29    \begin{picture}(600,400)(0,0)
     30    \multiput(0, 0)(15, 0){31}{\line(0, 1){15}}
     31    \multiput(0, 0)(0, 15){2}{\line(1, 0){450}}
     32    \put(-70,2){\makebox(0,0)[b]{edges}}
     33    \put(-20,-50){\makebox(0,0)[b]{neighbors[0]}}
     34    \put(100,-50){\makebox(0,0)[b]{neighbors[1]}}
     35    \put(250,-50){\makebox(0,0)[b]{neighbors[i]}}
     36    \put(400,-50){\makebox(0,0)[b]{neighbors[n-1]}}
     37    \put(500,-30){\makebox(0,0)[b]{neighbors[n]}}
     38    \multiput(450, 0)(15, 0){2}{\qbezier[8](0,0)(0,7.5)(0,15)}
     39    \multiput(450, 0)(0, 15){2}{\qbezier[8](0,0)(7.5,0)(15,0)}
     40    \put(0,0){\makebox(15,15){2}}
     41    \put(15,0){\makebox(15,15){3}}
     42    \put(30,0){\makebox(15,15){5}}
     43    \put(45,0){\makebox(15,15){7}}
     44    \put(60,0){\makebox(15,15){8}}
     45    \put(75,0){\makebox(15,15){9}}
     46    \put(90,0){\makebox(15,15){4}}
     47    \put(105,0){\makebox(15,15){8}}
     48    \multiput(120, 0)(15, 0){18}{\makebox(15,15){$\cdot$}}
     49    \put(390,0){\makebox(15,15){2}}
     50    \put(405,0){\makebox(15,15){5}}
     51    \put(420,0){\makebox(15,15){8}}
     52    \put(435,0){\makebox(15,15){9}}
     53    \thicklines
     54    \put(-50, 7.5){\vector(1, 0){40}}
     55    \put(-18, -28){\vector(2, 3){16}}
     56    \put(97, -25){\vector(0, 1){20}}
     57    \put(247, -25){\vector(0, 1){20}}
     58    \put(397, -25){\vector(0, 1){20}}
     59    \put(490, -5){\vector(-2, 1){20}}
     60    \end{picture}
     61
     62
     63The data structure is actually pretty simple and compact. ``short_digraph`` has
     64three fields
     65
     66    * ``n`` (``int``) -- the number of vertices in the graph.
     67
     68    * ``edges`` (``unsigned short *``) -- array whose length is the number of
     69      edges of the graph.
     70
     71    * ``neighbors`` (``unsigned short **``) -- this array has size `n+1`, and
     72      describes how the data of ``edges`` should be read : the neighbors of
     73      vertex `i` are the elements of ``edges`` addressed by
     74      ``neighbors[i]...neighbors[i+1]-1``. The element ``neighbors[n]``, which
     75      corresponds to no vertex (they are numbered from `0` to `n-1`) is present
     76      so that it remains easy to enumerate the neighbors of vertex `n-1` : the
     77      last of them is the element addressed by ``neighbors[n]-1``.
     78
     79
     80In the example given above, vertex 0 has 2,3,5,7,8 and 9 as out-neighbors, but
     81not 4, which is an out-neighbour of vertex 1. Vertex `n-1` has 2, 5, 8 and 9 as
     82out-neighbors. `\text{neighbors[n]}` points toward the cell immediately *after*
     83the end of `\text{edges}`, hence *outside of the allocated memory*. It is used
     84to indicate the end of the outneighbors of vertex `n-1`
     85
     86**Iterating over the edges**
     87
     88This is *the one thing* to have in mind when working with this data structure::
     89
     90    cdef list_edges(short_digraph g):
     91        cdef ushort * v
     92        cdef ushort * end
     93        cdef int i
     94
     95        for i in range(g.n):
     96            v = g.neighbors[i]
     97            end = g.neighbors[i+1]
     98
     99            while v < end:
     100                print "There is an edge from "+str(i)+" to "+str(v[0])
     101                v += 1
     102
     103**Advantages**
     104
     105Three great points :
     106
     107    * The neighbors of a vertex are contiguous in memory.
     108    * Going from one to the other amounts to increasing a pointer.
     109    * Storing such graphs is incredibly cheaper than storing Python structures.
     110
     111Well, I think it would be hard to have anything more efficient than that to
     112enumerate out-neighbors in sparse graphs ! :-)
     113
     114Technical details
     115-----------------
     116
     117    * When creating a ``fast_digraph`` from a ``Graph`` or ``DiGraph`` named
     118      ``G``, the `i^{\text{th}}` vertex corresponds to ``G.vertices()[i]``
     119
     120    * The data structure does not support edge labels
     121
     122    * In its current implementation (with ``unsigned short`` variables), the
     123      data structure can handle graphs with at most 65535 vertices. If
     124      necessary, changing it to ``int`` is totally straightforward.
     125
     126    * Some methods return ``bitset_t`` objets when lists could be
     127      expected. There is a very useful ``bitset_list`` function for this kind of
     128      problems :-)
     129
     130    * The codes of this module are well documented, and many answers can be
     131      found directly in the code.
     132
     133Todo list
     134
     135    * Adjacency test. The data structure can support it efficiently through
     136      dichotomy. It would require to sort the list of edges as it is not done at
     137      the moment. Some calls to the C function ``qsort`` would be sufficient.
     138
     139Cython functions
     140----------------
     141
     142``init_short_digraph(short_digraph g, G)``
     143
     144    This method initializes ``short_digraph g`` so that it represents ``G``. If
     145    ``G`` is a ``Graph`` objet (and not a ``DiGraph``), an edge between two
     146    vertices `u` and `v` is replaced by two arcs in both directions.
     147
     148``int n_edges(short_digraph g)``
     149
     150    Returns the number of edges in ``g``
     151
     152``int out_degree(short_digraph g, int i)``
     153
     154    Returns the out-degree of vertex `i` in ``g``
     155
     156``init_empty_copy(short_digraph dst, short_digraph src)``
     157
     158    Allocates memory for ``dst`` so that it can contain as many vertices and
     159    edges as ``src``. Its content is purely random, though.
     160
     161``init_reverse(short_digraph dst, short_digraph src)``
     162
     163    Initializes ``dst`` so that it represents a copy of ``src`` in which all
     164    edges go in the opposite direction.
     165
     166``can_be_reached_from(short_digraph g, int src, bitset_t reached)``
     167
     168    Assuming ``bitset_t reached`` has size at least ``g.n``, this method updates
     169    ``reached`` so that it represents the set of vertices that can be reached
     170    from ``src`` in ``g``.
     171
     172``strongly_connected_component_containing_vertex(short_digraph g, short_digraph g_reversed, int v, bitset_t scc)``
     173
     174    Assuming ``bitset_t reached`` has size at least ``g.n``, this method updates
     175    ``scc`` so that it represents the vertices of the strongly connected
     176    component containing ``v`` in ``g``. The variable ``g_reversed`` is assumed
     177    to represent the reverse of ``g``.
     178
     179``free_short_digraph(short_digraph g)``
     180
     181    Free the ressources used by ``g``
     182
     183What is this module used for ?
     184------------------------------
     185
     186At the moment, it is only used in the :mod:`sage.graphs.distances_all_pairs` module.
     187
     188Python functions
     189----------------
     190
     191These functions are available so that Python modules from Sage can call the
     192Cython routines this module implements (as they can not directly call methods
     193with C arguments).
     194"""
     195
     196include "../../misc/bitset.pxi"
     197
     198##############################################################################
     199#       Copyright (C) 2010 Nathann Cohen <nathann.cohen@gmail.com>
     200#  Distributed under the terms of the GNU General Public License (GPL)
     201#  The full text of the GPL is available at:
     202#                  http://www.gnu.org/licenses/
     203##############################################################################
     204
     205from sage.graphs.base.c_graph cimport CGraph
     206
     207cdef int init_short_digraph(short_digraph g, G) except -1:
     208
     209    # g.n is unsigned short, so -1 is actually the maximum value possible.
     210    g.n = -1
     211
     212    if G.order() > g.n:
     213        raise ValueError("This structure can handle at most "+str(<int> g.n)+" vertices !")
     214    else:
     215        g.n = G.order()
     216
     217    cdef int isdigraph
     218   
     219    from sage.graphs.all import Graph, DiGraph
     220
     221    if isinstance(G, DiGraph):
     222        isdigraph = 1
     223    elif isinstance(G, Graph):
     224         isdigraph = 0
     225    else:
     226        raise ValueError("The source graph must be either a DiGraph or a Graph object !")
     227
     228    cdef list vertices = G.vertices()
     229    cdef dict v_to_id = {}
     230    cdef ushort i,j
     231
     232    cdef int n_edges = G.size() if isdigraph else 2*G.size()
     233
     234    for i, v in enumerate(vertices):
     235        v_to_id[v] = i
     236
     237    g.edges = <ushort *> sage_malloc(n_edges*sizeof(ushort))
     238    if g.edges == NULL:
     239        raise ValueError("Problem while allocating memory (edges)")
     240
     241    g.neighbors = <ushort **> sage_malloc((g.n+1)*sizeof(ushort *))
     242    if g.neighbors == NULL:
     243        raise ValueError("Problem while allocating memory (neighbors)")
     244
     245
     246    # Initializing the value of neighbors
     247    g.neighbors[0] = g.edges
     248
     249    cdef CGraph cg = <CGraph> G._backend
     250    for i in range(1,g.n+1):
     251        g.neighbors[i] = g.neighbors[i-1] + <int> (cg.out_degree(vertices[i-1]) if isdigraph else G.degree(vertices[i-1]))
     252
     253    for u,v in G.edge_iterator(labels = False):
     254        i = v_to_id[u]
     255        j = v_to_id[v]
     256
     257        g.neighbors[i][0] = j
     258        g.neighbors[i] += 1
     259
     260        if not isdigraph:
     261            g.neighbors[j][0] = i
     262            g.neighbors[j] += 1
     263
     264    # Reinitializing the value of neighbors
     265    for g.n> i >0:
     266        g.neighbors[i] = g.neighbors[i-1]
     267
     268    g.neighbors[0] = g.edges
     269
     270cdef inline int n_edges(short_digraph g):
     271    # The number of edges is nothing but a difference of pointers
     272    return <int> (g.neighbors[g.n]-g.edges)
     273
     274cdef inline int out_degree(short_digraph g, int i):
     275    # The out-degree is nothing but a difference of pointers
     276    return <int> (g.neighbors[i+1]-g.neighbors[i])
     277
     278cdef int init_empty_copy(short_digraph dst, short_digraph src) except -1:
     279    dst.n = src.n
     280
     281    dst.edges = <ushort *> sage_malloc(n_edges(src)*sizeof(ushort))
     282    if dst.edges == NULL:
     283        raise ValueError("Problem while allocating memory (edges)")
     284
     285    dst.neighbors = <ushort **> sage_malloc((src.n+1)*sizeof(ushort *))
     286    if dst.neighbors == NULL:
     287        raise ValueError("Problem while allocating memory (neighbors)")
     288
     289cdef int init_reverse(short_digraph dst, short_digraph src) except -1:
     290    # Allocates memory for dst
     291    init_empty_copy(dst, src)
     292
     293    # Avoiding a later segfault
     294    if dst.n == 0:
     295        return 0
     296   
     297    #### 1/3
     298    #
     299    # In a first pass, we count the in-degrees of each vertex and store it in a
     300    # vector. With this information, we can initialize dst.neighbors to its
     301    # correct value. The content of dst.edges is not touched at this level.
     302
     303    cdef int * in_degree = <int *> sage_malloc(src.n*sizeof(int))
     304    if in_degree == NULL:
     305        raise ValueError("Problem while allocating memory (in_degree)")
     306
     307    # Counting the degrees
     308    memset(in_degree, 0, src.n*sizeof(int))
     309
     310    cdef ushort * v = src.edges
     311    cdef ushort * end = src.neighbors[src.n]
     312    while v < end:
     313        in_degree[v[0]] += 1
     314        v += 1
     315
     316    # Updating dst.neighbors
     317    cdef int i
     318    dst.neighbors[0] = dst.edges
     319    for i in range(1, src.n+1):
     320        dst.neighbors[i] = dst.neighbors[i-1] + in_degree[i-1]
     321    sage_free(in_degree)
     322
     323    #### 2/3
     324    #
     325    # Second pass : we list the edges again, and add them in dst.edges. Doing
     326    # so, we will change the value of dst.neighbors, but that is not so bad as
     327    # we can fix it afterwards.
     328    for i in range(0, src.n):
     329        v = src.neighbors[i]
     330        end = src.neighbors[i+1]
     331
     332        while v < end:
     333            dst.neighbors[v[0]][0] = i
     334            dst.neighbors[v[0]] += 1
     335            v += 1
     336
     337    #### 3/3
     338    #
     339    # Final step : set the correct values of dst.neighbors again. It is easy, as
     340    # the correct value of dst.neighbors[i] is actually dst.neighbors[i-1]
     341    for src.n> i >0:
     342        dst.neighbors[i] = dst.neighbors[i-1]
     343    dst.neighbors[0] = dst.edges
     344
     345cdef int can_be_reached_from(short_digraph g, int src, bitset_t reached) except -1:
     346    if g.n == 0:
     347        return 0
     348
     349    # Initializing the set of vertices reached by setting only bit src
     350    bitset_set_first_n(reached, 0)
     351    bitset_add(reached, src)
     352
     353    # We will be doing a Depth-First Search. We allocate the stack we need for
     354    # that, and put "src" on top of it.
     355    cdef ushort * stack = <ushort *> sage_malloc(g.n*sizeof(ushort))
     356    if stack == NULL:
     357        raise ValueError("Problem while allocating memory (stack)")
     358
     359    stack[0] = src
     360    cdef int stack_size = 1
     361
     362    # What we need to iterate over the edges
     363    cdef int i
     364    cdef ushort * v
     365    cdef ushort * end
     366
     367    # Plain old DFS ...
     368    #
     369    #If there is something left on the stack, we remove it consider each of its
     370    # neighbors. If we find any which has not been reached yet, we set its
     371    # corresponding bit in the reached bitset, and add it on top of the stack.
     372
     373    while stack_size:
     374        stack_size -= 1
     375        i = stack[stack_size]
     376
     377        v = g.neighbors[i]
     378        end = g.neighbors[i+1]
     379
     380        while v < end:
     381            if not bitset_in(reached, v[0]):
     382                bitset_add(reached, v[0])
     383                stack[stack_size] = v[0]
     384                stack_size += 1
     385
     386            v += 1
     387
     388    sage_free(stack)
     389
     390cdef strongly_connected_component_containing_vertex(short_digraph g, short_digraph g_reversed, int v, bitset_t scc):
     391
     392    # Computing the set of vertices that can be reached from v in g
     393    can_be_reached_from(g, v, scc)
     394
     395    # Computing the set of vertices that can be reached from v in g *reversed*
     396    cdef bitset_t scc_reversed
     397    bitset_init(scc_reversed, g.n)
     398    can_be_reached_from(g_reversed, v, scc_reversed)
     399
     400    # The scc containing v is the intersection of both sets
     401    bitset_intersection(scc, scc, scc_reversed)
     402
     403cdef void free_short_digraph(short_digraph g):
     404           
     405    if g.edges != NULL:
     406        sage_free(g.edges)
     407
     408    if g.neighbors != NULL:
     409        sage_free(g.neighbors)
     410
     411def strongly_connected_components(G):
     412    r"""
     413    Returns the strongly connected components of the given DiGraph.
     414
     415    INPUT:
     416
     417    - ``G`` -- a DiGraph.
     418
     419    .. NOTE::
     420
     421        This method has been written as an attempt to solve the slowness
     422        reported in #12235. It is not the one used by
     423        :meth:`sage.graphs.digraph.strongly_connected_components` as saving some
     424        time on the computation of the strongly connected components is not
     425        worth copying the whole graph, but it is a nice way to test this
     426        module's functions. It is also tested in the doctest or
     427        :meth:`sage.graphs.digraph.strongly_connected_components`.
     428
     429    EXAMPLE::
     430
     431        sage: from sage.graphs.base.static_sparse_graph import strongly_connected_components
     432        sage: g = digraphs.ButterflyGraph(2)
     433        sage: strongly_connected_components(g)
     434        [[('00', 0)], [('00', 1)], [('00', 2)], [('01', 0)], [('01', 1)], [('01', 2)],
     435        [('10', 0)], [('10', 1)], [('10', 2)], [('11', 0)], [('11', 1)], [('11', 2)]]
     436    """
     437
     438    if G.order() == 0:
     439        return [[]]
     440
     441    # To compute the connected component containing a given vertex v, we take
     442    # the intersection of the set of vertices that can be reached from v in G
     443    # and the set of vertices that can be reached from v in G reversed.
     444    #
     445    # That's all that happens here.
     446
     447    cdef list answer = []
     448    cdef list vertices = G.vertices()
     449    cdef short_digraph g, gr
     450
     451    init_short_digraph(g, G)
     452
     453    init_reverse(gr, g)
     454
     455    cdef bitset_t seen
     456    bitset_init(seen, g.n)
     457    bitset_set_first_n(seen, 0)
     458
     459
     460    cdef bitset_t scc
     461    bitset_init(scc, g.n)
     462    bitset_set_first_n(scc, 0)
     463
     464    cdef int v
     465    while bitset_len(seen) < g.n:
     466        v = bitset_first_in_complement(seen)
     467        strongly_connected_component_containing_vertex(g, gr, v, scc)
     468        answer.append([vertices[i] for i in bitset_list(scc)])
     469        bitset_union(seen, seen, scc)
     470       
     471    bitset_free(seen)
     472    bitset_free(scc)
     473    free_short_digraph(g)
     474    free_short_digraph(gr)
     475    return answer
     476
  • sage/graphs/digraph.py

    diff -r 4ae344273876 -r 4e16c6842694 sage/graphs/digraph.py
    a b  
    11651165            {0: 3, 1: 2, 2: 1}
    11661166            sage: D.out_degree()
    11671167            [3, 2, 1, 1, 2, 1]
     1168            sage: D.out_degree(2)
     1169            1
    11681170        """
    11691171        if vertices in self:
    1170             for d in self.out_degree_iterator(vertices):
    1171                 return d # (weird, but works: only happens once!)
     1172
     1173            try:
     1174                return self._backend.out_degree(vertices)
     1175
     1176            except AttributeError:
     1177                for d in self.out_degree_iterator(vertices):
     1178                    return d # (weird, but works: only happens once!)
     1179
    11721180        elif labels:
    11731181            di = {}
    11741182            for v, d in self.out_degree_iterator(vertices, labels=labels):
     
    25502558        """
    25512559        Returns a list of lists of vertices, each list representing a
    25522560        strongly connected component.
    2553        
     2561
     2562
    25542563        EXAMPLES::
    25552564
    25562565            sage: D = DiGraph( { 0 : [1, 3], 1 : [2], 2 : [3], 4 : [5, 6], 5 : [6] } )
     
    25652574
    25662575        TESTS:
    25672576
    2568         Checking against NetworkX::
    2569 
     2577        Checking against NetworkX, and another of Sage's implementations::
     2578
     2579            sage: from sage.graphs.base.static_sparse_graph import strongly_connected_components
    25702580            sage: import networkx
    25712581            sage: for i in range(100):                                     # long
    25722582            ...        g = digraphs.RandomDirectedGNP(100,.05)             # long
    25732583            ...        h = g.networkx_graph()                              # long
    25742584            ...        scc1 = g.strongly_connected_components()            # long
    25752585            ...        scc2 = networkx.strongly_connected_components(h)    # long
     2586            ...        scc3 = strongly_connected_components(g)             # long
    25762587            ...        s1 = Set(map(Set,scc1))                             # long
    25772588            ...        s2 = Set(map(Set,scc2))                             # long
     2589            ...        s3 = Set(map(Set,scc3))                             # long
    25782590            ...        if s1 != s2:                                        # long
    25792591            ...            print "Ooch !"                                  # long
     2592            ...        if s1 != s3:                                        # long
     2593            ...            print "Oooooch !"                               # long
     2594
    25802595        """
    25812596
    25822597        try:
     
    25882603                scc.append(tmp)
    25892604            return scc
    25902605
    2591         except ValueError:
     2606        except AttributeError:
    25922607            import networkx
    25932608            return networkx.strongly_connected_components(self.networkx_graph(copy=False))
    25942609
     
    26192634            return self._backend.strongly_connected_component_containing_vertex(v)
    26202635
    26212636        except AttributeError:
    2622             raise ValueError("This function is only defined for C graphs.")
     2637            raise AttributeError("This function is only defined for C graphs.")
    26232638
    26242639    def strongly_connected_components_subgraphs(self):
    26252640        r"""
  • sage/graphs/distances_all_pairs.pyx

    diff -r 4ae344273876 -r 4e16c6842694 sage/graphs/distances_all_pairs.pyx
    a b  
    114114from sage.graphs.base.c_graph cimport vertex_label
    115115from sage.graphs.base.c_graph cimport get_vertex
    116116
     117from sage.graphs.base.static_sparse_graph cimport short_digraph, init_short_digraph, free_short_digraph
     118
    117119
    118120cdef inline all_pairs_shortest_path_BFS(gg,
    119121                                        unsigned short * predecessors,
     
    127129    cdef CGraph cg = <CGraph> gg._backend._cg
    128130
    129131    cdef list int_to_vertex = gg.vertices()
    130     cdef dict vertex_to_int = {}
    131132    cdef int i
    132 
    133     for i, l in enumerate(int_to_vertex):
    134         int_to_vertex[i] = get_vertex(l, gg._backend.vertex_ints, gg._backend.vertex_labels, cg)
    135         vertex_to_int[int_to_vertex[i]] = i
    136        
    137133   
    138134    cdef int n = len(int_to_vertex)
    139135
     
    154150
    155151    cdef unsigned short source
    156152    cdef unsigned short v, u
     153    cdef unsigned short * p_tmp
     154    cdef unsigned short * end
    157155
    158156    cdef unsigned short * c_predecessors = predecessors
    159157    cdef unsigned short * c_eccentricity = eccentricity
     
    184182    #
    185183    # p_vertices[i] to p_vertices[i+1] - 1
    186184    # (if p_vertices[i] is equal to p_vertices[i+1], then i has no outneighbours)
     185    #
     186    # This data structure is well documented in the module
     187    # sage.graphs.base.static_sparse_graph
    187188
    188     cdef unsigned short ** p_vertices = <unsigned short **> sage_malloc(n*sizeof(short *))
    189     cdef unsigned short * p_edges = <unsigned short *> sage_malloc(cg.num_arcs*sizeof(short))
     189    cdef short_digraph sd
     190    init_short_digraph(sd, gg)
     191    cdef unsigned short ** p_vertices = sd.neighbors
     192    cdef unsigned short * p_edges = sd.edges
    190193    cdef unsigned short * p_next = p_edges
    191194
    192     for v,i in enumerate(int_to_vertex):
    193         outneighbors = <int *>sage_malloc(cg.out_degrees[i] * sizeof(int))
    194         cg.out_neighbors_unsafe(i, outneighbors, cg.out_degrees[i])
    195         p_vertices[v] = p_next
    196        
    197         for 0<= j < cg.out_degrees[i]:
    198             p_next[0] = <unsigned short> vertex_to_int[outneighbors[j]]
    199             p_next = p_next + 1
    200 
    201         degree[v] = p_next - p_vertices[v]
    202 
    203         sage_free(outneighbors)
    204 
    205 
    206195    # We run n different BFS taking each vertex as a source
    207196    for source in range(n):
    208197
     
    227216            # We pick the first one
    228217            v = waiting_list[waiting_beginning]
    229218
     219            p_tmp = p_vertices[v]
     220            end = p_vertices[v+1]
     221
    230222            # Iterating over all the outneighbors u of v
    231             for 0 <= i < degree[v]:
    232                 u = p_vertices[v][i]
     223            while p_tmp < end:
     224                u = p_tmp[0]
    233225
    234226                # If we notice one of these neighbors is not seen yet, we set
    235227                # its parameters and add it to the queue to be explored later.
     
    241233                    waiting_end += 1
    242234                    waiting_list[waiting_end] = u
    243235
     236                p_tmp += 1
     237
    244238            waiting_beginning += 1
    245239
    246240        # If not all the vertices have been met
     
    265259
    266260    bitset_free(seen)
    267261    sage_free(waiting_list)
    268     sage_free(p_vertices)
    269     sage_free(p_edges)
    270262    sage_free(degree)
     263    free_short_digraph(sd)
    271264    if distances == NULL:
    272265        sage_free(c_distances)
    273266