@@ -63,16 +63,17 @@ from collections import deque
6363
6464from libc.string cimport memset
6565from libc.stdint cimport uint32_t
66- from libcpp.queue cimport priority_queue
67- from libcpp.pair cimport pair
6866from libcpp.vector cimport vector
6967from cysignals.signals cimport sig_on, sig_off
7068from memory_allocator cimport MemoryAllocator
7169
70+ from sage.data_structures.pairing_heap cimport PairingHeap_of_n_integers
71+ from sage.graphs.base.c_graph cimport CGraph, CGraphBackend
72+ from sage.graphs.base.static_sparse_backend cimport StaticSparseCGraph
73+ from sage.graphs.base.static_sparse_backend cimport StaticSparseBackend
7274from sage.graphs.base.static_sparse_graph cimport init_short_digraph
7375from sage.graphs.base.static_sparse_graph cimport free_short_digraph
7476from sage.graphs.base.static_sparse_graph cimport out_degree
75- from sage.graphs.base.c_graph cimport CGraph, CGraphBackend
7677from sage.graphs.graph_decompositions.slice_decomposition cimport \
7778 extended_lex_BFS
7879
@@ -753,8 +754,7 @@ def lex_M(self, triangulation=False, labels=False, initial_vertex=None, algorith
753754 - ``labels`` -- boolean ( default: ``False``) ; whether to return the labels
754755 assigned to each vertex
755756
756- - ``initial_vertex`` -- ( default: ``None``) the first vertex to
757- consider
757+ - ``initial_vertex`` -- ( default: ``None``) ; the first vertex to consider
758758
759759 - ``algorithm`` -- string ( default: ``None``) ; one of the following
760760 algorithms:
@@ -820,6 +820,18 @@ def lex_M(self, triangulation=False, labels=False, initial_vertex=None, algorith
820820 sage: g. lex_M( )
821821 [6, 4, 5, 3, 2, 1 ]
822822
823+ The ordering depends on the initial vertex::
824+
825+ sage: G = graphs. HouseGraph( )
826+ sage: G. lex_M( algorithm='lex_M_slow', initial_vertex=0)
827+ [4, 3, 2, 1, 0 ]
828+ sage: G. lex_M( algorithm='lex_M_slow', initial_vertex=2)
829+ [1, 4, 3, 0, 2 ]
830+ sage: G. lex_M( algorithm='lex_M_fast', initial_vertex=0)
831+ [4, 3, 2, 1, 0 ]
832+ sage: G. lex_M( algorithm='lex_M_fast', initial_vertex=2)
833+ [1, 4, 3, 0, 2 ]
834+
823835 TESTS:
824836
825837 ``'lex_M_fast'`` cannot return labels::
@@ -1127,6 +1139,18 @@ def lex_M_fast(G, triangulation=False, initial_vertex=None):
11271139 Traceback ( most recent call last) :
11281140 ...
11291141 ValueError: 'foo' is not a graph vertex
1142+
1143+ Immutable graphs::
1144+
1145+ sage: from sage. graphs. traversals import lex_M_fast
1146+ sage: G = graphs. RandomGNP( 10, . 7)
1147+ sage: G. _backend
1148+ <sage. graphs. base. sparse_graph. SparseGraphBackend ... >
1149+ sage: H = Graph( G, immutable=True)
1150+ sage: H. _backend
1151+ <sage. graphs. base. static_sparse_backend. StaticSparseBackend ... >
1152+ sage: lex_M_fast( G) == lex_M_fast( H)
1153+ True
11301154 """
11311155 if initial_vertex is not None and initial_vertex not in G:
11321156 raise ValueError (" '{}' is not a graph vertex" .format(initial_vertex))
@@ -1136,23 +1160,31 @@ def lex_M_fast(G, triangulation=False, initial_vertex=None):
11361160
11371161 # ==> Initialization
11381162
1139- cdef list int_to_v = list (G)
11401163 cdef int i, j, k, v, w, z
11411164
1142- if initial_vertex is not None :
1143- # We put the initial vertex at first place in the ordering
1144- i = int_to_v.index(initial_vertex)
1145- int_to_v[0 ], int_to_v[i] = int_to_v[i], int_to_v[0 ]
1146-
1165+ cdef list int_to_v
1166+ cdef StaticSparseCGraph cg
11471167 cdef short_digraph sd
1148- init_short_digraph(sd, G, edge_labelled = False , vertex_list = int_to_v)
1168+ if isinstance (G, StaticSparseBackend):
1169+ cg = < StaticSparseCGraph> G._cg
1170+ sd = < short_digraph> cg.g
1171+ int_to_v = cg._vertex_to_labels
1172+ else :
1173+ int_to_v = list (G)
1174+ init_short_digraph(sd, G, edge_labelled = False , vertex_list = int_to_v)
1175+
11491176 cdef uint32_t* p_tmp
11501177 cdef uint32_t* p_end
11511178
11521179 cdef int n = G.order()
11531180
11541181 cdef list unnumbered_vertices = list (range (n))
11551182
1183+ if initial_vertex is not None :
1184+ # We put the initial vertex at the first place
1185+ i = int_to_v.index(initial_vertex)
1186+ unnumbered_vertices[0 ], unnumbered_vertices[i] = unnumbered_vertices[i], unnumbered_vertices[0 ]
1187+
11561188 cdef MemoryAllocator mem = MemoryAllocator()
11571189 cdef int * label = < int * > mem.allocarray(n, sizeof(int ))
11581190 cdef int * alpha = < int * > mem.allocarray(n, sizeof(int ))
@@ -1237,7 +1269,8 @@ def lex_M_fast(G, triangulation=False, initial_vertex=None):
12371269 k += 2
12381270 label[w] = k
12391271
1240- free_short_digraph(sd)
1272+ if not isinstance (G, StaticSparseBackend):
1273+ free_short_digraph(sd)
12411274
12421275 cdef list ordering = [int_to_v[alpha[i]] for i in range (n)]
12431276
@@ -1354,9 +1387,9 @@ def maximum_cardinality_search(G, reverse=False, tree=False, initial_vertex=None
13541387 sage: G. maximum_cardinality_search( initial_vertex=0)
13551388 [3, 2, 1, 0 ]
13561389 sage: G. maximum_cardinality_search( initial_vertex=1)
1357- [0, 3, 2, 1 ]
1390+ [3, 2, 0 , 1 ]
13581391 sage: G. maximum_cardinality_search( initial_vertex=2)
1359- [0, 1, 3 , 2 ]
1392+ [0, 3, 1 , 2 ]
13601393 sage: G. maximum_cardinality_search( initial_vertex=3)
13611394 [0, 1, 2, 3 ]
13621395 sage: G. maximum_cardinality_search( initial_vertex=3, reverse=True)
@@ -1388,6 +1421,17 @@ def maximum_cardinality_search(G, reverse=False, tree=False, initial_vertex=None
13881421 Traceback ( most recent call last) :
13891422 ...
13901423 ValueError: vertex ( 17) is not a vertex of the graph
1424+
1425+ Immutable graphs;:
1426+
1427+ sage: G = graphs. RandomGNP( 10, . 7)
1428+ sage: G. _backend
1429+ <sage. graphs. base. sparse_graph. SparseGraphBackend ... >
1430+ sage: H = Graph( G, immutable=True)
1431+ sage: H. _backend
1432+ <sage. graphs. base. static_sparse_backend. StaticSparseBackend ... >
1433+ sage: G. maximum_cardinality_search( ) == H. maximum_cardinality_search( )
1434+ True
13911435 """
13921436 if tree:
13931437 from sage.graphs.digraph import DiGraph
@@ -1398,17 +1442,27 @@ def maximum_cardinality_search(G, reverse=False, tree=False, initial_vertex=None
13981442 if N == 1 :
13991443 return (list (G), DiGraph(G)) if tree else list (G)
14001444
1401- cdef list int_to_vertex = list (G)
1445+ cdef list int_to_vertex
1446+ cdef StaticSparseCGraph cg
1447+ cdef short_digraph sd
1448+ if isinstance (G, StaticSparseBackend):
1449+ cg = < StaticSparseCGraph> G._cg
1450+ sd = < short_digraph> cg.g
1451+ int_to_vertex = cg._vertex_to_labels
1452+ else :
1453+ int_to_vertex = list (G)
1454+ init_short_digraph(sd, G, edge_labelled = False , vertex_list = int_to_vertex)
14021455
14031456 if initial_vertex is None :
14041457 initial_vertex = 0
14051458 elif initial_vertex in G:
1406- initial_vertex = int_to_vertex.index(initial_vertex)
1459+ if isinstance (G, StaticSparseBackend):
1460+ initial_vertex = cg._vertex_to_int[initial_vertex]
1461+ else :
1462+ initial_vertex = int_to_vertex.index(initial_vertex)
14071463 else :
14081464 raise ValueError (" vertex ({0}) is not a vertex of the graph" .format(initial_vertex))
14091465
1410- cdef short_digraph sd
1411- init_short_digraph(sd, G, edge_labelled = False , vertex_list = int_to_vertex)
14121466 cdef uint32_t** p_vertices = sd.neighbors
14131467 cdef uint32_t* p_tmp
14141468 cdef uint32_t* p_end
@@ -1420,27 +1474,18 @@ def maximum_cardinality_search(G, reverse=False, tree=False, initial_vertex=None
14201474
14211475 cdef int i, u, v
14221476 for i in range (N):
1423- weight[i] = 0
1424- seen[i] = False
14251477 pred[i] = i
14261478
1427- # We emulate a heap with decrease key operation using a priority queue.
1428- # A vertex can be inserted multiple times (up to its degree), but only the
1429- # first extraction (with maximum weight) matters. The size of the queue will
1430- # never exceed O(m).
1431- cdef priority_queue[pair[int , int ]] pq
1432- pq.push((0 , initial_vertex))
1479+ # We emulate a max-heap data structure using a min-heap with negative values
1480+ cdef PairingHeap_of_n_integers P = PairingHeap_of_n_integers(N)
1481+ P.push(initial_vertex, 0 )
14331482
14341483 # The ordering alpha is feed in reversed order and revert afterword
14351484 cdef list alpha = []
14361485
1437- while not pq.empty():
1438- _, u = pq.top()
1439- pq.pop()
1440- if seen[u]:
1441- # We use a lazy decrease key mode, so u can be several times in pq
1442- continue
1443-
1486+ while P:
1487+ u = P.top_item()
1488+ P.pop()
14441489 alpha.append(int_to_vertex[u])
14451490 seen[u] = True
14461491
@@ -1450,12 +1495,13 @@ def maximum_cardinality_search(G, reverse=False, tree=False, initial_vertex=None
14501495 v = p_tmp[0 ]
14511496 if not seen[v]:
14521497 weight[v] += 1
1453- pq.push((weight[v], v) )
1498+ P.decrease(v, - weight[v] )
14541499 if pred[v] == v:
14551500 pred[v] = u
14561501 p_tmp += 1
14571502
1458- free_short_digraph(sd)
1503+ if not isinstance (G, StaticSparseBackend):
1504+ free_short_digraph(sd)
14591505
14601506 if len (alpha) < N:
14611507 raise ValueError (" the input graph is not connected" )
@@ -1762,16 +1808,18 @@ def maximum_cardinality_search_M(G, initial_vertex=None):
17621808 Traceback ( most recent call last) :
17631809 ...
17641810 ValueError: vertex ( 17) is not a vertex of the graph
1765- """
1766- cdef list int_to_vertex = list (G)
17671811
1768- if initial_vertex is None :
1769- initial_vertex = 0
1770- elif initial_vertex in G:
1771- initial_vertex = int_to_vertex.index(initial_vertex)
1772- else :
1773- raise ValueError (" vertex ({0}) is not a vertex of the graph" .format(initial_vertex))
1812+ Immutable graphs::
17741813
1814+ sage: G = graphs. RandomGNP( 10, . 7)
1815+ sage: G. _backend
1816+ <sage. graphs. base. sparse_graph. SparseGraphBackend ... >
1817+ sage: H = Graph( G, immutable=True)
1818+ sage: H. _backend
1819+ <sage. graphs. base. static_sparse_backend. StaticSparseBackend ... >
1820+ sage: G. maximum_cardinality_search_M( ) == H. maximum_cardinality_search_M( )
1821+ True
1822+ """
17751823 cdef int N = G.order()
17761824 if not N:
17771825 return ([], [], [])
@@ -1781,8 +1829,26 @@ def maximum_cardinality_search_M(G, initial_vertex=None):
17811829 # Copying the whole graph to obtain the list of neighbors quicker than by
17821830 # calling out_neighbors. This data structure is well documented in the
17831831 # module sage.graphs.base.static_sparse_graph
1832+ cdef list int_to_vertex
1833+ cdef StaticSparseCGraph cg
17841834 cdef short_digraph sd
1785- init_short_digraph(sd, G, edge_labelled = False , vertex_list = int_to_vertex)
1835+ if isinstance (G, StaticSparseBackend):
1836+ cg = < StaticSparseCGraph> G._cg
1837+ sd = < short_digraph> cg.g
1838+ int_to_vertex = cg._vertex_to_labels
1839+ else :
1840+ int_to_vertex = list (G)
1841+ init_short_digraph(sd, G, edge_labelled = False , vertex_list = int_to_vertex)
1842+
1843+ if initial_vertex is None :
1844+ initial_vertex = 0
1845+ elif initial_vertex in G:
1846+ if isinstance (G, StaticSparseBackend):
1847+ initial_vertex = cg._vertex_to_int[initial_vertex]
1848+ else :
1849+ initial_vertex = int_to_vertex.index(initial_vertex)
1850+ else :
1851+ raise ValueError (" vertex ({0}) is not a vertex of the graph" .format(initial_vertex))
17861852
17871853 cdef MemoryAllocator mem = MemoryAllocator()
17881854 cdef int * alpha = < int * > mem.calloc(N, sizeof(int ))
@@ -1794,7 +1860,8 @@ def maximum_cardinality_search_M(G, initial_vertex=None):
17941860 maximum_cardinality_search_M_short_digraph(sd, initial_vertex, alpha, alpha_inv, F, X)
17951861 sig_off()
17961862
1797- free_short_digraph(sd)
1863+ if not isinstance (G, StaticSparseBackend):
1864+ free_short_digraph(sd)
17981865
17991866 cdef int u, v
18001867 return ([int_to_vertex[alpha[u]] for u in range (N)],
0 commit comments