Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagelib
Path: blob/master/sage/graphs/graph_decompositions/fast_digraph.pyx
4069 views
1
r"""
2
Compact structure for fast operations on less than 32 vertices
3
4
This module implements a digraph structure meant to be used in Cython in
5
**highly enumerative** algorithms. It can store graphs on less than
6
``sizeof(int)`` vertices and perform several basic operations **quickly**
7
(add/remove arcs, count the out-neighborhood of a set of vertices or return its
8
cardinality).
9
10
**Sets and integers :**
11
12
In the following code, sets are represented as integers, where the ith bit is
13
set if element i belongs to the set.
14
"""
15
16
include '../../ext/stdsage.pxi'
17
include '../../ext/cdefs.pxi'
18
include '../../ext/interrupt.pxi'
19
20
from libc.stdint cimport uint8_t
21
22
cdef class FastDigraph:
23
cdef uint8_t n
24
cdef int * graph
25
26
def __cinit__(self, D):
27
r"""
28
Constructor for ``FastDigraph``.
29
"""
30
if D.order() > 8*sizeof(int):
31
raise Exception("Too many vertices. This structure can only encode digraphs on at most sizeof(int) vertices.")
32
33
self.n = D.order()
34
self.graph = NULL
35
36
self.graph = <int *> sage_malloc(self.n*sizeof(int))
37
38
memset(self.graph, 0, self.n * sizeof(int))
39
40
cdef int i, j
41
cdef int tmp
42
43
# When the vertices are not consecutive integers
44
cdef dict vertices_to_int = {}
45
for i,v in enumerate(D.vertices()):
46
vertices_to_int[v] = i
47
48
for u in D:
49
tmp = 0
50
for v in D.neighbors_out(u):
51
tmp |= 1 << vertices_to_int[v]
52
self.graph[vertices_to_int[u]] = tmp
53
54
def __dealloc__(self):
55
r"""
56
Destructor.
57
"""
58
if self.graph != NULL:
59
sage_free(self.graph)
60
61
def print_adjacency_matrix(self):
62
r"""
63
Displays the adjacency matrix of ``self``.
64
"""
65
cdef int i,j
66
for 0<= i<self.n:
67
for 0<= j <self.n:
68
print ((self.graph[i]>>j)&1),
69
print ""
70
71
cdef inline int compute_out_neighborhood_cardinality(FastDigraph g, int S):
72
r"""
73
Returns the cardinality of `N^+(S)\S`.
74
75
INPUT:
76
77
- ``g`` a FastDigraph
78
- S (integer) an integer describing the set
79
"""
80
cdef int i
81
cdef int tmp = 0
82
for 0<= i<g.n:
83
tmp |= g.graph[i] * ((S >> i)&1)
84
85
tmp &= (~S)
86
return popcount32(tmp)
87
88
cdef inline int popcount32(int i):
89
"""
90
Returns the number of '1' bits in a 32-bits integer.
91
92
If sizeof(int) > 4, this function only returns the number of '1'
93
bits in (i & ((1<<32) - 1)).
94
"""
95
i = i - ((i >> 1) & 0x55555555);
96
i = (i & 0x33333333) + ((i >> 2) & 0x33333333);
97
return ((i + (i >> 4) & 0x0F0F0F0F) * 0x01010101) >> 24;
98
99
100
# If you happened to be doubting the consistency of the popcount32 function
101
# above, you can give the following doctest a try. It is not tested
102
# automatically by Sage as it takes a *LONG* time to run (around 5 minutes), but
103
# it would report any problem if it finds one.
104
105
def test_popcount():
106
"""
107
Correction test for popcount32.
108
109
EXAMPLE::
110
111
sage: from sage.graphs.graph_decompositions.vertex_separation import test_popcount
112
sage: test_popcount() # not tested
113
"""
114
cdef int i = 1
115
# While the last 32 bits of i are not equal to 0
116
while (i & ((1<<32) - 1)) :
117
if popcount32(i) != slow_popcount32(i):
118
print "Error for i = ", str(i)
119
print "Result with popcount32 : "+str(popcount32(i))
120
print "Result with slow_popcount32 : "+str(slow_popcount32(i))
121
i += 1
122
123
124
cdef inline int slow_popcount32(int i):
125
# Slow popcount for 32bits integers
126
cdef int j = 0
127
cdef int k
128
129
for k in range(32):
130
j += (i>>k) & 1
131
132
return j
133
134