Path: blob/master/sage/graphs/graph_decompositions/fast_digraph.pyx
4069 views
r"""1Compact structure for fast operations on less than 32 vertices23This module implements a digraph structure meant to be used in Cython in4**highly enumerative** algorithms. It can store graphs on less than5``sizeof(int)`` vertices and perform several basic operations **quickly**6(add/remove arcs, count the out-neighborhood of a set of vertices or return its7cardinality).89**Sets and integers :**1011In the following code, sets are represented as integers, where the ith bit is12set if element i belongs to the set.13"""1415include '../../ext/stdsage.pxi'16include '../../ext/cdefs.pxi'17include '../../ext/interrupt.pxi'1819from libc.stdint cimport uint8_t2021cdef class FastDigraph:22cdef uint8_t n23cdef int * graph2425def __cinit__(self, D):26r"""27Constructor for ``FastDigraph``.28"""29if D.order() > 8*sizeof(int):30raise Exception("Too many vertices. This structure can only encode digraphs on at most sizeof(int) vertices.")3132self.n = D.order()33self.graph = NULL3435self.graph = <int *> sage_malloc(self.n*sizeof(int))3637memset(self.graph, 0, self.n * sizeof(int))3839cdef int i, j40cdef int tmp4142# When the vertices are not consecutive integers43cdef dict vertices_to_int = {}44for i,v in enumerate(D.vertices()):45vertices_to_int[v] = i4647for u in D:48tmp = 049for v in D.neighbors_out(u):50tmp |= 1 << vertices_to_int[v]51self.graph[vertices_to_int[u]] = tmp5253def __dealloc__(self):54r"""55Destructor.56"""57if self.graph != NULL:58sage_free(self.graph)5960def print_adjacency_matrix(self):61r"""62Displays the adjacency matrix of ``self``.63"""64cdef int i,j65for 0<= i<self.n:66for 0<= j <self.n:67print ((self.graph[i]>>j)&1),68print ""6970cdef inline int compute_out_neighborhood_cardinality(FastDigraph g, int S):71r"""72Returns the cardinality of `N^+(S)\S`.7374INPUT:7576- ``g`` a FastDigraph77- S (integer) an integer describing the set78"""79cdef int i80cdef int tmp = 081for 0<= i<g.n:82tmp |= g.graph[i] * ((S >> i)&1)8384tmp &= (~S)85return popcount32(tmp)8687cdef inline int popcount32(int i):88"""89Returns the number of '1' bits in a 32-bits integer.9091If sizeof(int) > 4, this function only returns the number of '1'92bits in (i & ((1<<32) - 1)).93"""94i = i - ((i >> 1) & 0x55555555);95i = (i & 0x33333333) + ((i >> 2) & 0x33333333);96return ((i + (i >> 4) & 0x0F0F0F0F) * 0x01010101) >> 24;979899# If you happened to be doubting the consistency of the popcount32 function100# above, you can give the following doctest a try. It is not tested101# automatically by Sage as it takes a *LONG* time to run (around 5 minutes), but102# it would report any problem if it finds one.103104def test_popcount():105"""106Correction test for popcount32.107108EXAMPLE::109110sage: from sage.graphs.graph_decompositions.vertex_separation import test_popcount111sage: test_popcount() # not tested112"""113cdef int i = 1114# While the last 32 bits of i are not equal to 0115while (i & ((1<<32) - 1)) :116if popcount32(i) != slow_popcount32(i):117print "Error for i = ", str(i)118print "Result with popcount32 : "+str(popcount32(i))119print "Result with slow_popcount32 : "+str(slow_popcount32(i))120i += 1121122123cdef inline int slow_popcount32(int i):124# Slow popcount for 32bits integers125cdef int j = 0126cdef int k127128for k in range(32):129j += (i>>k) & 1130131return j132133134