passagemath-graphs 10.5.43__cp39-cp39-musllinux_1_2_aarch64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (258) hide show
  1. passagemath_graphs-10.5.43.dist-info/METADATA +293 -0
  2. passagemath_graphs-10.5.43.dist-info/RECORD +258 -0
  3. passagemath_graphs-10.5.43.dist-info/WHEEL +5 -0
  4. passagemath_graphs-10.5.43.dist-info/top_level.txt +2 -0
  5. passagemath_graphs.libs/libgcc_s-69c45f16.so.1 +0 -0
  6. passagemath_graphs.libs/libgmp-8e78bd9b.so.10.5.0 +0 -0
  7. passagemath_graphs.libs/libstdc++-1f1a71be.so.6.0.33 +0 -0
  8. sage/all__sagemath_graphs.py +39 -0
  9. sage/combinat/abstract_tree.py +2552 -0
  10. sage/combinat/all__sagemath_graphs.py +34 -0
  11. sage/combinat/binary_tree.py +5306 -0
  12. sage/combinat/cluster_algebra_quiver/all.py +22 -0
  13. sage/combinat/cluster_algebra_quiver/cluster_seed.py +5208 -0
  14. sage/combinat/cluster_algebra_quiver/interact.py +125 -0
  15. sage/combinat/cluster_algebra_quiver/mutation_class.py +625 -0
  16. sage/combinat/cluster_algebra_quiver/mutation_type.py +1556 -0
  17. sage/combinat/cluster_algebra_quiver/quiver.py +2262 -0
  18. sage/combinat/cluster_algebra_quiver/quiver_mutation_type.py +2468 -0
  19. sage/combinat/designs/MOLS_handbook_data.py +570 -0
  20. sage/combinat/designs/all.py +58 -0
  21. sage/combinat/designs/bibd.py +1655 -0
  22. sage/combinat/designs/block_design.py +1071 -0
  23. sage/combinat/designs/covering_array.py +269 -0
  24. sage/combinat/designs/covering_design.py +534 -0
  25. sage/combinat/designs/database.py +5614 -0
  26. sage/combinat/designs/design_catalog.py +122 -0
  27. sage/combinat/designs/designs_pyx.cpython-39-aarch64-linux-gnu.so +0 -0
  28. sage/combinat/designs/designs_pyx.pxd +21 -0
  29. sage/combinat/designs/designs_pyx.pyx +993 -0
  30. sage/combinat/designs/difference_family.py +3951 -0
  31. sage/combinat/designs/difference_matrices.py +279 -0
  32. sage/combinat/designs/evenly_distributed_sets.cpython-39-aarch64-linux-gnu.so +0 -0
  33. sage/combinat/designs/evenly_distributed_sets.pyx +661 -0
  34. sage/combinat/designs/ext_rep.py +1064 -0
  35. sage/combinat/designs/gen_quadrangles_with_spread.cpython-39-aarch64-linux-gnu.so +0 -0
  36. sage/combinat/designs/gen_quadrangles_with_spread.pyx +339 -0
  37. sage/combinat/designs/group_divisible_designs.py +361 -0
  38. sage/combinat/designs/incidence_structures.py +2357 -0
  39. sage/combinat/designs/latin_squares.py +548 -0
  40. sage/combinat/designs/orthogonal_arrays.py +2243 -0
  41. sage/combinat/designs/orthogonal_arrays_build_recursive.py +1780 -0
  42. sage/combinat/designs/orthogonal_arrays_find_recursive.cpython-39-aarch64-linux-gnu.so +0 -0
  43. sage/combinat/designs/orthogonal_arrays_find_recursive.pyx +966 -0
  44. sage/combinat/designs/resolvable_bibd.py +781 -0
  45. sage/combinat/designs/steiner_quadruple_systems.py +1306 -0
  46. sage/combinat/designs/subhypergraph_search.cpython-39-aarch64-linux-gnu.so +0 -0
  47. sage/combinat/designs/subhypergraph_search.pyx +530 -0
  48. sage/combinat/designs/twographs.py +306 -0
  49. sage/combinat/finite_state_machine.py +14874 -0
  50. sage/combinat/finite_state_machine_generators.py +2006 -0
  51. sage/combinat/graph_path.py +448 -0
  52. sage/combinat/interval_posets.py +3908 -0
  53. sage/combinat/nu_tamari_lattice.py +269 -0
  54. sage/combinat/ordered_tree.py +1446 -0
  55. sage/combinat/posets/all.py +46 -0
  56. sage/combinat/posets/cartesian_product.py +493 -0
  57. sage/combinat/posets/d_complete.py +182 -0
  58. sage/combinat/posets/elements.py +273 -0
  59. sage/combinat/posets/forest.py +30 -0
  60. sage/combinat/posets/hasse_cython.cpython-39-aarch64-linux-gnu.so +0 -0
  61. sage/combinat/posets/hasse_cython.pyx +174 -0
  62. sage/combinat/posets/hasse_diagram.py +3678 -0
  63. sage/combinat/posets/incidence_algebras.py +796 -0
  64. sage/combinat/posets/lattices.py +5119 -0
  65. sage/combinat/posets/linear_extension_iterator.cpython-39-aarch64-linux-gnu.so +0 -0
  66. sage/combinat/posets/linear_extension_iterator.pyx +292 -0
  67. sage/combinat/posets/linear_extensions.py +1039 -0
  68. sage/combinat/posets/mobile.py +275 -0
  69. sage/combinat/posets/moebius_algebra.py +776 -0
  70. sage/combinat/posets/poset_examples.py +2131 -0
  71. sage/combinat/posets/posets.py +9169 -0
  72. sage/combinat/rooted_tree.py +1070 -0
  73. sage/combinat/shard_order.py +239 -0
  74. sage/combinat/tamari_lattices.py +384 -0
  75. sage/combinat/yang_baxter_graph.py +923 -0
  76. sage/databases/all__sagemath_graphs.py +1 -0
  77. sage/databases/knotinfo_db.py +1230 -0
  78. sage/ext_data/all__sagemath_graphs.py +1 -0
  79. sage/ext_data/graphs/graph_plot_js.html +330 -0
  80. sage/ext_data/kenzo/CP2.txt +45 -0
  81. sage/ext_data/kenzo/CP3.txt +349 -0
  82. sage/ext_data/kenzo/CP4.txt +4774 -0
  83. sage/ext_data/kenzo/README.txt +49 -0
  84. sage/ext_data/kenzo/S4.txt +20 -0
  85. sage/graphs/all.py +42 -0
  86. sage/graphs/asteroidal_triples.cpython-39-aarch64-linux-gnu.so +0 -0
  87. sage/graphs/asteroidal_triples.pyx +299 -0
  88. sage/graphs/base/all.py +1 -0
  89. sage/graphs/base/boost_graph.cpython-39-aarch64-linux-gnu.so +0 -0
  90. sage/graphs/base/boost_graph.pxd +106 -0
  91. sage/graphs/base/boost_graph.pyx +3045 -0
  92. sage/graphs/base/c_graph.cpython-39-aarch64-linux-gnu.so +0 -0
  93. sage/graphs/base/c_graph.pxd +106 -0
  94. sage/graphs/base/c_graph.pyx +5096 -0
  95. sage/graphs/base/dense_graph.cpython-39-aarch64-linux-gnu.so +0 -0
  96. sage/graphs/base/dense_graph.pxd +26 -0
  97. sage/graphs/base/dense_graph.pyx +757 -0
  98. sage/graphs/base/graph_backends.cpython-39-aarch64-linux-gnu.so +0 -0
  99. sage/graphs/base/graph_backends.pxd +5 -0
  100. sage/graphs/base/graph_backends.pyx +797 -0
  101. sage/graphs/base/overview.py +85 -0
  102. sage/graphs/base/sparse_graph.cpython-39-aarch64-linux-gnu.so +0 -0
  103. sage/graphs/base/sparse_graph.pxd +90 -0
  104. sage/graphs/base/sparse_graph.pyx +1653 -0
  105. sage/graphs/base/static_dense_graph.cpython-39-aarch64-linux-gnu.so +0 -0
  106. sage/graphs/base/static_dense_graph.pxd +5 -0
  107. sage/graphs/base/static_dense_graph.pyx +1032 -0
  108. sage/graphs/base/static_sparse_backend.cpython-39-aarch64-linux-gnu.so +0 -0
  109. sage/graphs/base/static_sparse_backend.pxd +27 -0
  110. sage/graphs/base/static_sparse_backend.pyx +1580 -0
  111. sage/graphs/base/static_sparse_graph.cpython-39-aarch64-linux-gnu.so +0 -0
  112. sage/graphs/base/static_sparse_graph.pxd +37 -0
  113. sage/graphs/base/static_sparse_graph.pyx +1304 -0
  114. sage/graphs/bipartite_graph.py +2709 -0
  115. sage/graphs/centrality.cpython-39-aarch64-linux-gnu.so +0 -0
  116. sage/graphs/centrality.pyx +965 -0
  117. sage/graphs/cographs.py +519 -0
  118. sage/graphs/comparability.cpython-39-aarch64-linux-gnu.so +0 -0
  119. sage/graphs/comparability.pyx +813 -0
  120. sage/graphs/connectivity.cpython-39-aarch64-linux-gnu.so +0 -0
  121. sage/graphs/connectivity.pxd +157 -0
  122. sage/graphs/connectivity.pyx +4813 -0
  123. sage/graphs/convexity_properties.cpython-39-aarch64-linux-gnu.so +0 -0
  124. sage/graphs/convexity_properties.pxd +16 -0
  125. sage/graphs/convexity_properties.pyx +827 -0
  126. sage/graphs/digraph.py +4410 -0
  127. sage/graphs/digraph_generators.py +1921 -0
  128. sage/graphs/distances_all_pairs.cpython-39-aarch64-linux-gnu.so +0 -0
  129. sage/graphs/distances_all_pairs.pxd +12 -0
  130. sage/graphs/distances_all_pairs.pyx +2938 -0
  131. sage/graphs/domination.py +1363 -0
  132. sage/graphs/dot2tex_utils.py +100 -0
  133. sage/graphs/edge_connectivity.cpython-39-aarch64-linux-gnu.so +0 -0
  134. sage/graphs/edge_connectivity.pyx +1215 -0
  135. sage/graphs/generators/all.py +1 -0
  136. sage/graphs/generators/basic.py +1769 -0
  137. sage/graphs/generators/chessboard.py +538 -0
  138. sage/graphs/generators/classical_geometries.py +1611 -0
  139. sage/graphs/generators/degree_sequence.py +235 -0
  140. sage/graphs/generators/distance_regular.cpython-39-aarch64-linux-gnu.so +0 -0
  141. sage/graphs/generators/distance_regular.pyx +2846 -0
  142. sage/graphs/generators/families.py +4749 -0
  143. sage/graphs/generators/intersection.py +565 -0
  144. sage/graphs/generators/platonic_solids.py +262 -0
  145. sage/graphs/generators/random.py +2623 -0
  146. sage/graphs/generators/smallgraphs.py +5741 -0
  147. sage/graphs/generators/world_map.py +724 -0
  148. sage/graphs/generic_graph.py +26395 -0
  149. sage/graphs/generic_graph_pyx.cpython-39-aarch64-linux-gnu.so +0 -0
  150. sage/graphs/generic_graph_pyx.pxd +34 -0
  151. sage/graphs/generic_graph_pyx.pyx +1626 -0
  152. sage/graphs/genus.cpython-39-aarch64-linux-gnu.so +0 -0
  153. sage/graphs/genus.pyx +623 -0
  154. sage/graphs/graph.py +9362 -0
  155. sage/graphs/graph_coloring.cpython-39-aarch64-linux-gnu.so +0 -0
  156. sage/graphs/graph_coloring.pyx +2284 -0
  157. sage/graphs/graph_database.py +1122 -0
  158. sage/graphs/graph_decompositions/all.py +1 -0
  159. sage/graphs/graph_decompositions/bandwidth.cpython-39-aarch64-linux-gnu.so +0 -0
  160. sage/graphs/graph_decompositions/bandwidth.pyx +428 -0
  161. sage/graphs/graph_decompositions/clique_separators.cpython-39-aarch64-linux-gnu.so +0 -0
  162. sage/graphs/graph_decompositions/clique_separators.pyx +595 -0
  163. sage/graphs/graph_decompositions/cutwidth.cpython-39-aarch64-linux-gnu.so +0 -0
  164. sage/graphs/graph_decompositions/cutwidth.pyx +753 -0
  165. sage/graphs/graph_decompositions/fast_digraph.cpython-39-aarch64-linux-gnu.so +0 -0
  166. sage/graphs/graph_decompositions/fast_digraph.pxd +13 -0
  167. sage/graphs/graph_decompositions/fast_digraph.pyx +212 -0
  168. sage/graphs/graph_decompositions/graph_products.cpython-39-aarch64-linux-gnu.so +0 -0
  169. sage/graphs/graph_decompositions/graph_products.pyx +462 -0
  170. sage/graphs/graph_decompositions/modular_decomposition.cpython-39-aarch64-linux-gnu.so +0 -0
  171. sage/graphs/graph_decompositions/modular_decomposition.pxd +27 -0
  172. sage/graphs/graph_decompositions/modular_decomposition.pyx +1536 -0
  173. sage/graphs/graph_decompositions/slice_decomposition.cpython-39-aarch64-linux-gnu.so +0 -0
  174. sage/graphs/graph_decompositions/slice_decomposition.pxd +18 -0
  175. sage/graphs/graph_decompositions/slice_decomposition.pyx +1080 -0
  176. sage/graphs/graph_decompositions/tree_decomposition.cpython-39-aarch64-linux-gnu.so +0 -0
  177. sage/graphs/graph_decompositions/tree_decomposition.pxd +17 -0
  178. sage/graphs/graph_decompositions/tree_decomposition.pyx +1996 -0
  179. sage/graphs/graph_decompositions/vertex_separation.cpython-39-aarch64-linux-gnu.so +0 -0
  180. sage/graphs/graph_decompositions/vertex_separation.pxd +5 -0
  181. sage/graphs/graph_decompositions/vertex_separation.pyx +1963 -0
  182. sage/graphs/graph_editor.py +82 -0
  183. sage/graphs/graph_generators.py +3301 -0
  184. sage/graphs/graph_generators_pyx.cpython-39-aarch64-linux-gnu.so +0 -0
  185. sage/graphs/graph_generators_pyx.pyx +95 -0
  186. sage/graphs/graph_input.py +812 -0
  187. sage/graphs/graph_latex.py +2064 -0
  188. sage/graphs/graph_list.py +367 -0
  189. sage/graphs/graph_plot.py +1749 -0
  190. sage/graphs/graph_plot_js.py +338 -0
  191. sage/graphs/hyperbolicity.cpython-39-aarch64-linux-gnu.so +0 -0
  192. sage/graphs/hyperbolicity.pyx +1702 -0
  193. sage/graphs/hypergraph_generators.py +364 -0
  194. sage/graphs/independent_sets.cpython-39-aarch64-linux-gnu.so +0 -0
  195. sage/graphs/independent_sets.pxd +13 -0
  196. sage/graphs/independent_sets.pyx +402 -0
  197. sage/graphs/isgci.py +1033 -0
  198. sage/graphs/isoperimetric_inequalities.cpython-39-aarch64-linux-gnu.so +0 -0
  199. sage/graphs/isoperimetric_inequalities.pyx +453 -0
  200. sage/graphs/line_graph.cpython-39-aarch64-linux-gnu.so +0 -0
  201. sage/graphs/line_graph.pyx +627 -0
  202. sage/graphs/lovasz_theta.py +77 -0
  203. sage/graphs/matching.py +1633 -0
  204. sage/graphs/matching_covered_graph.py +3566 -0
  205. sage/graphs/orientations.py +1504 -0
  206. sage/graphs/partial_cube.py +459 -0
  207. sage/graphs/path_enumeration.cpython-39-aarch64-linux-gnu.so +0 -0
  208. sage/graphs/path_enumeration.pyx +2040 -0
  209. sage/graphs/pq_trees.py +1129 -0
  210. sage/graphs/print_graphs.py +201 -0
  211. sage/graphs/schnyder.py +865 -0
  212. sage/graphs/spanning_tree.cpython-39-aarch64-linux-gnu.so +0 -0
  213. sage/graphs/spanning_tree.pyx +1457 -0
  214. sage/graphs/strongly_regular_db.cpython-39-aarch64-linux-gnu.so +0 -0
  215. sage/graphs/strongly_regular_db.pyx +3340 -0
  216. sage/graphs/traversals.cpython-39-aarch64-linux-gnu.so +0 -0
  217. sage/graphs/traversals.pxd +9 -0
  218. sage/graphs/traversals.pyx +1871 -0
  219. sage/graphs/trees.cpython-39-aarch64-linux-gnu.so +0 -0
  220. sage/graphs/trees.pxd +15 -0
  221. sage/graphs/trees.pyx +310 -0
  222. sage/graphs/tutte_polynomial.py +713 -0
  223. sage/graphs/views.cpython-39-aarch64-linux-gnu.so +0 -0
  224. sage/graphs/views.pyx +794 -0
  225. sage/graphs/weakly_chordal.cpython-39-aarch64-linux-gnu.so +0 -0
  226. sage/graphs/weakly_chordal.pyx +562 -0
  227. sage/groups/all__sagemath_graphs.py +1 -0
  228. sage/groups/perm_gps/all__sagemath_graphs.py +1 -0
  229. sage/groups/perm_gps/partn_ref/all__sagemath_graphs.py +1 -0
  230. sage/groups/perm_gps/partn_ref/refinement_graphs.cpython-39-aarch64-linux-gnu.so +0 -0
  231. sage/groups/perm_gps/partn_ref/refinement_graphs.pxd +38 -0
  232. sage/groups/perm_gps/partn_ref/refinement_graphs.pyx +1666 -0
  233. sage/knots/all.py +6 -0
  234. sage/knots/free_knotinfo_monoid.py +507 -0
  235. sage/knots/gauss_code.py +291 -0
  236. sage/knots/knot.py +682 -0
  237. sage/knots/knot_table.py +284 -0
  238. sage/knots/knotinfo.py +2880 -0
  239. sage/knots/link.py +4682 -0
  240. sage/sandpiles/all.py +13 -0
  241. sage/sandpiles/examples.py +225 -0
  242. sage/sandpiles/sandpile.py +6365 -0
  243. sage/topology/all.py +22 -0
  244. sage/topology/cell_complex.py +1214 -0
  245. sage/topology/cubical_complex.py +1977 -0
  246. sage/topology/delta_complex.py +1806 -0
  247. sage/topology/filtered_simplicial_complex.py +744 -0
  248. sage/topology/moment_angle_complex.py +823 -0
  249. sage/topology/simplicial_complex.py +5161 -0
  250. sage/topology/simplicial_complex_catalog.py +86 -0
  251. sage/topology/simplicial_complex_examples.py +1692 -0
  252. sage/topology/simplicial_complex_homset.py +205 -0
  253. sage/topology/simplicial_complex_morphism.py +836 -0
  254. sage/topology/simplicial_set.py +4102 -0
  255. sage/topology/simplicial_set_catalog.py +55 -0
  256. sage/topology/simplicial_set_constructions.py +2954 -0
  257. sage/topology/simplicial_set_examples.py +865 -0
  258. sage/topology/simplicial_set_morphism.py +1464 -0
