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