Ticket #14589: trac_14589.patch

File trac_14589.patch, 15.0 KB (added by ncohen, 8 years ago)
  • doc/en/reference/graphs/index.rst

    # HG changeset patch
    # User Nathann Cohen <nathann.cohen@gmail.com>
    # Date 1368613532 -7200
    #      Wed May 15 12:25:32 2013 +0200
    # Node ID 88fdb1f3fbcd8a3587f912dd4bf97a3f7f58751a
    # Parent  0eee5ed9955fd55b5fb02b524b1c9a59067234eb
    binary matrices, dense graphs, and faster is_strongly_regular
    
    diff --git a/doc/en/reference/graphs/index.rst b/doc/en/reference/graphs/index.rst
    a b  
    3838   sage/graphs/base/sparse_graph
    3939   sage/graphs/base/dense_graph
    4040   sage/graphs/base/static_sparse_graph
     41   sage/graphs/base/static_dense_graph
    4142   sage/graphs/base/graph_backends
    4243
    4344Hypergraphs
  • module_list.py

    diff --git a/module_list.py b/module_list.py
    a b  
    383383    Extension('sage.graphs.base.static_sparse_graph',
    384384              sources = ['sage/graphs/base/static_sparse_graph.pyx']),
    385385
     386    Extension('sage.graphs.base.static_dense_graph',
     387              sources = ['sage/graphs/base/static_dense_graph.pyx']),
     388
    386389    Extension('sage.graphs.modular_decomposition.modular_decomposition',
    387390              sources = ['sage/graphs/modular_decomposition/modular_decomposition.pyx',
    388391                         'sage/graphs/modular_decomposition/src/dm.c'],
  • sage/graphs/base/all.py

    diff --git a/sage/graphs/base/all.py b/sage/graphs/base/all.py
    a b  
    11from sparse_graph import SparseGraph
    22from dense_graph import DenseGraph
    33import sage.graphs.base.static_sparse_graph
     4import sage.graphs.base.static_dense_graph
  • new file sage/graphs/base/static_dense_graph.pyx

    diff --git a/sage/graphs/base/static_dense_graph.pyx b/sage/graphs/base/static_dense_graph.pyx
    new file mode 100644
    - +  
     1r"""
     2Static dense graphs
     3
     4This module gathers everything which is related to static dense graphs, i.e. :
     5
     6- The vertices are integer from `0` to `n-1`
     7- No labels on vertices/edges
     8- No multiple edges
     9- No addition/removal of vertices
     10
     11This being said, it is technically possible to add/remove edges. The data
     12structure does not mind at all.
     13
     14It is all based on the binary matrix data structure described in
     15``misc/binary_matrix.pxi``, which is almost a copy of the bitset data
     16structure. The only difference is that it differentiates the rows (the vertices)
     17instead of storing the whole data in a long bitset, and we can use that.
     18
     19Index
     20-----
     21
     22**Cython functions**
     23
     24.. csv-table::
     25    :class: contentstable
     26    :widths: 30, 70
     27    :delim: |
     28
     29    ``dense_graph_init`` | Fills a binary matrix with the information of a (di)graph.
     30
     31**Python functions**
     32
     33.. csv-table::
     34    :class: contentstable
     35    :widths: 30, 70
     36    :delim: |
     37
     38    :meth:`is_strongly_regular` | Tests if a graph is strongly regular
     39
     40Functions
     41---------
     42"""
     43include "sage/misc/binary_matrix.pxi"
     44
     45cdef dict dense_graph_init(binary_matrix_t m, g, translation = False):
     46    r"""
     47    Initializes the binary matrix from a Sage (di)graph.
     48
     49    INPUT:
     50
     51    - ``binary_matrix_t m`` -- the binary matrix to be filled
     52
     53    - ``g`` -- a graph or digraph
     54
     55    - ``translation`` (boolean) -- whether to return a dictionary associating to
     56      each vertex its corresponding integer in the binary matrix.
     57    """
     58    cdef dict d_translation
     59    from sage.graphs.graph import Graph
     60    cdef int is_undirected = isinstance(g, Graph)
     61    cdef int n = g.order()
     62
     63    binary_matrix_init(m,n,n)
     64    binary_matrix_fill(m,0)
     65
     66    # If the vertices are 0...n-1, let's avoid an unnecessary dictionary
     67    if g.vertices() == range(n):
     68        if translation:
     69            d_translation = {i:i for i in range(n)}
     70
     71        for i,j in g.edge_iterator(labels = False):
     72            binary_matrix_set1(m,i,j)
     73            if is_undirected:
     74                binary_matrix_set1(m,j,i)
     75    else:
     76        d_translation = {v:i for i,v in enumerate(g.vertices())}
     77
     78        for u,v in g.edge_iterator(labels = False):
     79            binary_matrix_set1(m,d_translation[u],d_translation[v])
     80            if is_undirected:
     81                binary_matrix_set1(m,d_translation[v],d_translation[u])
     82
     83    if translation:
     84        return d_translation
     85
     86def is_strongly_regular(g, parameters = False):
     87    r"""
     88    Tests whether ``self`` is strongly regular.
     89
     90    A graph `G` is said to be strongly regular with parameters `(n, k, \lambda,
     91    \mu)` if and only if:
     92
     93        * `G` has `n` vertices.
     94
     95        * `G` is `k`-regular.
     96
     97        * Any two adjacent vertices of `G` have `\lambda` common neighbors.
     98
     99        * Any two non-adjacent vertices of `G` have `\mu` common neighbors.
     100
     101    By convention, the complete graphs, the graphs with no edges
     102    and the empty graph are not strongly regular.
     103
     104    See :wikipedia:`Strongly regular graph`
     105
     106    INPUT:
     107
     108    - ``parameters`` (boolean) -- whether to return the quadruple `(n,
     109      k,\lambda,\mu)`. If ``parameters = False`` (default), this method only
     110      returns ``True`` and ``False`` answers. If ``parameters=True``, the
     111      ``True`` answers are replaced by quadruples `(n, k,\lambda,\mu)`. See
     112      definition above.
     113
     114    EXAMPLES:
     115
     116    Petersen's graph is strongly regular::
     117
     118        sage: g = graphs.PetersenGraph()
     119        sage: g.is_strongly_regular()
     120        True
     121        sage: g.is_strongly_regular(parameters = True)
     122        (10, 3, 0, 1)
     123
     124    And Clebsch's graph is too::
     125
     126        sage: g = graphs.ClebschGraph()
     127        sage: g.is_strongly_regular()
     128        True
     129        sage: g.is_strongly_regular(parameters = True)
     130        (16, 5, 0, 2)
     131
     132    But Chvatal's graph is not::
     133
     134        sage: g = graphs.ChvatalGraph()
     135        sage: g.is_strongly_regular()
     136        False
     137
     138    Complete graphs are not strongly regular. (:trac:`14297`) ::
     139
     140        sage: g = graphs.CompleteGraph(5)
     141        sage: g.is_strongly_regular()
     142        False
     143
     144    Completements of complete graphs are not strongly regular::
     145
     146        sage: g = graphs.CompleteGraph(5).complement()
     147        sage: g.is_strongly_regular()
     148        False
     149
     150    The empty graph is not strongly regular::
     151
     152        sage: g = graphs.EmptyGraph()
     153        sage: g.is_strongly_regular()
     154        False
     155    """
     156    cdef binary_matrix_t m
     157    cdef int n = g.order()
     158    cdef int inter
     159    cdef int i,j,l, k
     160
     161    if g.size() == 0: # no vertices or no edges
     162        return False
     163
     164    if g.is_clique():
     165        return False
     166
     167    cdef list degree = g.degree()
     168    k = degree[0]
     169    if not all(d == k for d in degree):
     170        return False
     171
     172    # m i now our copy of the graph
     173    dense_graph_init(m, g)
     174
     175    cdef int llambda = -1
     176    cdef int mu = -1
     177
     178    for i in range(n):
     179        for j in range(i+1,n):
     180
     181            # The intersection of the common neighbors of i and j is a AND of
     182            # their respective rows. A popcount then returns its cardinality.
     183            inter = 0
     184            for l in range(m.width):
     185                inter += __builtin_popcountl(m.rows[i][l] & m.rows[j][l])
     186
     187            # Check that this cardinality is correct according to the values of lambda and mu
     188            if binary_matrix_get(m,i,j):
     189                if llambda == -1:
     190                    llambda = inter
     191                elif llambda != inter:
     192                    binary_matrix_free(m)
     193                    return False
     194            else:
     195                if mu == -1:
     196                    mu = inter
     197                elif mu != inter:
     198                    binary_matrix_free(m)
     199                    return False
     200
     201    binary_matrix_free(m)
     202
     203    if parameters:
     204        return (n,k,llambda,mu)
     205    else:
     206        return True
  • sage/graphs/graph.py

    diff --git a/sage/graphs/graph.py b/sage/graphs/graph.py
    a b  
    24522452
    24532453        return self_complement.is_odd_hole_free(certificate = certificate)
    24542454
    2455     def is_strongly_regular(self, parameters=False):
    2456         r"""
    2457         Tests whether ``self`` is strongly regular.
    2458 
    2459         A graph `G` is said to be strongly regular with parameters (n, k,
    2460         \lambda, \mu)` if and only if:
    2461 
    2462             * `G` has `n` vertices.
    2463 
    2464             * `G` is `k`-regular.
    2465 
    2466             * Any two adjacent vertices of `G` have `\lambda` common neighbors.
    2467 
    2468             * Any two non-adjacent vertices of `G` have `\mu` common neighbors.
    2469 
    2470         By convention, the complete graphs, the graphs with no edges
    2471         and the empty graph are not strongly regular.
    2472 
    2473         See :wikipedia:`Strongly regular graph`
    2474 
    2475         INPUT:
    2476 
    2477         - ``parameters`` (boolean) -- whether to return the quadruple `(n,
    2478           k,\lambda,\mu)`. If ``parameters = False`` (default), this method only
    2479           returns ``True`` and ``False`` answers. If ``parameters=True``, the
    2480           ``True`` answers are replaced by quadruples `(n, k,\lambda,\mu)`. See
    2481           definition above.
    2482 
    2483         EXAMPLES:
    2484 
    2485         Petersen's graph is strongly regular::
    2486 
    2487             sage: g = graphs.PetersenGraph()
    2488             sage: g.is_strongly_regular()
    2489             True
    2490             sage: g.is_strongly_regular(parameters = True)
    2491             (10, 3, 0, 1)
    2492 
    2493         And Clebsch's graph is too::
    2494 
    2495             sage: g = graphs.ClebschGraph()
    2496             sage: g.is_strongly_regular()
    2497             True
    2498             sage: g.is_strongly_regular(parameters = True)
    2499             (16, 5, 0, 2)
    2500 
    2501         But Chvatal's graph is not::
    2502 
    2503             sage: g = graphs.ChvatalGraph()
    2504             sage: g.is_strongly_regular()
    2505             False
    2506 
    2507         Complete graphs are not strongly regular. (:trac:`14297`) ::
    2508 
    2509             sage: g = graphs.CompleteGraph(5)
    2510             sage: g.is_strongly_regular()
    2511             False
    2512 
    2513         Completements of graphs are not strongly regular::
    2514 
    2515             sage: g = graphs.CompleteGraph(5).complement()
    2516             sage: g.is_strongly_regular()
    2517             False
    2518 
    2519         The empty graph is not strongly regular::
    2520 
    2521             sage: g = graphs.EmptyGraph()
    2522             sage: g.is_strongly_regular()
    2523             False
    2524         """
    2525 
    2526         if self.size() == 0: # no vertices or no edges
    2527             return False
    2528 
    2529         degree = self.degree()
    2530         k = degree[0]
    2531         if not all(d == k for d in degree):
    2532             return False
    2533 
    2534         if self.is_clique():
    2535             return False
    2536         else:
    2537             l = m = None
    2538             for u in self:
    2539                 nu = set(self.neighbors(u))
    2540                 for v in self:
    2541                     if u == v:
    2542                         continue
    2543                     nv = set(self.neighbors(v))
    2544                     inter = len(nu&nv)
    2545 
    2546                     if v in nu:
    2547                         if l is None:
    2548                             l = inter
    2549                         else:
    2550                             if l != inter:
    2551                                 return False
    2552                     else:
    2553                         if m is None:
    2554                             m = inter
    2555                         else:
    2556                             if m != inter:
    2557                                 return False
    2558 
    2559         if parameters:
    2560             return (self.order(),k,l,m)
    2561         else:
    2562             return True
    2563 
    25642455    def odd_girth(self):
    25652456        r"""
    25662457        Returns the odd girth of self.
     
    61146005import sage.graphs.graph_decompositions.graph_products
    61156006Graph.is_cartesian_product = types.MethodType(sage.graphs.graph_decompositions.graph_products.is_cartesian_product, None, Graph)
    61166007
     6008import sage.graphs.base.static_dense_graph
     6009Graph.is_strongly_regular = types.MethodType(sage.graphs.base.static_dense_graph.is_strongly_regular, None, Graph)
     6010
    61176011# From Python modules
    61186012import sage.graphs.line_graph
    61196013Graph.is_line_graph = sage.graphs.line_graph.is_line_graph
  • new file sage/misc/binary_matrix.pxi

    diff --git a/sage/misc/binary_matrix.pxi b/sage/misc/binary_matrix.pxi
    new file mode 100644
    - +  
     1r"""
     2A binary matrix datatype in Cython
     3
     4It's almost a copy of the bitset datatype, but allows a differentiation of the
     5rows of the matrix. That's the only advantage compared to storing all the rows
     6of a matrix in a loooooonng bitset.
     7
     8a ``binary_matrix_t`` structure contains :
     9
     10- ``long n_cols`` -- number of columns
     11
     12- ``long n_rows`` -- number of rows
     13
     14- ``long width`` -- number of ``unsigned long`` per row
     15
     16- ``unsigned long ** rows`` -- ``rows[i]`` points toward the ``width`` blocks of
     17  type ``unsigned long`` containing the bits of row `i`.
     18
     19.. NOTE::
     20
     21    The rows are stored contiguously in memory, i.e. ``row[i] = row[i-1] +
     22    width``.
     23"""
     24include "binary_matrix_pxd.pxi"
     25
     26cdef inline binary_matrix_init(binary_matrix_t m, long n_rows, long n_cols):
     27    r"""
     28    Allocates the binary matrix.
     29    """
     30    cdef int i
     31
     32    m.n_cols = n_cols
     33    m.n_rows = n_rows
     34    m.width = (n_cols - 1)/(8*sizeof(unsigned long)) + 1
     35    m.rows = <unsigned long**>sage_malloc(n_rows * sizeof(unsigned long *))
     36    if m.rows == NULL:
     37        raise MemoryError
     38
     39    m.rows[0] = <unsigned long*>sage_malloc(n_rows * m.width * sizeof(unsigned long))
     40    if m.rows[0] == NULL:
     41        sage_free(m.rows)
     42        raise MemoryError
     43
     44    for i in range(1,n_rows):
     45        m.rows[i] = m.rows[i-1] + m.width
     46        m.rows[i][m.width-1] = 0
     47
     48cdef inline binary_matrix_free(binary_matrix_t m):
     49    r"""
     50    Frees the memory allocated by the matrix
     51    """
     52    sage_free(m.rows[0])
     53    sage_free(m.rows)
     54
     55cdef inline binary_matrix_fill(binary_matrix_t m, bint bit):
     56    r"""
     57    Fill the whole matrix with a bit
     58    """
     59    memset(m.rows[0],-(<char> bit),m.width * m.n_rows * sizeof(unsigned long))
     60
     61cdef inline binary_matrix_set1(binary_matrix_t m, long row, long col):
     62    r"""
     63    Sets an entry to 1
     64    """
     65    m.rows[row][col >> index_shift] |= (<unsigned long>1) << (col & offset_mask)
     66
     67cdef inline binary_matrix_set0(binary_matrix_t m, long row, long col):
     68    r"""
     69    Sets an entry to 1
     70    """
     71    m.rows[row][col >> index_shift] &= ~((<unsigned long>1) << (col & offset_mask))
     72
     73cdef inline binary_matrix_set(binary_matrix_t m, long row, long col, bint value):
     74    r"""
     75    Sets an entry
     76    """
     77    binary_matrix_set0(m,row,col)
     78    m.rows[row][col >> index_shift] |= (<unsigned long>1) << (value & offset_mask)
     79
     80cdef inline bint binary_matrix_get(binary_matrix_t m, long row, long col):
     81    r"""
     82    Returns the value of a given entry
     83    """
     84    return (m.rows[row][col >> index_shift] >> (col & offset_mask)) & 1
     85
     86cdef inline binary_matrix_print(binary_matrix_t m):
     87    r"""
     88    Prints the binary matrix
     89    """
     90    cdef int i,j
     91    import sys
     92    for i in range(m.n_rows):
     93        for j in range(m.n_cols):
     94            sys.stdout.write("1" if binary_matrix_get(m, i, j) else ".",)
     95        print ""
  • new file sage/misc/binary_matrix_pxd.pxi

    diff --git a/sage/misc/binary_matrix_pxd.pxi b/sage/misc/binary_matrix_pxd.pxi
    new file mode 100644
    - +  
     1include "bitset_pxd.pxi"
     2include "bitset.pxi"
     3
     4cdef extern from *:
     5    int __builtin_popcountl(unsigned long)
     6
     7cdef struct binary_matrix_s:
     8    long n_cols
     9    long n_rows
     10
     11    # Number of "unsigned long" per row
     12    long width
     13
     14    unsigned long ** rows
     15
     16ctypedef binary_matrix_s[1] binary_matrix_t
     17