@@ -0,0 +1,1580 @@
1
+ # sage_setup: distribution = sagemath-graphs
2
+ r"""
3
+ Static sparse graph backend
4
+
5
+ This module implement a immutable sparse graph backend using the data structure
6
+ from :mod:`sage.graphs.base.static_sparse_graph`. It supports both directed and
7
+ undirected graphs, as well as vertex/edge labels, loops and multiple edges. As
8
+ it uses a very compact C structure it should be very small in memory.
9
+
10
+ As it is a sparse data structure, you can expect it to be very efficient when
11
+ you need to list the graph's edge, or those incident to a vertex, but an
12
+ adjacency test can be much longer than in a dense data structure (i.e. like in
13
+ :mod:`sage.graphs.base.static_dense_graph`)
14
+
15
+ For an overview of graph data structures in sage, see
16
+ :mod:`~sage.graphs.base.overview`.
17
+
18
+ Two classes
19
+ -----------
20
+
21
+ This module implements two classes
22
+
23
+ * :class:`StaticSparseCGraph` extends :class:`~sage.graphs.base.c_graph.CGraph`
24
+ and is a Cython class that manages the definition/deallocation of the
25
+ ``short_digraph`` structure. It does not know anything about labels on
26
+ vertices.
27
+
28
+ * :class:`StaticSparseBackend` extends
29
+ :class:`~sage.graphs.base.c_graph.CGraphBackend` and is a Python class that
30
+ does know about vertex labels and contains an instance of
31
+ :class:`StaticSparseCGraph` as an internal variable. The input/output of its
32
+ methods are labeled vertices, which it translates to integer id before
33
+ forwarding them to the :class:`StaticSparseCGraph` instance.
34
+
35
+ Classes and methods
36
+ -------------------
37
+ """
38
+
39
+ from cysignals.memory cimport check_calloc, sig_free
40
+
41
+ from sage.graphs.base.static_sparse_graph cimport (init_short_digraph,
42
+ init_reverse,
43
+ out_degree,
44
+ has_edge,
45
+ free_short_digraph,
46
+ edge_label)
47
+ from sage.graphs.base.c_graph cimport CGraphBackend
48
+ from sage.data_structures.bitset cimport FrozenBitset
49
+ from libc.stdint cimport uint32_t
50
+ from sage.data_structures.bitset_base cimport *
51
+
52
+ cdef extern from "Python.h":
53
+ int unlikely(int) nogil # Defined by Cython
54
+
55
+ cdef class StaticSparseCGraph(CGraph):
56
+ """
57
+ :mod:`CGraph <sage.graphs.base.c_graph>` class based on the sparse graph
58
+ data structure :mod:`static sparse graphs
59
+ <sage.graphs.base.static_sparse_graph>`.
60
+ """
61
+
62
+ def __cinit__(self, G, vertex_list=None):
63
+ r"""
64
+ Cython constructor.
65
+
66
+ INPUT:
67
+
68
+ - ``G`` -- a :class:`Graph` object
69
+
70
+ - ``vertex_list`` -- (optional) list of all vertices of ``G``
71
+
72
+ The optional argument ``vertex_list`` is assumed to be a list of all
73
+ vertices of the graph ``G`` in some order.
74
+ **Beware that no serious checks are made that this input is correct**.
75
+
76
+ If ``vertex_list`` is given, it will be used to map vertices
77
+ of the graph to consecutive integers. Otherwise, the result of
78
+ ``G.vertices(sort=True)`` will be used instead. Because this
79
+ only works if the vertices can be sorted, using
80
+ ``vertex_list`` is useful when working with possibly
81
+ non-sortable objects in Python 3.
82
+
83
+ TESTS::
84
+
85
+ sage: from sage.graphs.base.static_sparse_backend import StaticSparseCGraph
86
+ sage: g = StaticSparseCGraph(graphs.PetersenGraph())
87
+
88
+ Check that the digraph methods are working (see :issue:`20253`)::
89
+
90
+ sage: G = DiGraph([(0, 1), (1, 0)])
91
+ sage: G2 = G.copy(immutable=True)
92
+ sage: G2.is_strongly_connected()
93
+ True
94
+
95
+ Using the ``vertex_list`` optional argument::
96
+
97
+ sage: g = StaticSparseCGraph(DiGraph({0: [2]}), vertex_list=[2, 0])
98
+ sage: g.has_arc(0, 1)
99
+ False
100
+ sage: g.has_arc(1, 0)
101
+ True
102
+
103
+ sage: g = StaticSparseCGraph(DiGraph({0: [2]}), vertex_list=[2, 0, 4])
104
+ Traceback (most recent call last):
105
+ ...
106
+ ValueError: vertex_list has wrong length
107
+ """
108
+ cdef int i, j, tmp
109
+ has_labels = any(l is not None for _, _, l in G.edge_iterator())
110
+ self._directed = G.is_directed()
111
+
112
+ if vertex_list is not None and len(vertex_list) != G.order():
113
+ raise ValueError('vertex_list has wrong length')
114
+
115
+ init_short_digraph(self.g, G, edge_labelled=has_labels,
116
+ vertex_list=vertex_list)
117
+ if self._directed:
118
+ init_reverse(self.g_rev, self.g)
119
+
120
+ # Store the number of loops for undirected graphs
121
+ elif not G.has_loops():
122
+ self.number_of_loops = NULL
123
+ else:
124
+ try:
125
+ self.number_of_loops = <int *>check_calloc(self.g.n, sizeof(int))
126
+ except MemoryError:
127
+ free_short_digraph(self.g)
128
+ raise
129
+ for i in range(self.g.n):
130
+ for tmp in range(out_degree(self.g, i)):
131
+ j = self.g.neighbors[i][tmp]
132
+ if j == i:
133
+ self.number_of_loops[i] += 1
134
+ if j > i:
135
+ break
136
+
137
+ # Defining the meaningless set of 'active' vertices. Because of CGraph.
138
+ # As well as num_verts and num_edges
139
+ bitset_init(self.active_vertices, self.g.n + 1)
140
+ bitset_set_first_n(self.active_vertices, self.g.n)
141
+
142
+ self.num_verts = self.g.n
143
+ self.num_arcs = self.g.m
144
+
145
+ def __dealloc__(self):
146
+ r"""
147
+ Free the memory.
148
+
149
+ TESTS::
150
+
151
+ sage: from sage.graphs.base.static_sparse_backend import StaticSparseCGraph
152
+ sage: g = StaticSparseCGraph(graphs.PetersenGraph())
153
+ """
154
+ bitset_free(self.active_vertices)
155
+ free_short_digraph(self.g)
156
+ sig_free(self.number_of_loops)
157
+ if self._directed:
158
+ free_short_digraph(self.g_rev)
159
+
160
+ cpdef bint has_vertex(self, int v) except -1:
161
+ r"""
162
+ Test if a vertex belongs to the graph
163
+
164
+ INPUT:
165
+
166
+ - ``n`` -- integer
167
+
168
+ TESTS::
169
+
170
+ sage: from sage.graphs.base.static_sparse_backend import StaticSparseCGraph
171
+ sage: g = StaticSparseCGraph(graphs.PetersenGraph())
172
+ sage: g.has_vertex(1)
173
+ True
174
+ sage: g.has_vertex(10)
175
+ False
176
+ """
177
+ return 0 <= v and v < self.g.n
178
+
179
+ cdef int add_vertex_unsafe(self, int v) except -1:
180
+ raise ValueError("graph is immutable; please change a copy instead (use function copy())")
181
+
182
+ cdef int del_vertex_unsafe(self, int v) except -1:
183
+ raise ValueError("graph is immutable; please change a copy instead (use function copy())")
184
+
185
+ def add_vertex(self, int k):
186
+ r"""
187
+ Add a vertex to the graph. No way.
188
+
189
+ TESTS::
190
+
191
+ sage: from sage.graphs.base.static_sparse_backend import StaticSparseCGraph
192
+ sage: g = StaticSparseCGraph(graphs.PetersenGraph())
193
+ sage: g.add_vertex(45)
194
+ Traceback (most recent call last):
195
+ ...
196
+ ValueError: graph is immutable; please change a copy instead (use function copy())
197
+ """
198
+ self.add_vertex_unsafe(k)
199
+
200
+ cpdef del_vertex(self, int k):
201
+ r"""
202
+ Remove a vertex from the graph. No way.
203
+
204
+ TESTS::
205
+
206
+ sage: from sage.graphs.base.static_sparse_backend import StaticSparseCGraph
207
+ sage: g = StaticSparseCGraph(graphs.PetersenGraph())
208
+ sage: g.del_vertex(45)
209
+ Traceback (most recent call last):
210
+ ...
211
+ ValueError: graph is immutable; please change a copy instead (use function copy())
212
+ """
213
+ self.del_vertex_unsafe(k)
214
+
215
+ cpdef list verts(self):
216
+ r"""
217
+ Return the list of vertices.
218
+
219
+ TESTS::
220
+
221
+ sage: from sage.graphs.base.static_sparse_backend import StaticSparseCGraph
222
+ sage: g = StaticSparseCGraph(graphs.PetersenGraph())
223
+ sage: g.verts()
224
+ [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
225
+ """
226
+ return list(range(self.g.n))
227
+
228
+ cdef int has_arc_label_unsafe(self, int u, int v, int l) except -1:
229
+ """
230
+ Label is ignored.
231
+ """
232
+ return ((0 <= u) and
233
+ (0 <= v) and
234
+ (u < self.g.n) and
235
+ (v < self.g.n) and
236
+ has_edge(self.g, u, v) != NULL)
237
+
238
+ cpdef bint has_arc(self, int u, int v) except -1:
239
+ r"""
240
+ Test if `uv` is an edge of the graph
241
+
242
+ INPUT:
243
+
244
+ - ``u``, ``v`` -- integers
245
+
246
+ TESTS::
247
+
248
+ sage: from sage.graphs.base.static_sparse_backend import StaticSparseCGraph
249
+ sage: g = StaticSparseCGraph(graphs.PetersenGraph())
250
+ sage: g.has_arc(0, 1)
251
+ True
252
+ sage: g.has_arc(0, 7)
253
+ False
254
+ """
255
+ return self.has_arc_unsafe(u, v)
256
+
257
+ cdef inline int next_out_neighbor_unsafe(self, int u, int v, int* l) except -2:
258
+ """
259
+ Return the next out-neighbor of ``u`` after ``v``.
260
+
261
+ If ``v`` is ``-1`` return the first neighbor of ``u``.
262
+
263
+ Return ``-1`` in case there does not exist such an out-neighbor.
264
+
265
+ .. NOTE::
266
+
267
+ A caller may not alter ``l``.
268
+ It is used to keep track of the current position.
269
+ """
270
+ cdef int degree = out_degree(self.g, u)
271
+ if v == -1:
272
+ l[0] = -1
273
+ for i in range(l[0] + 1, degree):
274
+ if self.g.neighbors[u][i] != v:
275
+ l[0] = i
276
+ return self.g.neighbors[u][i]
277
+ else:
278
+ return -1
279
+
280
+ cdef inline int next_in_neighbor_unsafe(self, int u, int v, int* l) except -2:
281
+ """
282
+ Return the next in-neighbor of ``u`` after ``v``.
283
+
284
+ If ``v`` is ``-1`` return the first neighbor of ``u``.
285
+
286
+ Return ``-1`` in case there does not exist such an in-neighbor.
287
+
288
+ .. NOTE::
289
+
290
+ A caller may not alter ``l``.
291
+ It is used to keep track of the current position.
292
+ """
293
+ if not self._directed:
294
+ return self.next_out_neighbor_unsafe(u, v, l)
295
+ cdef int degree = out_degree(self.g_rev, u)
296
+ if v == -1:
297
+ l[0] = -1
298
+ for i in range(l[0] + 1, degree):
299
+ if self.g_rev.neighbors[u][i] != v:
300
+ l[0] = i
301
+ return self.g_rev.neighbors[u][i]
302
+ else:
303
+ return -1
304
+
305
+ cdef int out_neighbors_unsafe(self, int u, int *neighbors, int size) except -2:
306
+ cdef int degree = self.g.neighbors[u+1] - self.g.neighbors[u]
307
+ cdef int i
308
+ for i in range(min(degree, size)):
309
+ neighbors[i] = self.g.neighbors[u][i]
310
+ return -1 if size < degree else degree
311
+
312
+ cdef int in_neighbors_unsafe(self, int u, int *neighbors, int size) except -2:
313
+ if not self._directed:
314
+ return self.out_neighbors_unsafe(u, neighbors, size)
315
+
316
+ cdef int degree = self.g_rev.neighbors[u+1] - self.g_rev.neighbors[u]
317
+ cdef int i
318
+ for i in range(min(degree, size)):
319
+ neighbors[i] = self.g_rev.neighbors[u][i]
320
+ return -1 if size < degree else degree
321
+
322
+ cpdef list out_neighbors(self, int u):
323
+ r"""
324
+ List the out-neighbors of a vertex.
325
+
326
+ INPUT:
327
+
328
+ - ``u`` -- a vertex
329
+
330
+ TESTS::
331
+
332
+ sage: from sage.graphs.base.static_sparse_backend import StaticSparseCGraph
333
+ sage: g = StaticSparseCGraph(graphs.PetersenGraph())
334
+ sage: g.out_neighbors(0)
335
+ [1, 4, 5]
336
+ sage: g.out_neighbors(10)
337
+ Traceback (most recent call last):
338
+ ...
339
+ LookupError: the vertex does not belong to the graph
340
+ """
341
+ if u < 0 or u >= self.g.n:
342
+ raise LookupError("the vertex does not belong to the graph")
343
+
344
+ cdef int i
345
+ return [<int> self.g.neighbors[u][i] for i in range(out_degree(self.g, u))]
346
+
347
+ cpdef list in_neighbors(self, int u):
348
+ r"""
349
+ Return the in-neighbors of a vertex.
350
+
351
+ INPUT:
352
+
353
+ - ``u`` -- a vertex
354
+
355
+ TESTS::
356
+
357
+ sage: from sage.graphs.base.static_sparse_backend import StaticSparseCGraph
358
+ sage: g = StaticSparseCGraph(graphs.PetersenGraph())
359
+ sage: g.in_neighbors(0)
360
+ [1, 4, 5]
361
+ sage: g.in_neighbors(10)
362
+ Traceback (most recent call last):
363
+ ...
364
+ LookupError: the vertex does not belong to the graph
365
+ """
366
+ if not self._directed:
367
+ return self.out_neighbors(u)
368
+
369
+ if u < 0 or u >= self.g.n:
370
+ raise LookupError("the vertex does not belong to the graph")
371
+
372
+ cdef int i
373
+ return [<int> self.g_rev.neighbors[u][i] for i in range(out_degree(self.g_rev, u))]
374
+
375
+ cpdef int out_degree(self, int u) except -1:
376
+ r"""
377
+ Return the out-degree of a vertex
378
+
379
+ INPUT:
380
+
381
+ - ``u`` -- a vertex
382
+
383
+ TESTS::
384
+
385
+ sage: from sage.graphs.base.static_sparse_backend import StaticSparseCGraph
386
+ sage: g = StaticSparseCGraph(graphs.PetersenGraph())
387
+ sage: g.out_degree(0)
388
+ 3
389
+ sage: g.out_degree(10)
390
+ Traceback (most recent call last):
391
+ ...
392
+ LookupError: the vertex does not belong to the graph
393
+ """
394
+ if u < 0 or u >= self.g.n:
395
+ raise LookupError("the vertex does not belong to the graph")
396
+
397
+ return self.g.neighbors[u+1] - self.g.neighbors[u]
398
+
399
+ cpdef int in_degree(self, int u) except -1:
400
+ r"""
401
+ Return the in-degree of a vertex
402
+
403
+ INPUT:
404
+
405
+ - ``u`` -- a vertex
406
+
407
+ TESTS::
408
+
409
+ sage: from sage.graphs.base.static_sparse_backend import StaticSparseCGraph
410
+ sage: g = StaticSparseCGraph(graphs.PetersenGraph())
411
+ sage: g.in_degree(0)
412
+ 3
413
+ sage: g.in_degree(10)
414
+ Traceback (most recent call last):
415
+ ...
416
+ LookupError: the vertex does not belong to the graph
417
+ """
418
+ if u < 0 or u >= self.g.n:
419
+ raise LookupError("the vertex does not belong to the graph")
420
+
421
+ if not self._directed:
422
+ return self.g.neighbors[u+1] - self.g.neighbors[u]
423
+ else:
424
+ return self.g_rev.neighbors[u+1] - self.g_rev.neighbors[u]
425
+
426
+
427
+ cdef class StaticSparseBackend(CGraphBackend):
428
+
429
+ def __init__(self, G, loops=False, multiedges=False, sort=True):
430
+ """
431
+ A graph :mod:`backend <sage.graphs.base.graph_backends>` for static
432
+ sparse graphs.
433
+
434
+ EXAMPLES::
435
+
436
+ sage: D = sage.graphs.base.sparse_graph.SparseGraphBackend(9)
437
+ sage: D.add_edge(0, 1, None, False)
438
+ sage: list(D.iterator_edges(range(9), True))
439
+ [(0, 1, None)]
440
+
441
+ ::
442
+
443
+ sage: from sage.graphs.base.static_sparse_backend import StaticSparseBackend
444
+ sage: g = StaticSparseBackend(graphs.PetersenGraph())
445
+ sage: list(g.iterator_edges([0], 1))
446
+ [(0, 1, None), (0, 4, None), (0, 5, None)]
447
+
448
+ ::
449
+
450
+ sage: # needs sage.combinat
451
+ sage: g = DiGraph(digraphs.DeBruijn(4, 3), data_structure='static_sparse')
452
+ sage: gi = DiGraph(g, data_structure='static_sparse')
453
+ sage: gi.edges(sort=True)[0]
454
+ ('000', '000', '0')
455
+ sage: sorted(gi.edges_incident('111'))
456
+ [('111', '110', '0'),
457
+ ('111', '111', '1'),
458
+ ('111', '112', '2'),
459
+ ('111', '113', '3')]
460
+
461
+ sage: set(g.edges(sort=False)) == set(gi.edges(sort=False)) # needs sage.combinat
462
+ True
463
+
464
+ ::
465
+
466
+ sage: g = graphs.PetersenGraph()
467
+ sage: gi = Graph(g, data_structure='static_sparse')
468
+ sage: g == gi
469
+ True
470
+ sage: set(g.edges(sort=False)) == set(gi.edges(sort=False))
471
+ True
472
+
473
+ ::
474
+
475
+ sage: gi = Graph({ 0: {1: 1}, 1: {2: 1}, 2: {3: 1}, 3: {4: 2}, 4: {0: 2}}, data_structure='static_sparse')
476
+ sage: (0, 4, 2) in gi.edges(sort=False)
477
+ True
478
+ sage: gi.has_edge(0, 4)
479
+ True
480
+
481
+ ::
482
+
483
+ sage: G = Graph({1:{2:28, 6:10}, 2:{3:16, 7:14}, 3:{4:12}, 4:{5:22, 7:18}, 5:{6:25, 7:24}})
484
+ sage: GI = Graph({1:{2:28, 6:10}, 2:{3:16, 7:14}, 3:{4:12}, 4:{5:22, 7:18}, 5:{6:25, 7:24}}, data_structure='static_sparse')
485
+ sage: G == GI
486
+ True
487
+
488
+ ::
489
+
490
+ sage: G = graphs.OddGraph(4)
491
+ sage: d = G.diameter()
492
+ sage: H = G.distance_graph(list(range(d + 1)))
493
+ sage: HI = Graph(H, data_structure='static_sparse')
494
+ sage: HI.size() == len(HI.edges(sort=False))
495
+ True
496
+
497
+ ::
498
+
499
+ sage: g = Graph({1: {1: [1, 2, 3]}}, data_structure='static_sparse')
500
+ sage: g.size()
501
+ 3
502
+ sage: g.order()
503
+ 1
504
+ sage: g.vertices(sort=False)
505
+ [1]
506
+ sage: g.edges(sort=True)
507
+ [(1, 1, 1), (1, 1, 2), (1, 1, 3)]
508
+
509
+ :issue:`15810` is fixed::
510
+
511
+ sage: DiGraph({1: {2: ['a', 'b'], 3: ['c']}, 2: {3: ['d']}}, immutable=True).is_directed_acyclic()
512
+ True
513
+ """
514
+ vertices = list(G)
515
+ if sort:
516
+ try:
517
+ vertices.sort()
518
+ except TypeError:
519
+ pass
520
+ cdef StaticSparseCGraph cg = <StaticSparseCGraph> StaticSparseCGraph(G, vertices)
521
+ self._cg = cg
522
+
523
+ self._directed = cg._directed
524
+
525
+ self._order = G.order()
526
+
527
+ # Does it allow loops/multiedges ?
528
+ self._loops = loops
529
+ self._multiedges = multiedges
530
+
531
+ # Dictionary translating a vertex int to a label, and the other way around.
532
+ self._vertex_to_labels = vertices
533
+ self._vertex_to_int = {v: i for i, v in enumerate(vertices)}
534
+
535
+ # Needed by CGraph. The first one is just an alias, and the second is
536
+ # useless : accessing _vertex_to_labels (which is a list) is faster than
537
+ # vertex_labels (which is a dictionary)
538
+ self.vertex_ints = self._vertex_to_int
539
+ self.vertex_labels = {i: v for i, v in enumerate(vertices)}
540
+ self._multiple_edges = self._multiedges
541
+
542
+ def has_vertex(self, v):
543
+ r"""
544
+ Test if the vertex belongs to the graph.
545
+
546
+ INPUT:
547
+
548
+ - ``v`` -- a vertex (or not?)
549
+
550
+ TESTS::
551
+
552
+ sage: from sage.graphs.base.static_sparse_backend import StaticSparseBackend
553
+ sage: g = StaticSparseBackend(graphs.PetersenGraph())
554
+ sage: g.has_vertex(0)
555
+ True
556
+ sage: g.has_vertex("Hey")
557
+ False
558
+ """
559
+ return v in self._vertex_to_int
560
+
561
+ def add_vertex(self, object v):
562
+ r"""
563
+ Add a vertex to the graph. No way
564
+
565
+ INPUT:
566
+
567
+ - ``v`` -- a vertex (or not?)
568
+
569
+ TESTS::
570
+
571
+ sage: from sage.graphs.base.static_sparse_backend import StaticSparseBackend
572
+ sage: g = StaticSparseBackend(graphs.PetersenGraph())
573
+ sage: g.add_vertex(123)
574
+ Traceback (most recent call last):
575
+ ...
576
+ ValueError: graph is immutable; please change a copy instead (use function copy())
577
+ """
578
+ raise ValueError("graph is immutable; please change a copy instead (use function copy())")
579
+
580
+ cpdef add_edge(self, object u, object v, object l, bint directed):
581
+ r"""
582
+ Add an edge to the graph. No way.
583
+
584
+ TESTS::
585
+
586
+ sage: from sage.graphs.base.static_sparse_backend import StaticSparseBackend
587
+ sage: g = StaticSparseBackend(graphs.PetersenGraph())
588
+ sage: g.add_edge(1,2,3,True)
589
+ Traceback (most recent call last):
590
+ ...
591
+ ValueError: graph is immutable; please change a copy instead (use function copy())
592
+ """
593
+ raise ValueError("graph is immutable; please change a copy instead (use function copy())")
594
+
595
+ def add_edges(self, edges, directed, remove_loops=False):
596
+ r"""
597
+ Add edges to the graph. No way.
598
+
599
+ INPUT:
600
+
601
+ - ``edges`` -- a list of edges (or not?)
602
+
603
+ TESTS::
604
+
605
+ sage: from sage.graphs.base.static_sparse_backend import StaticSparseBackend
606
+ sage: g = StaticSparseBackend(graphs.PetersenGraph())
607
+ sage: g.add_edges([[1, 2]], True)
608
+ Traceback (most recent call last):
609
+ ...
610
+ ValueError: graph is immutable; please change a copy instead (use function copy())
611
+ """
612
+ raise ValueError("graph is immutable; please change a copy instead (use function copy())")
613
+
614
+ def add_vertices(self, vertices):
615
+ r"""
616
+ Add vertices to the graph. No way.
617
+
618
+ INPUT:
619
+
620
+ - ``vertices`` -- a list of vertices (or not?)
621
+
622
+ TESTS::
623
+
624
+ sage: from sage.graphs.base.static_sparse_backend import StaticSparseBackend
625
+ sage: g = StaticSparseBackend(graphs.PetersenGraph())
626
+ sage: g.add_vertices([1, 2])
627
+ Traceback (most recent call last):
628
+ ...
629
+ ValueError: graph is immutable; please change a copy instead (use function copy())
630
+ """
631
+ raise ValueError("graph is immutable; please change a copy instead (use function copy())")
632
+
633
+ def del_vertex(self, object v):
634
+ r"""
635
+ Delete a vertex from the graph. No way
636
+
637
+ INPUT:
638
+
639
+ - ``v`` -- a vertex (or not?)
640
+
641
+ TESTS::
642
+
643
+ sage: from sage.graphs.base.static_sparse_backend import StaticSparseBackend
644
+ sage: g = StaticSparseBackend(graphs.PetersenGraph())
645
+ sage: g.del_vertex(123)
646
+ Traceback (most recent call last):
647
+ ...
648
+ ValueError: graph is immutable; please change a copy instead (use function copy())
649
+
650
+ Check that :issue:`39270` is fixed::
651
+
652
+ sage: g.del_vertex('a')
653
+ Traceback (most recent call last):
654
+ ...
655
+ ValueError: graph is immutable; please change a copy instead (use function copy())
656
+ """
657
+ raise ValueError("graph is immutable; please change a copy instead (use function copy())")
658
+
659
+ def del_vertices(self, vertices):
660
+ r"""
661
+ Delete vertices from the graph. No way
662
+
663
+ INPUT:
664
+
665
+ - ``vertices`` -- a list of vertices (or not?)
666
+
667
+ TESTS::
668
+
669
+ sage: from sage.graphs.base.static_sparse_backend import StaticSparseBackend
670
+ sage: g = StaticSparseBackend(graphs.PetersenGraph())
671
+ sage: g.del_vertices([123, 234])
672
+ Traceback (most recent call last):
673
+ ...
674
+ ValueError: graph is immutable; please change a copy instead (use function copy())
675
+ """
676
+ raise ValueError("graph is immutable; please change a copy instead (use function copy())")
677
+
678
+ cpdef del_edge(self, object u, object v, object l, bint directed):
679
+ r"""
680
+ Delete an edge of the graph. No way.
681
+
682
+ TESTS::
683
+
684
+ sage: from sage.graphs.base.static_sparse_backend import StaticSparseBackend
685
+ sage: g = StaticSparseBackend(graphs.PetersenGraph())
686
+ sage: g.del_edge(1,2,3,True)
687
+ Traceback (most recent call last):
688
+ ...
689
+ ValueError: graph is immutable; please change a copy instead (use function copy())
690
+ """
691
+ raise ValueError("graph is immutable; please change a copy instead (use function copy())")
692
+
693
+ def del_edges(self, edges, directed):
694
+ r"""
695
+ Delete edges of the graph. No way.
696
+
697
+ TESTS::
698
+
699
+ sage: from sage.graphs.base.static_sparse_backend import StaticSparseBackend
700
+ sage: g = StaticSparseBackend(graphs.PetersenGraph())
701
+ sage: g.del_edges([[1,2,3]], True)
702
+ Traceback (most recent call last):
703
+ ...
704
+ ValueError: graph is immutable; please change a copy instead (use function copy())
705
+ """
706
+ raise ValueError("graph is immutable; please change a copy instead (use function copy())")
707
+
708
+ def set_edge_label(self, u, v, l, directed):
709
+ r"""
710
+ Set edge label. No way.
711
+
712
+ TESTS::
713
+
714
+ sage: from sage.graphs.base.static_sparse_backend import StaticSparseBackend
715
+ sage: g = StaticSparseBackend(graphs.PetersenGraph())
716
+ sage: g.set_edge_label(1,2,3,True)
717
+ Traceback (most recent call last):
718
+ ...
719
+ ValueError: graph is immutable; please change a copy instead (use function copy())
720
+ """
721
+ raise ValueError("graph is immutable; please change a copy instead (use function copy())")
722
+
723
+ def relabel(self, perm, directed):
724
+ r"""
725
+ Relabel the graphs' vertices. No way.
726
+
727
+ TESTS::
728
+
729
+ sage: from sage.graphs.base.static_sparse_backend import StaticSparseBackend
730
+ sage: g = StaticSparseBackend(graphs.PetersenGraph())
731
+ sage: g.relabel([],True)
732
+ Traceback (most recent call last):
733
+ ...
734
+ ValueError: graph is immutable; please change a copy instead (use function copy())
735
+ """
736
+ raise ValueError("graph is immutable; please change a copy instead (use function copy())")
737
+
738
+ def get_edge_label(self, object u, object v):
739
+ """
740
+ Return the edge label for ``(u, v)``.
741
+
742
+ INPUT:
743
+
744
+ - ``u``, ``v`` -- two vertices
745
+
746
+ TESTS::
747
+
748
+ sage: from sage.graphs.base.static_sparse_backend import StaticSparseBackend
749
+ sage: g = StaticSparseBackend(graphs.PetersenGraph())
750
+ sage: print(g.get_edge_label(0, 1))
751
+ None
752
+ sage: print(g.get_edge_label(0, "Hey"))
753
+ Traceback (most recent call last):
754
+ ...
755
+ LookupError: one of the two vertices does not belong to the graph
756
+ sage: print(g.get_edge_label(0, 7))
757
+ Traceback (most recent call last):
758
+ ...
759
+ LookupError: the edge does not exist
760
+
761
+ ::
762
+
763
+ sage: from sage.graphs.base.static_sparse_backend import StaticSparseBackend
764
+ sage: g = StaticSparseBackend(digraphs.DeBruijn(3, 2)) # needs sage.combinat
765
+ sage: g.has_edge('00', '01', '1') # needs sage.combinat
766
+ True
767
+ sage: g.has_edge('00', '01', '0') # needs sage.combinat
768
+ False
769
+ """
770
+ try:
771
+ u = self._vertex_to_int[u]
772
+ v = self._vertex_to_int[v]
773
+ except KeyError:
774
+ raise LookupError("one of the two vertices does not belong to the graph")
775
+
776
+ cdef StaticSparseCGraph cg = self._cg
777
+
778
+ cdef uint32_t * edge = has_edge(cg.g, u, v)
779
+ if not edge:
780
+ raise LookupError("the edge does not exist")
781
+
782
+ # At this level, edge points toward a edge from u to v in the graph, but
783
+ # not necessarily to the leftmost edge. Hence, we first decrease edge to
784
+ # make it point toward the leftmost such edge, then build the list of
785
+ # all labels.
786
+ if self.multiple_edges(None):
787
+ return self._all_edge_labels(u, v, edge)
788
+ return edge_label(cg.g, edge)
789
+
790
+ cdef inline list _all_edge_labels(self, int u, int v, uint32_t* edge=NULL):
791
+ """
792
+ Give the labels of all arcs from ``u`` to ``v``.
793
+
794
+ ``u`` and ``v`` are the integers corresponding to vertices.
795
+
796
+ ``edge`` may point to an edge from ``u`` to ``v``.
797
+ """
798
+ cdef StaticSparseCGraph cg = self._cg
799
+ if edge is NULL:
800
+ edge = has_edge(cg.g, u, v)
801
+
802
+ while edge > cg.g.neighbors[u] and (edge - 1)[0] == v:
803
+ edge -= 1
804
+ cdef list l = []
805
+ while edge < cg.g.neighbors[u+1] and edge[0] == v:
806
+ l.append(edge_label(cg.g, edge))
807
+ edge += 1
808
+ return l
809
+
810
+ def has_edge(self, object u, object v, object l):
811
+ """
812
+ Return whether this graph has edge ``(u, v)`` with label ``l``.
813
+
814
+ If ``l`` is ``None``, return whether this graph has an edge ``(u, v)``
815
+ with any label.
816
+
817
+ INPUT:
818
+
819
+ - ``u``, ``v`` -- two vertices
820
+
821
+ - ``l`` -- a label
822
+
823
+ TESTS::
824
+
825
+ sage: from sage.graphs.base.static_sparse_backend import StaticSparseBackend
826
+ sage: g = StaticSparseBackend(graphs.PetersenGraph())
827
+ sage: g.has_edge(0, 1, 'e')
828
+ False
829
+ sage: g.has_edge(0, 4, None)
830
+ True
831
+ """
832
+ try:
833
+ u = self._vertex_to_int[u]
834
+ v = self._vertex_to_int[v]
835
+ except KeyError:
836
+ raise LookupError("one of the two vertices does not belong to the graph")
837
+
838
+ return self._has_labeled_edge_unsafe(u, v, l)
839
+
840
+ cdef inline bint _has_labeled_edge_unsafe(self, int u, int v, object l) except -1:
841
+ """
842
+ Return whether ``self`` has an arc specified by indices of the vertices
843
+ and an arc label.
844
+ """
845
+ cdef uint32_t * edge = NULL
846
+ cdef StaticSparseCGraph cg = <StaticSparseCGraph> (self._cg)
847
+ edge = has_edge(cg.g, u, v)
848
+ if not edge:
849
+ return False
850
+ if l is None:
851
+ return True
852
+
853
+ # At this level, edge points toward a edge from u to v in the graph, but
854
+ # not necessarily toward the right label. As there may be many uv edges
855
+ # with different labels, we first make edge point toward the leftmost uv
856
+ # edge, then scan them all to find the right label.
857
+ while edge > cg.g.neighbors[u] and (edge - 1)[0] == v:
858
+ edge -= 1
859
+
860
+ while edge[0] == v and edge < cg.g.neighbors[u+1]:
861
+ if edge_label(cg.g, edge) == l:
862
+ return True
863
+ edge += 1
864
+
865
+ return False
866
+
867
+ def iterator_in_edges(self, object vertices, bint labels):
868
+ """
869
+ Iterate over the incoming edges incident to a sequence of vertices.
870
+
871
+ INPUT:
872
+
873
+ - ``vertices`` -- list of vertices
874
+
875
+ - ``labels`` -- whether to return labels too
876
+
877
+ TESTS::
878
+
879
+ sage: from sage.graphs.base.static_sparse_backend import StaticSparseBackend
880
+ sage: g = StaticSparseBackend(graphs.PetersenGraph())
881
+ sage: list(g.iterator_in_edges([0], False))
882
+ [(0, 1), (0, 4), (0, 5)]
883
+ sage: list(g.iterator_in_edges([0], True))
884
+ [(0, 1, None), (0, 4, None), (0, 5, None)]
885
+
886
+ ::
887
+
888
+ sage: DiGraph(digraphs.Path(5), immutable=False).incoming_edges([2])
889
+ [(1, 2, None)]
890
+ sage: DiGraph(digraphs.Path(5), immutable=True).incoming_edges([2])
891
+ [(1, 2, None)]
892
+ """
893
+ cdef StaticSparseCGraph cg = self._cg
894
+ if not cg._directed:
895
+ for x in self.iterator_out_edges(vertices, labels):
896
+ yield x
897
+ return
898
+
899
+ try:
900
+ vertices = [self._vertex_to_int[x] for x in vertices]
901
+ except KeyError:
902
+ raise LookupError("one of the vertices does not belong to the graph")
903
+
904
+ cdef int i, j
905
+ for i in vertices:
906
+ vi = self._vertex_to_labels[i]
907
+ for j in range(out_degree(cg.g_rev, i)):
908
+ if labels:
909
+ yield (self._vertex_to_labels[cg.g_rev.neighbors[i][j]],
910
+ vi,
911
+ edge_label(cg.g_rev, cg.g_rev.neighbors[i] + j))
912
+ else:
913
+ yield self._vertex_to_labels[cg.g_rev.neighbors[i][j]], vi
914
+
915
+ def iterator_out_edges(self, object vertices, bint labels):
916
+ """
917
+ Iterate over the outbound edges incident to a sequence of vertices.
918
+
919
+ INPUT:
920
+
921
+ - ``vertices`` -- list of vertices
922
+
923
+ - ``labels`` -- whether to return labels too
924
+
925
+ TESTS::
926
+
927
+ sage: from sage.graphs.base.static_sparse_backend import StaticSparseBackend
928
+ sage: g = StaticSparseBackend(graphs.PetersenGraph())
929
+ sage: list(g.iterator_out_edges([0], False))
930
+ [(0, 1), (0, 4), (0, 5)]
931
+ sage: list(g.iterator_out_edges([0], True))
932
+ [(0, 1, None), (0, 4, None), (0, 5, None)]
933
+ """
934
+ try:
935
+ vertices = [self._vertex_to_int[x] for x in vertices]
936
+ except KeyError:
937
+ raise LookupError("one of the vertices does not belong to the graph")
938
+
939
+ cdef StaticSparseCGraph cg = self._cg
940
+ cdef int i, j
941
+ for i in vertices:
942
+ vi = self._vertex_to_labels[i]
943
+ for j in range(out_degree(cg.g, i)):
944
+ if labels:
945
+ yield (vi,
946
+ self._vertex_to_labels[cg.g.neighbors[i][j]],
947
+ edge_label(cg.g, cg.g.neighbors[i] + j))
948
+ else:
949
+ yield vi, self._vertex_to_labels[cg.g.neighbors[i][j]]
950
+
951
+ def iterator_verts(self, vertices):
952
+ r"""
953
+ Iterate over the vertices.
954
+
955
+ INPUT:
956
+
957
+ - ``vertices`` -- list of objects; the method will only return the
958
+ elements of the graph which are contained in ``vertices``. It's not
959
+ very efficient. If ``vertices`` is equal to ``None``, all the vertices
960
+ are returned.
961
+
962
+ TESTS::
963
+
964
+ sage: from sage.graphs.base.static_sparse_backend import StaticSparseBackend
965
+ sage: g = StaticSparseBackend(graphs.PetersenGraph())
966
+ sage: list(g.iterator_verts(None))
967
+ [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
968
+ sage: list(g.iterator_verts([1, "Hey", "I am a french fry"]))
969
+ [1]
970
+ """
971
+ if vertices is None:
972
+ for x in self._vertex_to_labels:
973
+ yield x
974
+ return
975
+
976
+ cdef set V = set(vertices)
977
+ for x in self._vertex_to_labels:
978
+ if x in V:
979
+ yield x
980
+ return
981
+
982
+ def num_verts(self):
983
+ r"""
984
+ Return the number of vertices.
985
+
986
+ TESTS::
987
+
988
+ sage: from sage.graphs.base.static_sparse_backend import StaticSparseBackend
989
+ sage: g = StaticSparseBackend(graphs.PetersenGraph())
990
+ sage: g.num_verts()
991
+ 10
992
+ """
993
+ return self._order
994
+
995
+ def allows_loops(self, value=None):
996
+ r"""
997
+ Return whether the graph allows loops.
998
+
999
+ INPUT:
1000
+
1001
+ - ``value`` -- only useful for compatibility with other graph backends,
1002
+ where this method can be used to define this boolean. This method
1003
+ raises an exception if ``value`` is not equal to ``None``.
1004
+
1005
+ TESTS::
1006
+
1007
+ sage: from sage.graphs.base.static_sparse_backend import StaticSparseBackend
1008
+ sage: g = StaticSparseBackend(graphs.PetersenGraph())
1009
+ sage: g.allows_loops()
1010
+ False
1011
+ sage: g = StaticSparseBackend(graphs.PetersenGraph(), loops=True)
1012
+ sage: g.allows_loops()
1013
+ True
1014
+ """
1015
+ if value is None:
1016
+ return self._loops
1017
+ else:
1018
+ raise ValueError("the graph is immutable and cannot be changed in any way")
1019
+
1020
+ def multiple_edges(self, value=None):
1021
+ r"""
1022
+ Return whether the graph allows multiple edges.
1023
+
1024
+ INPUT:
1025
+
1026
+ - ``value`` -- only useful for compatibility with other graph backends,
1027
+ where this method can be used to define this boolean. This method
1028
+ raises an exception if ``value`` is not equal to ``None``.
1029
+
1030
+ TESTS::
1031
+
1032
+ sage: from sage.graphs.base.static_sparse_backend import StaticSparseBackend
1033
+ sage: g = StaticSparseBackend(graphs.PetersenGraph())
1034
+ sage: g.multiple_edges()
1035
+ False
1036
+ sage: g = StaticSparseBackend(graphs.PetersenGraph(), multiedges=True)
1037
+ sage: g.multiple_edges()
1038
+ True
1039
+ """
1040
+ if value is None:
1041
+ return self._multiedges
1042
+ else:
1043
+ raise ValueError("the graph is immutable and cannot be changed in any way")
1044
+
1045
+ def num_edges(self, directed):
1046
+ r"""
1047
+ Return the number of edges.
1048
+
1049
+ INPUT:
1050
+
1051
+ - ``directed`` -- boolean; whether to consider the graph as directed or
1052
+ not
1053
+
1054
+ TESTS::
1055
+
1056
+ sage: from sage.graphs.base.static_sparse_backend import StaticSparseBackend
1057
+ sage: g = StaticSparseBackend(graphs.PetersenGraph())
1058
+ sage: g.num_edges(False)
1059
+ 15
1060
+
1061
+ Testing the exception::
1062
+
1063
+ sage: g = StaticSparseBackend(digraphs.Circuit(4))
1064
+ sage: g.num_edges(False)
1065
+ Traceback (most recent call last):
1066
+ ...
1067
+ NotImplementedError: Sorry, I have no idea what is expected in this situation. I don't think that it is well-defined either, especially for multigraphs.
1068
+
1069
+ :issue:`15491`::
1070
+
1071
+ sage: g = digraphs.RandomDirectedGNP(10, .3)
1072
+ sage: gi = DiGraph(g, data_structure='static_sparse')
1073
+ sage: gi.size() == len(gi.edges(sort=False))
1074
+ True
1075
+ """
1076
+ cdef StaticSparseCGraph cg = <StaticSparseCGraph> self._cg
1077
+
1078
+ if directed:
1079
+ if cg._directed:
1080
+ # Returns the real number of directed arcs
1081
+ return int(cg.g.m)
1082
+ else:
1083
+ # Returns twice the number of edges, minus the number of
1084
+ # loops. This is actually equal to the index of
1085
+ # cg.g.neighbors[cg.g.n] in the array `cg.g.edges`
1086
+ return int(cg.g.neighbors[cg.g.n] - cg.g.edges)
1087
+ else:
1088
+ if cg._directed:
1089
+ raise NotImplementedError("Sorry, I have no idea what is expected "
1090
+ "in this situation. I don't think "
1091
+ "that it is well-defined either, "
1092
+ "especially for multigraphs.")
1093
+ else:
1094
+ # Returns the number of edges
1095
+ return int(cg.g.m)
1096
+
1097
+ def iterator_edges(self, vertices, bint labels):
1098
+ r"""
1099
+ Iterate over the graph's edges.
1100
+
1101
+ INPUT:
1102
+
1103
+ - ``vertices`` -- list; only returns the edges incident to at least one
1104
+ vertex of ``vertices``
1105
+
1106
+ - ``labels`` -- boolean; whether to return edge labels too
1107
+
1108
+ TESTS::
1109
+
1110
+ sage: from sage.graphs.base.static_sparse_backend import StaticSparseBackend
1111
+ sage: g = StaticSparseBackend(graphs.PetersenGraph())
1112
+ sage: list(g.iterator_edges(g.iterator_verts(None), False))
1113
+ [(0, 1), (0, 4), (0, 5), (1, 2), (1, 6), (2, 3), (2, 7),
1114
+ (3, 4), (3, 8), (4, 9), (5, 7), (5, 8), (6, 8), (6, 9), (7, 9)]
1115
+
1116
+ :issue:`15665`::
1117
+
1118
+ sage: Graph(immutable=True).edges(sort=False)
1119
+ []
1120
+ """
1121
+ cdef FrozenBitset b_vertices
1122
+
1123
+ if not vertices:
1124
+ return
1125
+
1126
+ if self._directed:
1127
+ raise RuntimeError("this is not meant for directed graphs")
1128
+
1129
+ try:
1130
+ vertices = [self._vertex_to_int[x] for x in vertices]
1131
+ b_vertices = FrozenBitset(vertices)
1132
+ except KeyError:
1133
+ raise LookupError("one of the vertices does not belong to the graph")
1134
+
1135
+ cdef StaticSparseCGraph cg = self._cg
1136
+ cdef int i, j, tmp
1137
+
1138
+ for i in vertices:
1139
+ vi = self._vertex_to_labels[i]
1140
+ for tmp in range(out_degree(cg.g, i)):
1141
+ j = cg.g.neighbors[i][tmp]
1142
+ if j < i and j in b_vertices:
1143
+ continue
1144
+ if labels:
1145
+ yield (vi,
1146
+ self._vertex_to_labels[j],
1147
+ edge_label(cg.g, cg.g.neighbors[i] + tmp))
1148
+ else:
1149
+ yield vi, self._vertex_to_labels[j]
1150
+
1151
+ iterator_unsorted_edges = iterator_edges
1152
+
1153
+ cdef int _use_edge_iterator_on_subgraph(self, CGraphBackend other, object vertices, const int modus) except -1:
1154
+ """
1155
+ Use an edge iterator on the subgraph induced by ``vertices`` and do something according to ``modus``.
1156
+
1157
+ INPUT:
1158
+
1159
+ - ``other`` -- a (mutable) subclass of :class:`CGraphBackend`
1160
+ - ``vertices`` -- list of vertex labels
1161
+ - ``modus`` -- integer representing the modus:
1162
+ - ``0`` -- initialize ``other`` to be the subgraph induced by the vertices;
1163
+ see :meth:`subgraph_given_vertices`
1164
+ - ``1`` -- test whether subgraph of ``self`` induced by the vertices is a subgraph of ``other``
1165
+ - ``2`` -- as ``1`` but ignore the labels
1166
+ """
1167
+ cdef object v, l
1168
+ cdef int u_int, prev_u_int, v_int, l_int_other, tmp
1169
+ cdef StaticSparseCGraph cg = self._cg
1170
+ cdef CGraph cg_other = other.cg()
1171
+ cdef list b_vertices_2
1172
+ cdef FrozenBitset b_vertices
1173
+ cdef int n_vertices = len(vertices)
1174
+ cdef bint loops = other.loops()
1175
+ cdef bint ignore_multiple_edges = modus == 0 and self.multiple_edges(None) and not other.multiple_edges(None)
1176
+
1177
+ if self._directed and not other._directed and modus == 0:
1178
+ raise ValueError("cannot obtain an undirected subgraph of a directed graph")
1179
+
1180
+ if self._directed != other._directed and 1 <= modus <= 2:
1181
+ if self._directed:
1182
+ raise ValueError("cannot check if directed graph is a subgraph of an undirected")
1183
+ else:
1184
+ raise ValueError("cannot check if undirected graph is a subgraph of a directed")
1185
+
1186
+ try:
1187
+ b_vertices_2 = [self._vertex_to_int[x] for x in vertices]
1188
+ b_vertices = FrozenBitset(b_vertices_2)
1189
+ except KeyError:
1190
+ raise LookupError("one of the vertices does not belong to the graph")
1191
+ except ValueError:
1192
+ # Avoiding "Bitset must not be empty"
1193
+ # in this case there is nothing to do
1194
+ return 1
1195
+
1196
+ cdef int length = len(b_vertices)
1197
+ cdef int i
1198
+ cdef int* vertices_translation = <int *> sig_malloc(b_vertices.capacity() * sizeof(int))
1199
+
1200
+ try:
1201
+ # Iterate through the vertices.
1202
+ if cg_other.active_vertices.size < length:
1203
+ cg_other.realloc(length)
1204
+ for j in range(n_vertices):
1205
+ i = b_vertices_2[j]
1206
+ if i >= 0:
1207
+ v = self.vertex_label(i)
1208
+ if modus == 0:
1209
+ # Add the vertex and obtain the corresponding index.
1210
+ vertices_translation[i] = other.check_labelled_vertex(v, False)
1211
+ elif 1 <= modus <= 2:
1212
+ # Obtain the corresponding index if the vertex is contained in ``other``.
1213
+ foo = other.get_vertex_checked(v)
1214
+ if foo >= 0:
1215
+ vertices_translation[i] = foo
1216
+ else:
1217
+ # Not a subgraph.
1218
+ return 0
1219
+
1220
+ # Iterate through the edges.
1221
+ for v_int in b_vertices:
1222
+ prev_u_int = -1
1223
+ for tmp in range(out_degree(cg.g, v_int)):
1224
+ u_int = cg.g.neighbors[v_int][tmp]
1225
+ if (u_int < b_vertices.capacity() and bitset_in(b_vertices._bitset, u_int)
1226
+ and (u_int >= v_int or other._directed)):
1227
+
1228
+ if unlikely(ignore_multiple_edges and u_int == prev_u_int):
1229
+ # Delete multiple edges, if ``other`` does not allow them.
1230
+ continue
1231
+
1232
+ if modus == 0:
1233
+ prev_u_int = u_int
1234
+
1235
+ if unlikely(not loops and u_int == v_int):
1236
+ # Ignore loops, if ``other`` does not allow them.
1237
+ continue
1238
+
1239
+ l = edge_label(cg.g, cg.g.neighbors[v_int] + tmp)
1240
+
1241
+ # Will return ``0``, if ``other`` does not support edge labels.
1242
+ l_int_other = other.new_edge_label(l)
1243
+
1244
+ cg_other.add_arc_label_unsafe(vertices_translation[v_int], vertices_translation[u_int], l_int_other)
1245
+
1246
+ else:
1247
+ # Modus is 1 or 2.
1248
+
1249
+ # Check if the arc is contained in ``other``.
1250
+
1251
+ if unlikely(u_int == prev_u_int):
1252
+ # Check if all of the multiple edges are contained.
1253
+ if not other.multiple_edges(None):
1254
+ # ``other`` does not allow multiple edges.
1255
+ # As ``self`` has a multiple edges (not only allows), it cannot be a subgraph.
1256
+ return 0
1257
+
1258
+ all_arc_labels = self._all_edge_labels(v_int, u_int)
1259
+ all_arc_labels_other = other._all_edge_labels(vertices_translation[v_int], vertices_translation[u_int])
1260
+ if modus == 2:
1261
+ # Ignore the labels.
1262
+ if len(all_arc_labels) > len(all_arc_labels_other):
1263
+ return 0
1264
+ else:
1265
+ for l in all_arc_labels:
1266
+ try:
1267
+ all_arc_labels_other.remove(l)
1268
+ except ValueError:
1269
+ return 0
1270
+
1271
+ continue
1272
+ prev_u_int = u_int
1273
+
1274
+ l = edge_label(cg.g, cg.g.neighbors[v_int] + tmp)
1275
+
1276
+ if modus == 1:
1277
+ if not other._has_labeled_edge_unsafe(vertices_translation[v_int], vertices_translation[u_int], l):
1278
+ return 0
1279
+ else:
1280
+ # Ignore the label.
1281
+ if not cg_other.has_arc_unsafe(vertices_translation[v_int], vertices_translation[u_int]):
1282
+ return 0
1283
+
1284
+ finally:
1285
+ sig_free(vertices_translation)
1286
+
1287
+ return 1
1288
+
1289
+ def degree(self, v, directed):
1290
+ r"""
1291
+ Return the degree of a vertex.
1292
+
1293
+ INPUT:
1294
+
1295
+ - ``v`` -- a vertex
1296
+
1297
+ - ``directed`` -- boolean; whether to take into account the orientation
1298
+ of this graph in counting the degree of ``v``
1299
+
1300
+ EXAMPLES::
1301
+
1302
+ sage: g = Graph(graphs.PetersenGraph(), data_structure='static_sparse')
1303
+ sage: g.degree(0)
1304
+ 3
1305
+
1306
+ :issue:`17225` about the degree of a vertex with a loop::
1307
+
1308
+ sage: Graph({0: [0]}, immutable=True).degree(0)
1309
+ 2
1310
+ sage: Graph({0: [0], 1: [0, 1, 1, 1]}, immutable=True).degree(1)
1311
+ 7
1312
+ """
1313
+ try:
1314
+ v = self._vertex_to_int[v]
1315
+ except KeyError:
1316
+ raise LookupError("the vertex does not belong to the graph")
1317
+
1318
+ cdef StaticSparseCGraph cg = self._cg
1319
+
1320
+ if directed:
1321
+ if cg._directed:
1322
+ return cg.in_degree(v) + cg.out_degree(v)
1323
+ else:
1324
+ return 2 * cg.out_degree(v)
1325
+ else:
1326
+ if cg._directed:
1327
+ raise NotImplementedError("Sorry, I have no idea what is expected "
1328
+ "in this situation. I don't think "
1329
+ "that it is well-defined either, "
1330
+ "especially for multigraphs.")
1331
+ else:
1332
+ return cg.out_degree(v) + (0 if not cg.number_of_loops else cg.number_of_loops[v])
1333
+
1334
+ def in_degree(self, v):
1335
+ r"""
1336
+ Return the in-degree of a vertex.
1337
+
1338
+ INPUT:
1339
+
1340
+ - ``v`` -- a vertex
1341
+
1342
+ EXAMPLES::
1343
+
1344
+ sage: g = DiGraph(graphs.PetersenGraph(), data_structure='static_sparse')
1345
+ sage: g.in_degree(0)
1346
+ 3
1347
+ """
1348
+ try:
1349
+ v = self._vertex_to_int[v]
1350
+ except KeyError:
1351
+ raise LookupError("the vertex does not belong to the graph")
1352
+
1353
+ cdef StaticSparseCGraph cg = self._cg
1354
+
1355
+ if cg._directed:
1356
+ return cg.in_degree(v)
1357
+ else:
1358
+ return cg.out_degree(v)
1359
+
1360
+ def out_degree(self, v):
1361
+ r"""
1362
+ Return the out-degree of a vertex.
1363
+
1364
+ INPUT:
1365
+
1366
+ - ``v`` -- a vertex
1367
+
1368
+ EXAMPLES::
1369
+
1370
+ sage: g = DiGraph(graphs.PetersenGraph(), data_structure='static_sparse')
1371
+ sage: g.out_degree(0)
1372
+ 3
1373
+ """
1374
+ try:
1375
+ v = self._vertex_to_int[v]
1376
+ except KeyError:
1377
+ raise LookupError("the vertex does not belong to the graph")
1378
+
1379
+ cdef StaticSparseCGraph cg = self._cg
1380
+
1381
+ return cg.out_degree(v)
1382
+
1383
+ def iterator_nbrs(self, v):
1384
+ r"""
1385
+ Iterate over the neighbors of a vertex.
1386
+
1387
+ INPUT:
1388
+
1389
+ - ``v`` -- a vertex
1390
+
1391
+ EXAMPLES::
1392
+
1393
+ sage: g = Graph(graphs.PetersenGraph(), data_structure='static_sparse')
1394
+ sage: g.neighbors(0)
1395
+ [1, 4, 5]
1396
+
1397
+ TESTS:
1398
+
1399
+ Issue :issue:`25550` is fixed::
1400
+
1401
+ sage: g = DiGraph({0: [1]}, immutable=True)
1402
+ sage: g.neighbors(1)
1403
+ [0]
1404
+ sage: g = DiGraph({0: [0, 1, 1]}, loops=True, multiedges=True, immutable=True)
1405
+ sage: g.neighbors(0)
1406
+ [0, 1]
1407
+ sage: g = DiGraph({0: [1, 1], 1:[0, 0]}, multiedges=True, immutable=True)
1408
+ sage: g.neighbors(0)
1409
+ [1]
1410
+ sage: g.neighbors(1)
1411
+ [0]
1412
+ """
1413
+ try:
1414
+ v = self._vertex_to_int[v]
1415
+ except KeyError:
1416
+ raise LookupError("the vertex does not belong to the graph")
1417
+
1418
+ cdef StaticSparseCGraph cg = self._cg
1419
+ cdef int i, u
1420
+ cdef set seen = set()
1421
+
1422
+ if cg._directed:
1423
+ for i in range(out_degree(cg.g, v)):
1424
+ u = cg.g.neighbors[v][i]
1425
+ if u not in seen:
1426
+ yield self._vertex_to_labels[u]
1427
+ seen.add(u)
1428
+ for i in range(out_degree(cg.g_rev, v)):
1429
+ u = cg.g_rev.neighbors[v][i]
1430
+ if u not in seen:
1431
+ yield self._vertex_to_labels[u]
1432
+ seen.add(u)
1433
+ else:
1434
+ for i in range(out_degree(cg.g, v)):
1435
+ u = cg.g.neighbors[v][i]
1436
+ if u not in seen:
1437
+ yield self._vertex_to_labels[cg.g.neighbors[v][i]]
1438
+ seen.add(u)
1439
+
1440
+ def iterator_out_nbrs(self, v):
1441
+ r"""
1442
+ Iterate over the out-neighbors of a vertex.
1443
+
1444
+ INPUT:
1445
+
1446
+ - ``v`` -- a vertex
1447
+
1448
+ EXAMPLES::
1449
+
1450
+ sage: g = DiGraph(graphs.PetersenGraph(), data_structure='static_sparse')
1451
+ sage: g.neighbors_out(0)
1452
+ [1, 4, 5]
1453
+ """
1454
+ try:
1455
+ v = self._vertex_to_int[v]
1456
+ except KeyError:
1457
+ raise LookupError("the vertex does not belong to the graph")
1458
+
1459
+ cdef StaticSparseCGraph cg = self._cg
1460
+ cdef int i, u
1461
+ cdef set seen = set()
1462
+
1463
+ for i in range(out_degree(cg.g, v)):
1464
+ u = cg.g.neighbors[v][i]
1465
+ if u not in seen:
1466
+ yield self._vertex_to_labels[u]
1467
+ seen.add(u)
1468
+
1469
+ def iterator_in_nbrs(self, v):
1470
+ r"""
1471
+ Iterate over the in-neighbors of a vertex.
1472
+
1473
+ INPUT:
1474
+
1475
+ - ``v`` -- a vertex
1476
+
1477
+ EXAMPLES::
1478
+
1479
+ sage: g = DiGraph(graphs.PetersenGraph(), data_structure='static_sparse')
1480
+ sage: g.neighbors_in(0)
1481
+ [1, 4, 5]
1482
+
1483
+ TESTS::
1484
+
1485
+ sage: g = DiGraph({0: [1]}, immutable=True)
1486
+ sage: print(g.neighbors_in(1))
1487
+ [0]
1488
+ """
1489
+ try:
1490
+ v = self._vertex_to_int[v]
1491
+ except KeyError:
1492
+ raise LookupError("the vertex does not belong to the graph")
1493
+
1494
+ cdef StaticSparseCGraph cg = self._cg
1495
+ cdef int i, u
1496
+ cdef set seen = set()
1497
+
1498
+ if cg._directed:
1499
+ for i in range(out_degree(cg.g_rev, v)):
1500
+ u = cg.g_rev.neighbors[v][i]
1501
+ if u not in seen:
1502
+ yield self._vertex_to_labels[u]
1503
+ seen.add(u)
1504
+ else:
1505
+ for i in range(out_degree(cg.g, v)):
1506
+ u = cg.g.neighbors[v][i]
1507
+ if u not in seen:
1508
+ yield self._vertex_to_labels[u]
1509
+ seen.add(u)
1510
+
1511
+ def add_vertex(self, v):
1512
+ r"""
1513
+ Addition of vertices is not available on an immutable graph.
1514
+
1515
+ EXAMPLES::
1516
+
1517
+ sage: g = DiGraph(graphs.PetersenGraph(), data_structure='static_sparse')
1518
+ sage: g.add_vertex(1)
1519
+ Traceback (most recent call last):
1520
+ ...
1521
+ ValueError: graph is immutable; please change a copy instead (use function copy())
1522
+ sage: g.add_vertices([1,2,3])
1523
+ Traceback (most recent call last):
1524
+ ...
1525
+ ValueError: graph is immutable; please change a copy instead (use function copy())
1526
+ """
1527
+ (<StaticSparseCGraph> self._cg).add_vertex(v)
1528
+
1529
+ def del_vertex(self, v):
1530
+ r"""
1531
+ Removal of vertices is not available on an immutable graph.
1532
+
1533
+ EXAMPLES::
1534
+
1535
+ sage: g = DiGraph(graphs.PetersenGraph(), data_structure='static_sparse')
1536
+ sage: g.delete_vertex(1)
1537
+ Traceback (most recent call last):
1538
+ ...
1539
+ ValueError: graph is immutable; please change a copy instead (use function copy())
1540
+ sage: g.delete_vertices([1,2,3])
1541
+ Traceback (most recent call last):
1542
+ ...
1543
+ ValueError: graph is immutable; please change a copy instead (use function copy())
1544
+ """
1545
+ (<StaticSparseCGraph> self._cg).del_vertex(v)
1546
+
1547
+
1548
+ def _run_it_on_static_instead(f):
1549
+ r"""
1550
+ A decorator function to force the (Di)Graph functions to compute from a
1551
+ static sparse graph
1552
+
1553
+ This decorator can be used on methods from (Di)Graph. When it is applied,
1554
+ the method that was meant to compute something on a graph first converts
1555
+ this graph to a static sparse graph, then does what it had to do on this new
1556
+ graph. Of course, it makes no sense to decorate Graph.add_vertex with it as
1557
+ such a method will never work on an immutable graph. But it can help find
1558
+ new bugs, from time to time.
1559
+
1560
+ EXAMPLES::
1561
+
1562
+ sage: from sage.graphs.base.static_sparse_backend import _run_it_on_static_instead
1563
+ sage: @_run_it_on_static_instead
1564
+ ....: def new_graph_method(g):
1565
+ ....: print("My backend is of type {}".format(type(g._backend)))
1566
+ sage: Graph.new_graph_method = new_graph_method
1567
+ sage: g = Graph(5)
1568
+ sage: print("My backend is of type {}".format(type(g._backend)))
1569
+ My backend is of type <class 'sage.graphs.base.sparse_graph.SparseGraphBackend'>
1570
+ sage: g.new_graph_method()
1571
+ My backend is of type <class 'sage.graphs.base.static_sparse_backend.StaticSparseBackend'>
1572
+ """
1573
+ def same_function_on_static_version(*kwd, **kwds):
1574
+ if not isinstance(kwd[0]._backend, StaticSparseBackend):
1575
+ gcopy = kwd[0].copy(data_structure='static_sparse')
1576
+ return getattr(gcopy, f.__name__)(*kwd[1:], **kwds)
1577
+ else:
1578
+ return f(*kwd, **kwds)
1579
+
1580
+ return same_function_on_static_version