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,1653 @@
1
+ # sage_setup: distribution = sagemath-graphs
2
+ r"""
3
+ Fast sparse graphs
4
+
5
+ For an overview of graph data structures in sage, see
6
+ :mod:`~sage.graphs.base.overview`.
7
+
8
+ Usage Introduction
9
+ ------------------
10
+
11
+ ::
12
+
13
+ sage: from sage.graphs.base.sparse_graph import SparseGraph
14
+
15
+ Sparse graphs are initialized as follows::
16
+
17
+ sage: S = SparseGraph(nverts = 10, expected_degree = 3, extra_vertices = 10)
18
+
19
+ This example initializes a sparse graph with room for twenty vertices, the first
20
+ ten of which are in the graph. In general, the first ``nverts`` are "active."
21
+ For example, see that 9 is already in the graph::
22
+
23
+ sage: S.verts()
24
+ [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
25
+ sage: S.add_vertex(9)
26
+ 9
27
+ sage: S.verts()
28
+ [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
29
+
30
+ But 10 is not, until we add it::
31
+
32
+ sage: S.add_vertex(10)
33
+ 10
34
+ sage: S.verts()
35
+ [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
36
+
37
+ You can begin working with unlabeled arcs right away as follows::
38
+
39
+ sage: S.add_arc(0,1)
40
+ sage: S.add_arc(1,2)
41
+ sage: S.add_arc(1,0)
42
+ sage: S.has_arc(7,3)
43
+ False
44
+ sage: S.has_arc(0,1)
45
+ True
46
+ sage: S.in_neighbors(1)
47
+ [0]
48
+ sage: S.out_neighbors(1)
49
+ [0, 2]
50
+ sage: S.del_all_arcs(0,1)
51
+ sage: S.all_arcs(0,1)
52
+ []
53
+ sage: S.all_arcs(1,2)
54
+ [0]
55
+ sage: S.del_vertex(7)
56
+ sage: S.all_arcs(7,3)
57
+ Traceback (most recent call last):
58
+ ...
59
+ LookupError: vertex (7) is not a vertex of the graph
60
+
61
+ Sparse graphs support multiple edges and labeled edges, but requires that the
62
+ labels be positive integers (the case label = 0 is treated as no label).
63
+
64
+ ::
65
+
66
+ sage: S.add_arc_label(0,1,-1)
67
+ Traceback (most recent call last):
68
+ ...
69
+ ValueError: Label (-1) must be a nonnegative integer.
70
+ sage: S.add_arc(0,1)
71
+ sage: S.arc_label(0,1)
72
+ 0
73
+
74
+ Note that ``arc_label`` only returns the first edge label found in the specified
75
+ place, and this can be in any order (if you want all arc labels, use
76
+ ``all_arcs``)::
77
+
78
+ sage: S.add_arc_label(0,1,1)
79
+ sage: S.arc_label(0,1)
80
+ 1
81
+ sage: S.all_arcs(0,1)
82
+ [0, 1]
83
+
84
+ Zero specifies only that there is no labeled arc::
85
+
86
+ sage: S.arc_label(1,2)
87
+ 0
88
+
89
+ So do not be fooled::
90
+
91
+ sage: S.all_arcs(1,2)
92
+ [0]
93
+ sage: S.add_arc(1,2)
94
+ sage: S.arc_label(1,2)
95
+ 0
96
+
97
+ Instead, if you work with unlabeled edges, be sure to use the right functions::
98
+
99
+ sage: T = SparseGraph(nverts = 3, expected_degree = 2)
100
+ sage: T.add_arc(0,1)
101
+ sage: T.add_arc(1,2)
102
+ sage: T.add_arc(2,0)
103
+ sage: T.has_arc(0,1)
104
+ True
105
+
106
+ Sparse graphs are by their nature directed. As of this writing, you need to do
107
+ operations in pairs to treat the undirected case (or use a backend or a Sage
108
+ graph)::
109
+
110
+ sage: T.has_arc(1,0)
111
+ False
112
+
113
+ Multiple unlabeled edges are also possible::
114
+
115
+ sage: for _ in range(10): S.add_arc(5,4)
116
+ sage: S.all_arcs(5,4)
117
+ [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
118
+
119
+ The curious developer is encouraged to check out the ``unsafe`` functions,
120
+ which do not check input but which run in pure C.
121
+
122
+ Underlying Data Structure
123
+ -------------------------
124
+
125
+ The class ``SparseGraph`` contains the following variables which are inherited
126
+ from ``CGraph`` (for explanation, refer to the documentation there)::
127
+
128
+ cdef int num_verts
129
+ cdef int num_arcs
130
+ cdef int *in_degrees
131
+ cdef int *out_degrees
132
+ cdef bitset_t active_vertices
133
+
134
+ It also contains the following variables::
135
+
136
+ cdef int hash_length
137
+ cdef int hash_mask
138
+ cdef SparseGraphBTNode **vertices
139
+ cdef SparseGraphBTNode **vertices_rev
140
+ cdef bint _directed
141
+
142
+ For each vertex ``u``, a hash table of length ``hash_length`` is instantiated.
143
+ An arc ``(u, v)`` is stored at ``u * hash_length + hash(v)`` of the array
144
+ ``vertices``, where ``hash`` should be thought of as an arbitrary but fixed hash
145
+ function which takes values in ``0 <= hash < hash_length``. Each address may
146
+ represent different arcs, say ``(u, v1)`` and ``(u, v2)`` where
147
+ ``hash(v1) == hash(v2)``. Thus, a binary tree structure is used at this step to
148
+ speed access to individual arcs, whose nodes (each of which represents a pair
149
+ ``(u,v)``) are instances of the following type::
150
+
151
+ cdef struct SparseGraphBTNode:
152
+ int vertex
153
+ int number
154
+ SparseGraphLLNode *labels
155
+ SparseGraphBTNode *left
156
+ SparseGraphBTNode *right
157
+
158
+ Which range of the ``vertices`` array the root of the tree is in determines
159
+ ``u``, and ``vertex`` stores ``v``. The integer ``number`` stores only the
160
+ number of unlabeled arcs from ``u`` to ``v``.
161
+
162
+ Currently, labels are stored in a simple linked list, whose nodes are instances
163
+ of the following type::
164
+
165
+ cdef struct SparseGraphLLNode:
166
+ int label
167
+ int number
168
+ SparseGraphLLNode *next
169
+
170
+ The int ``label`` must be a positive integer, since 0 indicates no label, and
171
+ negative numbers indicate errors. The int ``number`` is the number of arcs with
172
+ the given label.
173
+
174
+ TODO: Optimally, edge labels would also be represented by a binary tree, which
175
+ would help performance in graphs with many overlapping edges. Also, a more
176
+ efficient binary tree structure could be used, although in practice the trees
177
+ involved will usually have very small order, unless the degree of vertices
178
+ becomes significantly larger than the ``expected_degree`` given, because this is
179
+ the size of each hash table. Indeed, the expected size of the binary trees is
180
+ `\frac{\text{actual degree}}{\text{expected degree}}`. Ryan Dingman, e.g., is
181
+ working on a general-purpose Cython-based red black tree, which would be optimal
182
+ for both of these uses.
183
+ """
184
+
185
+ # ****************************************************************************
186
+ # Copyright (C) 2008-9 Robert L. Miller <rlmillster@gmail.com>
187
+ #
188
+ # This program is free software: you can redistribute it and/or modify
189
+ # it under the terms of the GNU General Public License as published by
190
+ # the Free Software Foundation, either version 2 of the License, or
191
+ # (at your option) any later version.
192
+ # https://www.gnu.org/licenses/
193
+ # ****************************************************************************
194
+
195
+
196
+ from libc.string cimport memset
197
+ from cysignals.memory cimport check_malloc, check_allocarray, sig_free
198
+ from memory_allocator cimport MemoryAllocator
199
+
200
+ from sage.data_structures.bitset_base cimport *
201
+ from sage.data_structures.bitset cimport *
202
+
203
+
204
+ cdef enum:
205
+ BT_REORDERING_CONSTANT = 145533211
206
+ # Since the binary tree will often see vertices coming in already sorted,
207
+ # we don't use the normal ordering on integers, instead multiplying by a
208
+ # randomly chosen number and (after reducing mod the size of integers)
209
+ # comparing the result. This isn't necessarily the most efficient way to do
210
+ # things, but it may just be on binary trees that are never bigger than two
211
+ # or three nodes.
212
+
213
+
214
+ cdef inline int compare(int a, int b) noexcept:
215
+ # Here we rely on the fact that C performs arithmetic on unsigned
216
+ # ints modulo 2^wordsize.
217
+ cdef unsigned int aa = a, bb = b # signed ints lead to badness like a>b>c>a...
218
+ if aa*BT_REORDERING_CONSTANT > bb*BT_REORDERING_CONSTANT:
219
+ return 1
220
+ elif aa*BT_REORDERING_CONSTANT < bb*BT_REORDERING_CONSTANT:
221
+ return -1
222
+ return 0
223
+
224
+
225
+ cdef class SparseGraph(CGraph):
226
+ """
227
+ Compiled sparse graphs.
228
+
229
+ ::
230
+
231
+ sage: from sage.graphs.base.sparse_graph import SparseGraph
232
+
233
+ Sparse graphs are initialized as follows::
234
+
235
+ sage: S = SparseGraph(nverts = 10, expected_degree = 3, extra_vertices = 10)
236
+
237
+ INPUT:
238
+
239
+ - ``nverts`` -- nonnegative integer, the number of vertices
240
+
241
+ - ``expected_degree`` -- nonnegative integer (default: 16); expected upper
242
+ bound on degree of vertices
243
+
244
+ - ``extra_vertices`` -- nonnegative integer (default: 0); how many extra
245
+ vertices to allocate
246
+
247
+ - ``verts`` -- (optional) list of vertices to add
248
+
249
+ - ``arcs`` -- (optional) list of arcs to add
250
+
251
+ The first ``nverts`` are created as vertices of the graph, and the next
252
+ ``extra_vertices`` can be freely added without reallocation. See top level
253
+ documentation for more details. The input ``verts`` and ``arcs`` are mainly
254
+ for use in pickling.
255
+ """
256
+
257
+ def __cinit__(self, int nverts, int expected_degree=16, int extra_vertices=10,
258
+ verts=None, arcs=None, directed=True):
259
+ """
260
+ Allocation and initialization happen in one place.
261
+
262
+ Memory usage is roughly
263
+
264
+ O( (nverts + extra_vertices)*expected_degree + num_arcs ).
265
+
266
+ EXAMPLES::
267
+
268
+ sage: from sage.graphs.base.sparse_graph import SparseGraph
269
+ sage: S = SparseGraph(nverts = 10, expected_degree = 3, extra_vertices = 10)
270
+
271
+ TESTS::
272
+
273
+ sage: Graph(-1)
274
+ Traceback (most recent call last):
275
+ ...
276
+ ValueError: The number of vertices cannot be strictly negative!
277
+ """
278
+ cdef int i = 1
279
+ if nverts < 0:
280
+ raise ValueError("The number of vertices cannot be strictly negative!")
281
+ if nverts == 0 and extra_vertices == 0:
282
+ raise RuntimeError('Sparse graphs must allocate space for vertices!')
283
+ self.num_verts = nverts
284
+ nverts += extra_vertices
285
+ self.num_arcs = 0
286
+ while i < expected_degree:
287
+ i = i << 1
288
+ self.hash_length = i
289
+ self.hash_mask = i - 1
290
+
291
+ # Allocating memory (initialized to zero)
292
+ self.vertices = <SparseGraphBTNode **>check_calloc(
293
+ nverts * self.hash_length, sizeof(SparseGraphBTNode *))
294
+ if directed:
295
+ # In a directed graph we keep also track of the incoming edges.
296
+ # So each edge has two copies.
297
+ self.vertices_rev = <SparseGraphBTNode **>check_calloc(
298
+ nverts * self.hash_length, sizeof(SparseGraphBTNode *))
299
+ else:
300
+ self.vertices_rev = self.vertices
301
+ self._directed = directed
302
+
303
+ self.in_degrees = <int *>check_calloc(nverts, sizeof(int))
304
+ self.out_degrees = <int *>check_calloc(nverts, sizeof(int))
305
+
306
+ bitset_init(self.active_vertices, self.num_verts + extra_vertices)
307
+ bitset_set_first_n(self.active_vertices, self.num_verts)
308
+
309
+ if verts is not None:
310
+ self.add_vertices(verts)
311
+
312
+ if arcs is not None:
313
+ for u, v, l in arcs:
314
+ self.add_arc_label(u, v, l)
315
+
316
+ def __dealloc__(self):
317
+ """
318
+ New and dealloc are both tested at class level.
319
+ """
320
+ cdef SparseGraphBTNode **temp
321
+ cdef SparseGraphLLNode *label_temp
322
+ cdef size_t i
323
+
324
+ # Freeing the list of arcs attached to each vertex (going out)
325
+ for i in range(self.active_vertices.size * self.hash_length):
326
+ temp = &(self.vertices[i])
327
+
328
+ # While temp[0]=self.vertices[i] is not NULL, find a leaf in the
329
+ # tree rooted at temp[0] and free it. Then go back to temp[0] and do
330
+ # it again. When self.vertices[i] is NULL, go for self.vertices[i+1]
331
+ while temp[0]:
332
+ if temp[0].left:
333
+ temp = &(temp[0].left)
334
+ elif temp[0].right:
335
+ temp = &(temp[0].right)
336
+ else:
337
+ label_temp = temp[0].labels
338
+ while label_temp:
339
+ temp[0].labels = label_temp.next
340
+ sig_free(label_temp)
341
+ label_temp = temp[0].labels
342
+ sig_free(temp[0])
343
+ temp[0] = NULL
344
+ temp = &(self.vertices[i])
345
+
346
+ if self.is_directed():
347
+
348
+ # Freeing the list of arcs attached to each vertex (going in)
349
+ for i in range(self.active_vertices.size * self.hash_length):
350
+ temp = &(self.vertices_rev[i])
351
+
352
+ # While temp[0]=self.vertices_rev[i] is not NULL, find a leaf in the
353
+ # tree rooted at temp[0] and free it. Then go back to temp[0] and do
354
+ # it again. When self.vertices_rev[i] is NULL, go for self.vertices_rev[i+1]
355
+ while temp[0]:
356
+ if temp[0].left:
357
+ temp = &(temp[0].left)
358
+ elif temp[0].right:
359
+ temp = &(temp[0].right)
360
+ else:
361
+ label_temp = temp[0].labels
362
+ while label_temp:
363
+ temp[0].labels = label_temp.next
364
+ sig_free(label_temp)
365
+ label_temp = temp[0].labels
366
+ sig_free(temp[0])
367
+ temp[0] = NULL
368
+ temp = &(self.vertices_rev[i])
369
+ sig_free(self.vertices_rev)
370
+
371
+ sig_free(self.vertices)
372
+ sig_free(self.in_degrees)
373
+ sig_free(self.out_degrees)
374
+ bitset_free(self.active_vertices)
375
+
376
+ cpdef realloc(self, int total):
377
+ """
378
+ Reallocate the number of vertices to use, without actually adding any.
379
+
380
+ INPUT:
381
+
382
+ - ``total`` -- integer; the total size to make the array
383
+
384
+ Returns -1 and fails if reallocation would destroy any active vertices.
385
+
386
+ EXAMPLES::
387
+
388
+ sage: from sage.graphs.base.sparse_graph import SparseGraph
389
+ sage: S = SparseGraph(nverts=4, extra_vertices=4)
390
+ sage: S.current_allocation()
391
+ 8
392
+ sage: S.add_vertex(6)
393
+ 6
394
+ sage: S.current_allocation()
395
+ 8
396
+ sage: S.add_vertex(10)
397
+ 10
398
+ sage: S.current_allocation()
399
+ 16
400
+ sage: S.add_vertex(40)
401
+ Traceback (most recent call last):
402
+ ...
403
+ RuntimeError: requested vertex is past twice the allocated range: use realloc
404
+ sage: S.realloc(50)
405
+ sage: S.add_vertex(40)
406
+ 40
407
+ sage: S.current_allocation()
408
+ 50
409
+ sage: S.realloc(30)
410
+ -1
411
+ sage: S.current_allocation()
412
+ 50
413
+ sage: S.del_vertex(40)
414
+ sage: S.realloc(30)
415
+ sage: S.current_allocation()
416
+ 30
417
+ """
418
+ if not total:
419
+ raise RuntimeError('Sparse graphs must allocate space for vertices!')
420
+ cdef bitset_t bits
421
+ cdef size_t s_total = <size_t>total
422
+ if s_total < self.active_vertices.size:
423
+ bitset_init(bits, self.active_vertices.size)
424
+ bitset_set_first_n(bits, s_total)
425
+ if not bitset_issubset(self.active_vertices, bits):
426
+ bitset_free(bits)
427
+ return -1
428
+ bitset_free(bits)
429
+
430
+ self.vertices = <SparseGraphBTNode **>check_reallocarray(
431
+ self.vertices, s_total * self.hash_length, sizeof(SparseGraphBTNode *))
432
+ if self.is_directed():
433
+ self.vertices_rev = <SparseGraphBTNode **>check_reallocarray(
434
+ self.vertices_rev, s_total * self.hash_length, sizeof(SparseGraphBTNode *))
435
+ else:
436
+ self.vertices_rev = self.vertices
437
+
438
+ self.in_degrees = <int *>check_reallocarray(self.in_degrees, s_total, sizeof(int))
439
+ self.out_degrees = <int *>check_reallocarray(self.out_degrees, s_total, sizeof(int))
440
+
441
+ cdef int new_vertices = total - self.active_vertices.size
442
+
443
+ # Initializing the entries corresponding to new vertices if any
444
+ if new_vertices > 0:
445
+
446
+ # self.vertices
447
+ memset(self.vertices + self.active_vertices.size * self.hash_length, 0,
448
+ new_vertices * self.hash_length * sizeof(SparseGraphBTNode *))
449
+ if self.is_directed():
450
+ memset(self.vertices_rev + self.active_vertices.size * self.hash_length, 0,
451
+ new_vertices * self.hash_length * sizeof(SparseGraphBTNode *))
452
+
453
+ # self.in_degrees
454
+ memset(self.in_degrees + self.active_vertices.size, 0,
455
+ new_vertices * sizeof(int))
456
+
457
+ # self.out_degrees
458
+ memset(self.out_degrees + self.active_vertices.size, 0,
459
+ new_vertices * sizeof(int))
460
+
461
+ # self.active_vertices
462
+ bitset_realloc(self.active_vertices, s_total)
463
+
464
+ cpdef inline bint is_directed(self) noexcept:
465
+ r"""
466
+ Return whether the graph is directed.
467
+
468
+ EXAMPLES::
469
+
470
+ sage: from sage.graphs.base.sparse_graph import SparseGraph
471
+ sage: G = SparseGraph(5)
472
+ sage: G.is_directed()
473
+ True
474
+ sage: G = SparseGraph(5, directed=False)
475
+ sage: G.is_directed()
476
+ False
477
+ """
478
+ return self._directed
479
+
480
+ ###################################
481
+ # Unlabeled arc functions
482
+ ###################################
483
+
484
+ cdef inline int _del_arc_unsafe(self, int u, int v, SparseGraphBTNode **parent) except -1:
485
+ """
486
+ .. WARNING::
487
+
488
+ This method is for internal use only. Use :meth:`del_arc_unsafe` instead.
489
+
490
+ Deletes *all* arcs from u to v, returns the number of arcs deleted.
491
+ """
492
+ cdef int i = (u * self.hash_length) + (v & self.hash_mask)
493
+ parent = &parent[i]
494
+ cdef int compared, left_len, right_len
495
+ cdef SparseGraphBTNode *temp
496
+ cdef SparseGraphBTNode **left_child
497
+ cdef SparseGraphBTNode **right_child
498
+ cdef SparseGraphLLNode *labels
499
+ cdef int n_arcs = 0
500
+
501
+ # Assigning to parent the SparseGraphBTNode corresponding to arc (u,v)
502
+ while parent[0]:
503
+ compared = compare(parent[0].vertex, v)
504
+ if compared > 0:
505
+ parent = &(parent[0].left)
506
+ elif compared < 0:
507
+ parent = &(parent[0].right)
508
+ else: # if parent[0].vertex == v:
509
+ break
510
+
511
+ # If not found, there is no arc to delete !
512
+ if not parent[0]:
513
+ return n_arcs
514
+
515
+ # now parent[0] points to the BT node corresponding to (u,v)
516
+ labels = parent[0].labels
517
+ n_arcs += parent[0].number
518
+
519
+ # Freeing the labels
520
+ while labels:
521
+ n_arcs += labels.number
522
+ parent[0].labels = parent[0].labels.next
523
+ sig_free(labels)
524
+ labels = parent[0].labels
525
+
526
+ # Now, if the SparseGraphBTNode element is to be removed, it has to be
527
+ # replaced in the binary tree by one of its children.
528
+
529
+ # If there is no left child
530
+ if not parent[0].left:
531
+ temp = parent[0]
532
+ parent[0] = parent[0].right
533
+ sig_free(temp)
534
+ return n_arcs
535
+
536
+ # If there is no right child
537
+ elif not parent[0].right:
538
+ temp = parent[0]
539
+ parent[0] = parent[0].left
540
+ sig_free(temp)
541
+ return n_arcs
542
+
543
+ # Both children
544
+ else:
545
+ left_len = 0
546
+ right_len = 0
547
+ left_child = &(parent[0].left)
548
+ right_child = &(parent[0].right)
549
+
550
+ # left_len is equal to the maximum length of a path LR...R. The
551
+ # last element of this path is the value of left_child
552
+
553
+ while left_child[0].right:
554
+ left_len += 1
555
+ left_child = &(left_child[0].right)
556
+ # right_len is equal to the maximum length of a path RL...L. The
557
+ # last element of this path is the value of right_child
558
+
559
+ while right_child[0].left:
560
+ right_len += 1
561
+ right_child = &(right_child[0].left)
562
+
563
+ # According to the respective lengths, replace parent by the left or
564
+ # right child and place the other child at its expected place.
565
+ if left_len > right_len:
566
+ left_child[0].right = parent[0].right
567
+ temp = parent[0]
568
+ parent[0] = left_child[0]
569
+ left_child[0] = left_child[0].left
570
+ parent[0].left = temp.left
571
+ sig_free(temp)
572
+ return n_arcs
573
+ else:
574
+ right_child[0].left = parent[0].left
575
+ temp = parent[0]
576
+ parent[0] = right_child[0]
577
+ right_child[0] = right_child[0].right
578
+ parent[0].right = temp.right
579
+ sig_free(temp)
580
+ return n_arcs
581
+
582
+ cdef int del_arc_unsafe(self, int u, int v) except -1:
583
+ """
584
+ Delete *all* arcs from u to v.
585
+
586
+ INPUT:
587
+
588
+ - ``u``, ``v`` -- nonnegative integers
589
+
590
+ OUTPUT:
591
+
592
+ - 0 -- no error
593
+ - 1 -- no arc to delete
594
+ """
595
+ cdef int n_arcs = self._del_arc_unsafe(u, v, self.vertices)
596
+ if u != v or self.is_directed():
597
+ # We remove the reverse copy only if u != v or graph is directed.
598
+ self._del_arc_unsafe(v, u, self.vertices_rev)
599
+ if self.vertices == self.vertices_rev:
600
+ # In case of an undirected graph, we have added two copies each.
601
+ self.in_degrees[u] -= n_arcs
602
+ self.out_degrees[v] -= n_arcs
603
+ self.num_arcs -= n_arcs
604
+
605
+ self.in_degrees[v] -= n_arcs
606
+ self.out_degrees[u] -= n_arcs
607
+ self.num_arcs -= n_arcs
608
+ if n_arcs:
609
+ return 1
610
+
611
+ ###################################
612
+ # Neighbor functions
613
+ ###################################
614
+
615
+ cdef inline int _neighbors_BTNode_unsafe (self, int u, bint out, SparseGraphBTNode **res, int size) except -2:
616
+ r"""
617
+ .. WARNING::
618
+
619
+ This method is for internal use only.
620
+ """
621
+ cdef SparseGraphBTNode** vertices = self.vertices if out else self.vertices_rev
622
+ cdef int i
623
+ cdef int n = 0
624
+ cdef int nr = 0
625
+ cdef SparseGraphBTNode *c
626
+
627
+ for i in range(u * self.hash_length, (u+1) * self.hash_length):
628
+ if not vertices[i]:
629
+ continue
630
+ else:
631
+ res[n] = vertices[i]
632
+ nr = 1
633
+ while nr > 0 and n < size:
634
+ c = res[n]
635
+ n += 1
636
+ nr -= 1
637
+ if c.left:
638
+ res[n+nr] = c.left
639
+ nr += 1
640
+ if c.right:
641
+ res[n+nr] = c.right
642
+ nr += 1
643
+ return -1 if nr > 0 else n
644
+
645
+ cdef inline int next_out_neighbor_unsafe(self, int u, int v, int* l) except -2:
646
+ """
647
+ Return the next out-neighbor of ``u`` that is greater than ``v``.
648
+
649
+ If ``v`` is ``-1`` return the first neighbor of ``u``.
650
+
651
+ Return ``-1`` in case there does not exist such an out-neighbor.
652
+
653
+ Set ``l`` to be the label of the first arc.
654
+
655
+ .. WARNING::
656
+
657
+ Repeated calls to this function until -1 is returned DOES NOT yield
658
+ a linear time algorithm in the number of neighbors of v.
659
+ To list the neighbors of a vertex in linear time, one should use
660
+ out_neighbors_unsafe.
661
+ """
662
+ cdef SparseGraphBTNode* next_bt = self.next_out_neighbor_BTNode_unsafe(u, v)
663
+ if next_bt:
664
+ if next_bt.number:
665
+ l[0] = 0
666
+ else:
667
+ l[0] = next_bt.labels.label
668
+ return next_bt.vertex
669
+ else:
670
+ return -1
671
+
672
+ cdef inline SparseGraphBTNode* next_neighbor_BTNode_unsafe(self, SparseGraphBTNode** vertices, int u, int v) noexcept:
673
+ """
674
+ Return the next neighbor of ``u`` that is greater than ``v``.
675
+
676
+ If ``v`` is ``-1`` return the first neighbor of ``u``.
677
+
678
+ Return ``NULL`` in case there does not exist such a neighbor.
679
+
680
+ If ``vertices`` is ``self.vertices`` the out-neighbor is given.
681
+ If ``vertices`` is ``self.vertices_rev`` the in-neighbor is given.
682
+
683
+ .. WARNING::
684
+
685
+ Repeated calls to this function until NULL is returned DOES NOT
686
+ yield a linear time algorithm in the number of neighbors of u.
687
+ To list the neighbors of a vertex in linear time, one should use
688
+ _neighbors_BTNode_unsafe.
689
+ """
690
+ cdef int i
691
+ cdef int start_i = (u * self.hash_length) + (v & self.hash_mask)
692
+ cdef SparseGraphBTNode* temp
693
+ cdef SparseGraphBTNode* last_larger
694
+
695
+ i = start_i
696
+ if v != -1 and vertices[i]:
697
+ last_larger = NULL
698
+ temp = vertices[i]
699
+ while temp:
700
+ if compare(temp.vertex, v) > 0:
701
+ # We have found a candidate.
702
+ # We fall back to it, if we do not find anything smaller.
703
+ last_larger = temp
704
+ temp = temp.left
705
+ else: # note compare < 0
706
+ temp = temp.right
707
+ if last_larger:
708
+ return last_larger
709
+ elif v == -1:
710
+ start_i = (u*self.hash_length) - 1
711
+
712
+ # Return the next vertex.
713
+ for i in range(start_i+1, (u+1) * self.hash_length):
714
+ if not vertices[i]:
715
+ continue
716
+ temp = vertices[i]
717
+ while temp.left:
718
+ temp = temp.left
719
+ return temp
720
+ return NULL
721
+
722
+ cpdef int out_degree(self, int u) noexcept:
723
+ """
724
+ Return the out-degree of ``v``
725
+
726
+ INPUT:
727
+
728
+ - ``u`` -- integer
729
+
730
+ EXAMPLES::
731
+
732
+ sage: from sage.graphs.base.sparse_graph import SparseGraph
733
+ sage: G = SparseGraph(5)
734
+ sage: G.add_arc(0,1)
735
+ sage: G.add_arc(1,2)
736
+ sage: G.add_arc(1,3)
737
+ sage: G.out_degree(0)
738
+ 1
739
+ sage: G.out_degree(1)
740
+ 2
741
+ """
742
+ return self.out_degrees[u]
743
+
744
+ cdef inline int next_in_neighbor_unsafe(self, int v, int u, int* l) except -2:
745
+ """
746
+ Return the next in-neighbor of ``v`` that is greater than ``u``.
747
+
748
+ If ``u`` is ``-1`` return the first neighbor of ``v``.
749
+
750
+ Return ``-1`` in case there does not exist such an in-neighbor.
751
+
752
+ Set ``l`` to be the label of the first arc.
753
+
754
+ .. WARNING::
755
+
756
+ Repeated calls to this function until -1 is returned DOES NOT yield
757
+ a linear time algorithm in the number of neighbors of v.
758
+ To list the neighbors of a vertex in linear time, one should use
759
+ in_neighbors_unsafe.
760
+ """
761
+ cdef SparseGraphBTNode* next_bt = self.next_in_neighbor_BTNode_unsafe(v, u)
762
+ if next_bt:
763
+ if next_bt.number:
764
+ l[0] = 0
765
+ else:
766
+ l[0] = next_bt.labels.label
767
+ return next_bt.vertex
768
+ else:
769
+ return -1
770
+
771
+ cdef inline int _neighbors_unsafe(self, int u, bint out, int *neighbors, int size) except -2:
772
+ r"""
773
+ .. WARNING::
774
+
775
+ This method is for internal use only.
776
+ """
777
+ cdef int r
778
+ cdef SparseGraphBTNode **nodes = <SparseGraphBTNode **>check_allocarray(size, sizeof(SparseGraphBTNode *))
779
+
780
+ r = self._neighbors_BTNode_unsafe(u, out, nodes, size)
781
+ for i in range(r if r >= 0 else size):
782
+ neighbors[i] = nodes[i].vertex
783
+ sig_free(nodes)
784
+ return r
785
+
786
+ cdef int out_neighbors_unsafe(self, int u, int *neighbors, int size) except -2:
787
+ return self._neighbors_unsafe(u, 1, neighbors, size)
788
+
789
+ cdef int in_neighbors_unsafe(self, int u, int *neighbors, int size) except -2:
790
+ return self._neighbors_unsafe(u, 0, neighbors, size)
791
+
792
+ cpdef int in_degree(self, int v) noexcept:
793
+ """
794
+ Return the in-degree of ``v``
795
+
796
+ INPUT:
797
+
798
+ - ``v`` -- integer
799
+
800
+ EXAMPLES::
801
+
802
+ sage: from sage.graphs.base.sparse_graph import SparseGraph
803
+ sage: G = SparseGraph(5)
804
+ sage: G.add_arc(0,1)
805
+ sage: G.add_arc(1,2)
806
+ sage: G.add_arc(1,3)
807
+ sage: G.in_degree(0)
808
+ 0
809
+ sage: G.in_degree(1)
810
+ 1
811
+ """
812
+ return self.in_degrees[v]
813
+
814
+ ###################################
815
+ # Labeled arc functions
816
+ ###################################
817
+
818
+ cdef inline int _add_arc_label_unsafe(self, int u, int v, int l, SparseGraphBTNode **ins_pt) except -1:
819
+ r"""
820
+ .. WARNING::
821
+
822
+ This method is for internal use only. Use :meth:`add_arc_label_unsafe` instead.
823
+
824
+ Add arc (u, v) with label l to only the ingoing or outgoing arcs
825
+ """
826
+ cdef int i = (u * self.hash_length) + (v & self.hash_mask)
827
+ ins_pt = &ins_pt[i]
828
+ cdef int compared
829
+ cdef SparseGraphLLNode *label_ptr
830
+ while ins_pt[0]:
831
+ compared = compare(ins_pt[0].vertex, v)
832
+ if compared > 0:
833
+ ins_pt = &(ins_pt[0].left)
834
+ elif compared < 0:
835
+ ins_pt = &(ins_pt[0].right)
836
+ else:
837
+ break
838
+ if not ins_pt[0]:
839
+ ins_pt[0] = <SparseGraphBTNode *>check_malloc(sizeof(SparseGraphBTNode))
840
+ ins_pt[0].number = 0
841
+ ins_pt[0].vertex = v
842
+ ins_pt[0].left = NULL
843
+ ins_pt[0].right = NULL
844
+ ins_pt[0].labels = NULL
845
+ if l:
846
+ label_ptr = ins_pt[0].labels
847
+ while label_ptr and label_ptr.label != l:
848
+ label_ptr = label_ptr.next
849
+ if not label_ptr:
850
+ label_ptr = <SparseGraphLLNode *>check_malloc(sizeof(SparseGraphLLNode))
851
+ label_ptr.label = l
852
+ label_ptr.number = 1
853
+ label_ptr.next = ins_pt[0].labels
854
+ ins_pt[0].labels = label_ptr
855
+ else:
856
+ label_ptr.number += 1
857
+ else:
858
+ ins_pt[0].number += 1
859
+
860
+ cdef int add_arc_label_unsafe(self, int u, int v, int l) except -1:
861
+ """
862
+ Add arc (u, v) to the graph with label l.
863
+
864
+ INPUT:
865
+
866
+ - ``u``, ``v`` -- nonnegative integers
867
+
868
+ - ``l`` -- positive integer label, or zero for no label
869
+
870
+ OUTPUT: ``0`` -- no error
871
+ """
872
+ self._add_arc_label_unsafe(u, v, l, self.vertices)
873
+ if u != v or self.is_directed():
874
+ # We add the reverse copy only if u != v or graph is directed.
875
+ self._add_arc_label_unsafe(v, u, l, self.vertices_rev)
876
+ if self.vertices == self.vertices_rev:
877
+ # In case of an undirected graph, we have added two arcs.
878
+ self.in_degrees[u] += 1
879
+ self.out_degrees[v] += 1
880
+ self.num_arcs += 1
881
+
882
+ self.in_degrees[v] += 1
883
+ self.out_degrees[u] += 1
884
+ self.num_arcs += 1
885
+
886
+ def add_arc_label(self, int u, int v, int l=0):
887
+ """
888
+ Add arc ``(u, v)`` to the graph with label ``l``.
889
+
890
+ INPUT:
891
+
892
+ - ``u``, ``v`` -- nonnegative integers, must be in ``self``
893
+
894
+ - ``l`` -- positive integer label, or zero for no label
895
+
896
+ EXAMPLES::
897
+
898
+ sage: from sage.graphs.base.sparse_graph import SparseGraph
899
+ sage: G = SparseGraph(5)
900
+ sage: G.add_arc_label(0,1)
901
+ sage: G.add_arc_label(4,7)
902
+ Traceback (most recent call last):
903
+ ...
904
+ LookupError: vertex (7) is not a vertex of the graph
905
+ sage: G.has_arc(1,0)
906
+ False
907
+ sage: G.has_arc(0,1)
908
+ True
909
+ sage: G.add_arc_label(1,2,2)
910
+ sage: G.arc_label(1,2)
911
+ 2
912
+ """
913
+ self.check_vertex(u)
914
+ self.check_vertex(v)
915
+ if l < 0:
916
+ raise ValueError("Label ({0}) must be a nonnegative integer.".format(l))
917
+ self.add_arc_label_unsafe(u, v, l)
918
+
919
+ cdef int arc_label_unsafe(self, int u, int v) except -1:
920
+ """
921
+ Retrieves the first label found associated with (u, v) (a positive
922
+ integer).
923
+
924
+ INPUT:
925
+
926
+ - ``u``, ``v`` -- integers from `0`, ..., `n-1`, where `n` is the
927
+ number of vertices
928
+
929
+ OUTPUT: one of
930
+
931
+ - positive integer -- indicates that there is a label on ``(u, v)``
932
+
933
+ - ``0`` -- either the arc ``(u, v)`` is unlabeled, or there is no arc at all.
934
+ """
935
+ cdef int i = (u * self.hash_length) + (v & self.hash_mask)
936
+ cdef int compared
937
+ cdef SparseGraphBTNode *temp = self.vertices[i]
938
+ while temp:
939
+ compared = compare(temp.vertex, v)
940
+ if compared > 0:
941
+ temp = temp.left
942
+ elif compared < 0:
943
+ temp = temp.right
944
+ else:
945
+ break
946
+ if not temp or not temp.labels:
947
+ return 0
948
+ return temp.labels.label
949
+
950
+ cdef int all_arcs_unsafe(self, int u, int v, int *arc_labels, int size) except -1:
951
+ """
952
+ Give the labels of all arcs (u, v).
953
+
954
+ INPUT:
955
+
956
+ - ``u``, ``v`` -- integers from `0`, ..., `n-1`, where `n` is the
957
+ number of vertices
958
+ - ``arc_labels`` -- must be a pointer to an (allocated) integer array
959
+ - ``size`` -- the length of the array
960
+
961
+ OUTPUT: integer; the number of arcs ``(u, v)``.
962
+ ``-1`` -- indicates that the array has been filled with labels, but
963
+ there were more.
964
+ """
965
+ cdef int i = (u * self.hash_length) + (v & self.hash_mask), j
966
+ cdef int compared, num_arcs
967
+ cdef SparseGraphBTNode *temp = self.vertices[i]
968
+ cdef SparseGraphLLNode *label
969
+ while temp:
970
+ compared = compare(temp.vertex, v)
971
+ if compared > 0:
972
+ temp = temp.left
973
+ elif compared < 0:
974
+ temp = temp.right
975
+ else: # temp.vertex == v:
976
+ break
977
+ if not temp:
978
+ return 0
979
+ j = 0
980
+ num_arcs = temp.number
981
+ while j < num_arcs and j < size:
982
+ arc_labels[j] = 0
983
+ j += 1
984
+ label = temp.labels
985
+ while label:
986
+ num_arcs += label.number
987
+ while j < num_arcs and j < size:
988
+ arc_labels[j] = label.label
989
+ j += 1
990
+ label = label.next
991
+ if j == size and label:
992
+ return -1
993
+ return num_arcs
994
+
995
+ cdef SparseGraphLLNode* arc_labels_unsafe(self, int u, int v) noexcept:
996
+ """
997
+ Return the first label of arcs (u, v) or ``NULL`` if there are none.
998
+
999
+ INPUT:
1000
+
1001
+ - ``u``, ``v`` -- integers from `0`, ..., `n-1`, where `n` is the
1002
+ number of vertices
1003
+
1004
+ OUTPUT:
1005
+
1006
+ - a pointer to the first label or ``NULL`` if there are none
1007
+ """
1008
+ cdef int i = (u * self.hash_length) + (v & self.hash_mask)
1009
+ cdef int compared
1010
+ cdef SparseGraphBTNode *temp = self.vertices[i]
1011
+ while temp:
1012
+ compared = compare(temp.vertex, v)
1013
+ if compared > 0:
1014
+ temp = temp.left
1015
+ elif compared < 0:
1016
+ temp = temp.right
1017
+ else: # temp.vertex == v:
1018
+ break
1019
+ if not temp:
1020
+ return NULL
1021
+ return temp.labels
1022
+
1023
+ cdef inline int _del_arc_label_unsafe(self, int u, int v, int l, SparseGraphBTNode **parent) noexcept:
1024
+ """
1025
+ .. WARNING::
1026
+
1027
+ This method is for internal use only. Use :meth:`del_arc_label_unsafe` instead.
1028
+
1029
+ Delete an arc (u, v) with label l.
1030
+
1031
+ OUTPUT:
1032
+
1033
+ - 0 -- no error
1034
+ - 1 -- no arc with label l
1035
+ """
1036
+ cdef int i = (u * self.hash_length) + (v & self.hash_mask)
1037
+ cdef SparseGraphBTNode **old_parent = parent
1038
+ parent = &parent[i]
1039
+ cdef int compared
1040
+ cdef SparseGraphLLNode **labels
1041
+ cdef SparseGraphLLNode *label
1042
+ while parent[0]:
1043
+ compared = compare(parent[0].vertex, v)
1044
+ if compared > 0:
1045
+ parent = &(parent[0].left)
1046
+ elif compared < 0:
1047
+ parent = &(parent[0].right)
1048
+ else: # if parent[0].vertex == v:
1049
+ break
1050
+ if not parent[0]:
1051
+ return 1 # indicate an error
1052
+ if l == 0:
1053
+ if parent[0].number > 1:
1054
+ parent[0].number -= 1
1055
+ elif parent[0].number == 1:
1056
+ if not parent[0].labels:
1057
+ self._del_arc_unsafe(u, v, old_parent)
1058
+ return 0
1059
+ else:
1060
+ parent[0].number -= 1
1061
+ else:
1062
+ return 1 # indicate an error
1063
+ else:
1064
+ labels = &(parent[0].labels)
1065
+ while labels[0] and labels[0].label != l:
1066
+ labels = &(labels[0].next)
1067
+ if not labels[0]:
1068
+ return 1
1069
+ label = labels[0]
1070
+ if label.number > 1:
1071
+ label.number -= 1
1072
+ else:
1073
+ labels[0] = labels[0].next
1074
+ sig_free(label)
1075
+ if labels == &(parent[0].labels) and not labels[0] and parent[0].number == 0:
1076
+ # here we need to delete an "empty" binary tree node
1077
+ self._del_arc_unsafe(u, v, old_parent)
1078
+
1079
+ cdef int del_arc_label_unsafe(self, int u, int v, int l) except -1:
1080
+ """
1081
+ Delete an arc (u, v) with label l.
1082
+
1083
+ INPUT:
1084
+
1085
+ - ``u``, ``v`` -- integers from `0`, ..., `n-1`, where `n` is the
1086
+ number of vertices
1087
+
1088
+ - ``l`` -- positive integer label, or zero for no label
1089
+
1090
+ OUTPUT: one of
1091
+
1092
+ - ``0`` -- no error
1093
+
1094
+ - ``1`` -- no arc with label ``l``
1095
+ """
1096
+ if self._del_arc_label_unsafe(u, v, l, self.vertices):
1097
+ return 1 # indicate an error
1098
+
1099
+ if u != v or self.is_directed():
1100
+ # We remove the reverse copy only if u != v or graph is directed.
1101
+ self._del_arc_label_unsafe(v, u, l, self.vertices_rev)
1102
+ if self.vertices == self.vertices_rev:
1103
+ # In case of an undirected graph, we have removed two arcs.
1104
+ self.in_degrees[u] -= 1
1105
+ self.out_degrees[v] -= 1
1106
+ self.num_arcs -= 1
1107
+
1108
+ self.in_degrees[v] -= 1
1109
+ self.out_degrees[u] -= 1
1110
+ self.num_arcs -= 1
1111
+
1112
+ cdef int has_arc_label_unsafe(self, int u, int v, int l) except -1:
1113
+ """
1114
+ Indicates whether there is an arc (u, v) with label l.
1115
+
1116
+ INPUT:
1117
+
1118
+ - ``u``, ``v`` -- integers from `0`, ..., `n-1`, where `n` is the
1119
+ number of vertices
1120
+
1121
+ - ``l`` -- positive integer label, or zero for no label, or ``-1`` for any label
1122
+
1123
+ OUTPUT: one of
1124
+
1125
+ - ``0`` -- false
1126
+
1127
+ - ``1`` -- true
1128
+ """
1129
+ cdef int i = (u * self.hash_length) + (v & self.hash_mask)
1130
+ cdef int compared
1131
+ cdef SparseGraphBTNode *temp = self.vertices[i]
1132
+ cdef SparseGraphLLNode *label
1133
+ while temp:
1134
+ compared = compare(temp.vertex, v)
1135
+ if compared > 0:
1136
+ temp = temp.left
1137
+ elif compared < 0:
1138
+ temp = temp.right
1139
+ else: # if temp.vertex == v:
1140
+ break
1141
+ if not temp:
1142
+ return 0
1143
+ if l == -1:
1144
+ return 1
1145
+ if l == 0 and temp.number > 0:
1146
+ return 1
1147
+ label = temp.labels
1148
+ while label:
1149
+ if label.label == l:
1150
+ return 1
1151
+ label = label.next
1152
+ return 0
1153
+
1154
+
1155
+ ##############################
1156
+ # Further tests. Unit tests for methods, functions, classes defined with cdef.
1157
+ ##############################
1158
+
1159
+ def _test_adjacency_sequence_out():
1160
+ """
1161
+ Randomly test the method ``SparseGraph.adjacency_sequence_out()``. No output
1162
+ indicates that no errors were found.
1163
+
1164
+ TESTS::
1165
+
1166
+ sage: from sage.graphs.base.sparse_graph import _test_adjacency_sequence_out
1167
+ sage: _test_adjacency_sequence_out() # long time
1168
+ """
1169
+ from sage.graphs.digraph import DiGraph
1170
+ from sage.graphs.graph_generators import GraphGenerators
1171
+ from sage.misc.prandom import randint, random
1172
+ low = 0
1173
+ high = 1000
1174
+ n = 0
1175
+ while not n:
1176
+ randg = DiGraph(GraphGenerators().RandomGNP(randint(low, high), random()))
1177
+ n = randg.order()
1178
+ # set all labels to 0
1179
+ E = [(u, v, 0) for u, v in randg.edges(sort=True, labels=False)]
1180
+ cdef SparseGraph g = SparseGraph(n,
1181
+ verts=randg.vertices(sort=False),
1182
+ arcs=E)
1183
+ assert g.num_verts == randg.order(), (
1184
+ "Graph order mismatch: %s vs. %s" % (g.num_verts, randg.order()))
1185
+ assert g.num_arcs == randg.size(), (
1186
+ "Graph size mismatch: %s vs. %s" % (g.num_arcs, randg.size()))
1187
+ M = randg.adjacency_matrix()
1188
+ cdef int *V = <int *>check_allocarray(n, sizeof(int))
1189
+ cdef int i = 0
1190
+ for v in randg.vertex_iterator():
1191
+ V[i] = v
1192
+ i += 1
1193
+ cdef int *seq = <int *>check_allocarray(n, sizeof(int))
1194
+ for i in range(randint(50, 101)):
1195
+ u = randint(low, n - 1)
1196
+ g.adjacency_sequence_out(n, V, u, seq)
1197
+ A = [seq[k] for k in range(n)]
1198
+ try:
1199
+ assert A == list(M[u])
1200
+ except AssertionError:
1201
+ sig_free(V)
1202
+ sig_free(seq)
1203
+ raise AssertionError("Graph adjacency mismatch")
1204
+ sig_free(seq)
1205
+ sig_free(V)
1206
+
1207
+
1208
+ ###########################################
1209
+ # Sparse Graph Backend
1210
+ ###########################################
1211
+
1212
+ cdef class SparseGraphBackend(CGraphBackend):
1213
+ """
1214
+ Backend for Sage graphs using SparseGraphs.
1215
+
1216
+ ::
1217
+
1218
+ sage: from sage.graphs.base.sparse_graph import SparseGraphBackend
1219
+
1220
+ This class is only intended for use by the Sage Graph and DiGraph class.
1221
+ If you are interested in using a SparseGraph, you probably want to do
1222
+ something like the following example, which creates a Sage Graph instance
1223
+ which wraps a SparseGraph object::
1224
+
1225
+ sage: G = Graph(30, sparse=True)
1226
+ sage: G.add_edges([(0,1), (0,3), (4,5), (9, 23)])
1227
+ sage: G.edges(sort=True, labels=False)
1228
+ [(0, 1), (0, 3), (4, 5), (9, 23)]
1229
+
1230
+ Note that Sage graphs using the backend are more flexible than SparseGraphs
1231
+ themselves. This is because SparseGraphs (by design) do not deal with Python
1232
+ objects::
1233
+
1234
+ sage: G.add_vertex((0,1,2))
1235
+ sage: sorted(list(G),
1236
+ ....: key=lambda x: (isinstance(x, tuple), x))
1237
+ [0,
1238
+ ...
1239
+ 29,
1240
+ (0, 1, 2)]
1241
+ sage: from sage.graphs.base.sparse_graph import SparseGraph
1242
+ sage: SG = SparseGraph(30)
1243
+ sage: SG.add_vertex((0,1,2))
1244
+ Traceback (most recent call last):
1245
+ ...
1246
+ TypeError: an integer is required
1247
+ """
1248
+
1249
+ def __init__(self, int n, directed=True):
1250
+ """
1251
+ Initialize a sparse graph with n vertices.
1252
+
1253
+ EXAMPLES::
1254
+
1255
+ sage: D = sage.graphs.base.sparse_graph.SparseGraphBackend(9)
1256
+ sage: D.add_edge(0,1,None,False)
1257
+ sage: list(D.iterator_edges(range(9), True))
1258
+ [(0, 1, None)]
1259
+ """
1260
+ self._cg = SparseGraph(n, directed=directed)
1261
+ self._directed = directed
1262
+ self.vertex_labels = {}
1263
+ self.vertex_ints = {}
1264
+ self.edge_labels = {}
1265
+ self.edge_labels_max = 1
1266
+ self.edge_labels_available_ids = []
1267
+
1268
+ cdef inline int new_edge_label(self, object l) except -1:
1269
+ """
1270
+ Return a new unique int representing the arbitrary label l.
1271
+ """
1272
+ if l is None:
1273
+ return 0
1274
+
1275
+ cdef int l_int
1276
+ if self.edge_labels_available_ids:
1277
+ l_int = self.edge_labels_available_ids.pop(-1)
1278
+ else:
1279
+ l_int = self.edge_labels_max
1280
+ self.edge_labels_max += 1
1281
+
1282
+ self.edge_labels[l_int] = l
1283
+ return l_int
1284
+
1285
+ cdef inline int free_edge_label(self, int l_int) except -1:
1286
+ """
1287
+ Free the label corresponding to ``l_int``.
1288
+
1289
+ Usually called after deleting an edge.
1290
+ """
1291
+ if l_int:
1292
+ self.edge_labels.pop(l_int)
1293
+ self.edge_labels_available_ids.append(l_int)
1294
+
1295
+ def get_edge_label(self, object u, object v):
1296
+ """
1297
+ Return the edge label for ``(u, v)``.
1298
+
1299
+ INPUT:
1300
+
1301
+ - ``u``, ``v`` -- the vertices of the edge
1302
+
1303
+ EXAMPLES::
1304
+
1305
+ sage: D = sage.graphs.base.sparse_graph.SparseGraphBackend(9)
1306
+ sage: D.add_edges([(0,1,1), (2,3,2), (4,5,3), (5,6,2)], False)
1307
+ sage: list(D.iterator_edges(range(9), True))
1308
+ [(0, 1, 1), (2, 3, 2), (4, 5, 3), (5, 6, 2)]
1309
+ sage: D.get_edge_label(3,2)
1310
+ 2
1311
+ """
1312
+ cdef int l_int
1313
+ if not self.has_vertex(u):
1314
+ raise LookupError("({0}) is not a vertex of the graph.".format(repr(u)))
1315
+ if not self.has_vertex(v):
1316
+ raise LookupError("({0}) is not a vertex of the graph.".format(repr(v)))
1317
+ cdef int u_int = self.get_vertex(u)
1318
+ cdef int v_int = self.get_vertex(v)
1319
+ if not self._cg.has_arc_unsafe(u_int, v_int):
1320
+ raise LookupError("({0}, {1}) is not an edge of the graph.".format(repr(u), repr(v)))
1321
+ if self.multiple_edges(None):
1322
+ return [self.edge_labels[l_int] if l_int != 0 else None
1323
+ for l_int in self._cg.all_arcs(u_int, v_int)]
1324
+ l_int = self._cg.arc_label(u_int, v_int)
1325
+ return self.edge_labels[l_int] if l_int else None
1326
+
1327
+ def has_edge(self, object u, object v, object l):
1328
+ """
1329
+ Return whether this graph has edge ``(u,v)`` with label ``l``. If ``l``
1330
+ is ``None``, return whether this graph has an edge ``(u,v)`` with any
1331
+ label.
1332
+
1333
+ INPUT:
1334
+
1335
+ - ``u``, ``v`` -- the vertices of the edge
1336
+
1337
+ - ``l`` -- the edge label, or ``None``
1338
+
1339
+ EXAMPLES::
1340
+
1341
+ sage: D = sage.graphs.base.sparse_graph.SparseGraphBackend(9)
1342
+ sage: D.add_edges([(0,1), (2,3), (4,5), (5,6)], False)
1343
+ sage: D.has_edge(0,1,None)
1344
+ True
1345
+ """
1346
+ cdef int u_int = self.get_vertex_checked(u)
1347
+ cdef int v_int = self.get_vertex_checked(v)
1348
+ if u_int == -1 or v_int == -1:
1349
+ return False
1350
+ return self._has_labeled_edge_unsafe(u_int, v_int, l)
1351
+
1352
+ cdef inline bint _has_labeled_edge_unsafe(self, int u_int, int v_int, object l) except -1:
1353
+ """
1354
+ Return whether ``self`` has an arc specified by indices of the vertices
1355
+ and an arc label.
1356
+ """
1357
+ cdef SparseGraph cg = self.cg()
1358
+ if l is None:
1359
+ return 1 == cg.has_arc_unsafe(u_int, v_int)
1360
+ cdef SparseGraphLLNode* label = cg.arc_labels_unsafe(u_int, v_int)
1361
+ while label:
1362
+ if label.label and self.edge_labels[label.label] == l:
1363
+ return True
1364
+ label = label.next
1365
+ return False
1366
+
1367
+ def multiple_edges(self, new):
1368
+ """
1369
+ Get/set whether or not ``self`` allows multiple edges.
1370
+
1371
+ INPUT:
1372
+
1373
+ - ``new`` -- boolean (to set) or ``None`` (to get)
1374
+
1375
+ EXAMPLES::
1376
+
1377
+ sage: G = sage.graphs.base.sparse_graph.SparseGraphBackend(9)
1378
+ sage: G.multiple_edges(True)
1379
+ sage: G.multiple_edges(None)
1380
+ True
1381
+ sage: G.multiple_edges(False)
1382
+ sage: G.multiple_edges(None)
1383
+ False
1384
+ sage: G.add_edge(0,1,0,True)
1385
+ sage: G.add_edge(0,1,0,True)
1386
+ sage: list(G.iterator_out_edges(range(9), True))
1387
+ [(0, 1, 0)]
1388
+ """
1389
+ if new is None:
1390
+ return self._multiple_edges
1391
+ self._multiple_edges = bool(new)
1392
+
1393
+ def set_edge_label(self, object u, object v, object l, bint directed):
1394
+ """
1395
+ Label the edge ``(u,v)`` by ``l``.
1396
+
1397
+ INPUT:
1398
+
1399
+ - ``u``, ``v`` -- the vertices of the edge
1400
+
1401
+ - ``l`` -- the edge label
1402
+
1403
+ - ``directed`` -- if ``False``, also set ``(v,u)`` with label ``l``
1404
+
1405
+ EXAMPLES::
1406
+
1407
+ sage: G = sage.graphs.base.sparse_graph.SparseGraphBackend(9)
1408
+ sage: G.add_edge(1,2,None,True)
1409
+ sage: G.set_edge_label(1,2,'a',True)
1410
+ sage: list(G.iterator_out_edges(range(9), True))
1411
+ [(1, 2, 'a')]
1412
+
1413
+ Note that it fails silently if there is no edge there::
1414
+
1415
+ sage: G.set_edge_label(2,1,'b',True)
1416
+ sage: list(G.iterator_out_edges(range(9), True))
1417
+ [(1, 2, 'a')]
1418
+ """
1419
+ if not self.has_edge(u, v, None):
1420
+ return
1421
+ if self.multiple_edges(None):
1422
+ if len(self.get_edge_label(u, v)) > 1:
1423
+ raise RuntimeError("Cannot set edge label, since there are multiple edges from %s to %s." % (u, v))
1424
+ # now we know there is exactly one edge from u to v
1425
+ cdef int l_int, ll_int
1426
+ if l is None:
1427
+ l_int = 0
1428
+ else:
1429
+ l_int = self.new_edge_label(l)
1430
+ cdef int u_int = self.get_vertex(u)
1431
+ cdef int v_int = self.get_vertex(v)
1432
+ if not (<SparseGraph>self._cg).has_arc_unsafe(u_int, v_int):
1433
+ return
1434
+ ll_int = (<SparseGraph>self._cg).arc_label_unsafe(u_int, v_int)
1435
+ if ll_int:
1436
+ self.edge_labels.pop(ll_int)
1437
+ self.edge_labels_available_ids.append(ll_int)
1438
+ self._cg.del_arc_label(u_int, v_int, ll_int)
1439
+ self._cg.add_arc_label(u_int, v_int, l_int)
1440
+ if not directed and self._directed and v_int != u_int:
1441
+ self._cg.del_arc_label(v_int, u_int, ll_int)
1442
+ self._cg.add_arc_label(v_int, u_int, l_int)
1443
+
1444
+ def _iterator_edges(self, object vertices, const bint labels, const int modus=0):
1445
+ """
1446
+ Iterate over the edges incident to a sequence of vertices.
1447
+
1448
+ INPUT:
1449
+
1450
+ - ``vertices`` -- a list of vertex labels
1451
+
1452
+ - ``labels`` -- boolean, whether to return labels as well
1453
+
1454
+ - ``modus`` -- integer representing the modus of the iterator:
1455
+ - ``0`` -- outgoing edges
1456
+ - ``1`` -- ingoing edges
1457
+ - ``2`` -- unsorted edges of an undirected graph
1458
+ - ``3`` -- sorted edges of an undirected graph
1459
+
1460
+ EXAMPLES::
1461
+
1462
+ sage: G = sage.graphs.base.dense_graph.DenseGraphBackend(9)
1463
+ sage: G.add_edge(1, 2, None, False)
1464
+ sage: list(G._iterator_edges(range(9), False, 3))
1465
+ [(1, 2)]
1466
+ sage: list(G._iterator_edges(range(9), True, 3))
1467
+ [(1, 2, None)]
1468
+
1469
+ ::
1470
+
1471
+ sage: G = sage.graphs.base.dense_graph.DenseGraphBackend(9)
1472
+ sage: G.add_edge(1, 2, None, True)
1473
+ sage: list(G.iterator_in_edges([1], False))
1474
+ []
1475
+ sage: list(G.iterator_in_edges([2], False))
1476
+ [(1, 2)]
1477
+ sage: list(G.iterator_in_edges([2], True))
1478
+ [(1, 2, None)]
1479
+
1480
+ ::
1481
+
1482
+ sage: G = sage.graphs.base.dense_graph.DenseGraphBackend(9)
1483
+ sage: G.add_edge(1, 2, None, True)
1484
+ sage: list(G.iterator_out_edges([2], False))
1485
+ []
1486
+ sage: list(G.iterator_out_edges([1], False))
1487
+ [(1, 2)]
1488
+ sage: list(G.iterator_out_edges([1], True))
1489
+ [(1, 2, None)]
1490
+ """
1491
+ cdef object u, v, l, v_copy
1492
+ cdef int u_int, v_int, l_int, foo
1493
+ cdef CGraph cg = self.cg()
1494
+ cdef list b_vertices_2, all_arc_labels
1495
+ cdef FrozenBitset b_vertices
1496
+ cdef bint out = modus == 0
1497
+
1498
+ cdef int vertices_case
1499
+ cdef object it
1500
+
1501
+ cdef int r
1502
+ cdef int maxdegree = 0
1503
+ cdef int *degrees = NULL
1504
+ if out:
1505
+ degrees = cg.out_degrees
1506
+ else:
1507
+ degrees = cg.in_degrees
1508
+ for v_int in range(cg.active_vertices.size):
1509
+ if bitset_in(cg.active_vertices, v_int):
1510
+ maxdegree = max(degrees[v_int], maxdegree)
1511
+ cdef MemoryAllocator mem = MemoryAllocator()
1512
+ cdef SparseGraphBTNode **neighbors = <SparseGraphBTNode **>mem.allocarray(maxdegree, sizeof(SparseGraphBTNode *))
1513
+
1514
+ if not isinstance(vertices, list):
1515
+ # ALL edges
1516
+ it = self.iterator_verts(None)
1517
+ vertices_case = 0
1518
+
1519
+ elif not vertices:
1520
+ return
1521
+
1522
+ elif len(vertices) == 1:
1523
+ # One vertex
1524
+ vertices_case = 1
1525
+ v_int = -1
1526
+
1527
+ else:
1528
+ # Several vertices (nonempty list)
1529
+ vertices_case = 2
1530
+ b_vertices_2 = [self.get_vertex_checked(v) for v in vertices]
1531
+ try:
1532
+ b_vertices = FrozenBitset(foo for foo in b_vertices_2 if foo >= 0)
1533
+ except ValueError:
1534
+ # Avoiding "Bitset must not be empty"
1535
+ # in case none of the vertices is active.
1536
+ return
1537
+ it = iter(b_vertices)
1538
+
1539
+ while True:
1540
+ # Think of this as a loop through ``vertices``.
1541
+ # We pick the next vertex according to three cases.
1542
+
1543
+ if vertices_case == 0:
1544
+ # ALL edges
1545
+ try:
1546
+ v = next(it)
1547
+ v_int = self.get_vertex(v)
1548
+ except StopIteration:
1549
+ return
1550
+
1551
+ elif vertices_case == 1:
1552
+ # One vertex
1553
+ if v_int != -1:
1554
+ # Only visit one vertex once.
1555
+ return
1556
+ v = vertices[0]
1557
+ v_int = self.get_vertex_checked(v)
1558
+ if v_int == -1:
1559
+ return
1560
+
1561
+ else:
1562
+ # Several vertices (nonempty list)
1563
+ try:
1564
+ v_int = -1
1565
+ while v_int == -1:
1566
+ v_int = next(it)
1567
+ v = self.vertex_label(v_int)
1568
+ except StopIteration:
1569
+ return
1570
+
1571
+ # WARNING
1572
+ # If you modify this, you must keep in mind the documentation in the
1573
+ # corresponding method in ``generic_graph.py`` in the method ``edge_iterator``.
1574
+ # E.g. code assumes that you can use an iterator to relabel or delete arcs.
1575
+
1576
+ r = self._cg._neighbors_BTNode_unsafe(v_int, out, neighbors, maxdegree)
1577
+ for i in range(r):
1578
+ u_int = neighbors[i].vertex
1579
+ if neighbors[i].number:
1580
+ l_int = 0
1581
+ else:
1582
+ l_int = neighbors[i].labels.label
1583
+ if (modus < 2 or # Do not delete duplicates.
1584
+ vertices_case == 1 or # Only one vertex, so no duplicates.
1585
+ u_int >= v_int or # We visit if u_int >= v_int ...
1586
+ (vertices_case == 2 and
1587
+ u_int < b_vertices.capacity() and
1588
+ not bitset_in(b_vertices._bitset, u_int))): # ... or if u_int is not in ``vertices``.
1589
+ u = self.vertex_label(u_int)
1590
+ if labels:
1591
+ l = self.edge_labels[l_int] if l_int else None
1592
+
1593
+ # Yield the arc/arcs.
1594
+ v_copy = v
1595
+ if _reorganize_edge(v, u, modus):
1596
+ u, v = v, u
1597
+
1598
+ if not self._multiple_edges:
1599
+ if labels:
1600
+ yield (v, u, l)
1601
+ else:
1602
+ yield (v, u)
1603
+ else:
1604
+ if out:
1605
+ all_arc_labels = cg.all_arcs(v_int, u_int)
1606
+ else:
1607
+ all_arc_labels = cg.all_arcs(u_int, v_int)
1608
+
1609
+ for l_int in all_arc_labels:
1610
+ if labels:
1611
+ l = self.edge_labels[l_int] if l_int else None
1612
+ yield (v, u, l)
1613
+ else:
1614
+ yield (v, u)
1615
+ v = v_copy
1616
+
1617
+ ##############################
1618
+ # Functions to simplify edge iterator.
1619
+ ##############################
1620
+
1621
+ cdef inline bint _reorganize_edge(object v, object u, const int modus) noexcept:
1622
+ """
1623
+ Return ``True`` if ``v`` and ``u`` should be exchanged according to the modus.
1624
+
1625
+ INPUT:
1626
+
1627
+ - ``v`` -- vertex
1628
+
1629
+ - ``u`` -- vertex
1630
+
1631
+ - ``modus`` -- integer representing the modus of the iterator:
1632
+ - ``0`` -- outgoing edges
1633
+ - ``1`` -- ingoing edges
1634
+ - ``2`` -- unsorted edges of an undirected graph
1635
+ - ``3`` -- sorted edges of an undirected graph
1636
+
1637
+ OUTPUT: Boolean according the modus:
1638
+
1639
+ - ``modus == 0`` -- ``False``
1640
+ - ``modus == 1`` -- ``True``
1641
+ - ``modus == 2`` -- ``True
1642
+ - ``modus == 3`` -- ``False if v <= u else True``
1643
+ """
1644
+ if modus == 0:
1645
+ return False
1646
+ elif modus == 3:
1647
+ try:
1648
+ if v <= u:
1649
+ return False
1650
+ except TypeError:
1651
+ pass
1652
+
1653
+ return True