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,1215 @@
1
+ # sage_setup: distribution = sagemath-graphs
2
+ # cython: binding=True
3
+ # distutils: language = c++
4
+ r"""
5
+ Edge connectivity
6
+
7
+ This module implements methods for computing the edge-connectivity of graphs and
8
+ digraphs. It also implements methods to extract `k` edge-disjoint spanning trees
9
+ from a `2k` edge-connected graph or a `k` edge-connected digraph.
10
+
11
+ .. TODO::
12
+
13
+ - Implement the tree-packing algorithms proposed in [Gabow1995]_ and
14
+ [BHKP2008]_
15
+ - Extend to digraphs with multiple edges
16
+ - Extend to weighted digraphs
17
+ """
18
+ # ****************************************************************************
19
+ # Copyright (c) 2022 David Coudert <david.coudert@inria.fr>
20
+ #
21
+ # This program is free software: you can redistribute it and/or modify
22
+ # it under the terms of the GNU General Public License as published by
23
+ # the Free Software Foundation, either version 2 of the License, or
24
+ # (at your option) any later version.
25
+ # https://www.gnu.org/licenses/
26
+ # ****************************************************************************
27
+
28
+ from memory_allocator cimport MemoryAllocator
29
+ from cysignals.signals cimport sig_check
30
+ from sage.graphs.generic_graph_pyx cimport GenericGraph_pyx
31
+ from libc.limits cimport INT_MAX
32
+ from libcpp.pair cimport pair
33
+ from libcpp.vector cimport vector
34
+ from libcpp.queue cimport queue
35
+
36
+
37
+ cdef class GabowEdgeConnectivity:
38
+ r"""
39
+ Gabow's algorithm for finding the edge connectivity of digraphs.
40
+
41
+ This class implements the algorithm proposed in [Gabow1995]_ for finding the
42
+ edge connectivity of a directed graph and `k` edge disjoint spanning trees
43
+ if the digraph is `k` edge connected.
44
+
45
+ .. WARNING::
46
+
47
+ Multiple edges are currently not supported. The current implementation
48
+ act as if the digraph is simple and so the return results might not be
49
+ correct. We therefore raise an error if the digraph has multiple edges.
50
+
51
+ INPUT:
52
+
53
+ - ``D`` -- a :class:`~sage.graphs.digraph.DiGraph`
54
+
55
+ EXAMPLES:
56
+
57
+ A random `d`-regular digraph is `d`-edge-connected::
58
+
59
+ sage: from sage.graphs.edge_connectivity import GabowEdgeConnectivity
60
+ sage: D = DiGraph(graphs.RandomRegular(6, 50)) # needs networkx
61
+ sage: while not D.is_strongly_connected(): # needs networkx
62
+ ....: D = DiGraph(graphs.RandomRegular(6, 50))
63
+ sage: GabowEdgeConnectivity(D).edge_connectivity() # needs networkx
64
+ 6
65
+
66
+ A complete digraph with `n` vertices is `n-1`-edge-connected::
67
+
68
+ sage: from sage.graphs.edge_connectivity import GabowEdgeConnectivity
69
+ sage: D = DiGraph(digraphs.Complete(10))
70
+ sage: GabowEdgeConnectivity(D, use_rec=True).edge_connectivity()
71
+ 9
72
+
73
+ Check that we get the same result when with and without the DFS-based
74
+ speed-up initialization proposed in [GKLP2021]_::
75
+
76
+ sage: # needs networkx
77
+ sage: G = graphs.RandomBarabasiAlbert(100, 2)
78
+ sage: D = DiGraph(G)
79
+ sage: ec1 = GabowEdgeConnectivity(D,
80
+ ....: dfs_preprocessing=False).edge_connectivity()
81
+ sage: ec2 = GabowEdgeConnectivity(D,
82
+ ....: dfs_preprocessing=True).edge_connectivity()
83
+ sage: ec3 = GabowEdgeConnectivity(D, dfs_preprocessing=True,
84
+ ....: use_rec=True).edge_connectivity()
85
+ sage: ec1 == ec2 and ec2 == ec3
86
+ True
87
+
88
+ TESTS:
89
+
90
+ :issue:`32169`::
91
+
92
+ sage: dig6_string = r'[E_S?_hKIH@eos[BSg???Q@FShGC?hTHUGM?IPug?'
93
+ sage: dig6_string += r'JOEYCdOzdkQGo@ADA@AAg?GAQW?'
94
+ sage: dig6_string += r'[aIaSwHYcD@qQb@Dd?\hJTI@OHlJ_?C_OEIKoeCR@_BC?Q?'
95
+ sage: dig6_string += r'?YBFosqITEA?IvCU_'
96
+ sage: D = DiGraph(dig6_string)
97
+ sage: GabowEdgeConnectivity(D).edge_connectivity()
98
+ 5
99
+ sage: GabowEdgeConnectivity(D).edge_disjoint_spanning_trees()
100
+ Traceback (most recent call last):
101
+ ...
102
+ NotImplementedError: this method has not been implemented yet
103
+
104
+ Corner cases::
105
+
106
+ sage: [GabowEdgeConnectivity(DiGraph(n)).edge_connectivity() for n in range(4)]
107
+ [0, 0, 0, 0]
108
+ sage: D = digraphs.Circuit(3) * 2
109
+ sage: D.add_edge(0, 3)
110
+ sage: GabowEdgeConnectivity(D).edge_connectivity()
111
+ 0
112
+ sage: D.add_edge(3, 0)
113
+ sage: GabowEdgeConnectivity(D).edge_connectivity()
114
+ 1
115
+
116
+ Looped digraphs are supported but not digraphs with multiple edges::
117
+
118
+ sage: D = digraphs.Complete(5, loops=True)
119
+ sage: GabowEdgeConnectivity(D).edge_connectivity()
120
+ 4
121
+ sage: D.allow_multiple_edges(True)
122
+ sage: D.add_edges(D.edges(sort=False))
123
+ sage: GabowEdgeConnectivity(D).edge_connectivity()
124
+ Traceback (most recent call last):
125
+ ...
126
+ ValueError: This method is not known to work on graphs with multiedges. ...
127
+ """
128
+ cdef MemoryAllocator mem
129
+ cdef Py_ssize_t n # number of nodes
130
+ cdef Py_ssize_t m # number of arcs
131
+
132
+ cdef int max_ec # upper bound on the edge connectivity
133
+ cdef int ec # current (proven) value of edge connectivity
134
+ cdef bint ec_checked # whether we have well computed edge connectivity
135
+
136
+ cdef int UNUSED
137
+ cdef int FIRSTEDGE
138
+
139
+ # The graph is stored as lists of incident edges
140
+ cdef readonly GenericGraph_pyx G # the original graph
141
+ cdef list int_to_vertex # mapping from integers to vertex labels
142
+ cdef vector[vector[int]] g_out
143
+ cdef vector[vector[int]] g_in
144
+ cdef vector[vector[int]] my_g # either g_out or g_in
145
+ cdef vector[vector[int]] my_g_reversed # either g_out or g_in
146
+
147
+ # values associated to edges
148
+ cdef int* tail # source of edge j
149
+ cdef int* head # target of edge j
150
+ cdef int* my_from # either tail or head
151
+ cdef int* my_to # either tail or head
152
+
153
+ cdef int* labels # label of each edge given by the labeling algorithm, UNUSED if unlabeled
154
+
155
+ cdef int* edge_state_1 # index of forest Ti to which belongs the arc j of g_out, UNUSED if not used
156
+ cdef int* edge_state_2 # index of forest Ti to which belongs the arc j of g_in, UNUSED if not used
157
+ cdef int* my_edge_state # either edge_state_1 or edge_state_2
158
+
159
+ # values associated to trees and forests
160
+ cdef int root_vertex # 0 by default
161
+ cdef int current_tree # index of the current tree
162
+ cdef int next_f_tree
163
+ cdef int augmenting_root
164
+ cdef bint* tree_flag # indicate whether a tree Ti has been touched
165
+ cdef int* root # current root vertex of f_tree i
166
+ cdef int* L_roots # L_roots of the trees
167
+ cdef bint* forests # indicate whether the f_tree is active or inactive
168
+ cdef bint** labeled #
169
+
170
+ cdef int** parent_1 # parent of v in tree/forest Ti
171
+ cdef int** parent_2 # parent of v in tree/forest Ti
172
+ cdef int** my_parent # either parent_1 or parent_2
173
+ cdef int** parent_edge_id_1 # edge id of parent of v in tree/forest Ti
174
+ cdef int** parent_edge_id_2 # edge id of parent of v in tree/forest Ti
175
+ cdef int** my_parent_edge_id # either parent_edge_id_1 or parent_edge_id_2
176
+ cdef int** depth_1 # depth of v in tree/forest Ti
177
+ cdef int** depth_2 # depth of v in tree/forest Ti
178
+ cdef int** my_depth # either depth_1 or depth_2
179
+
180
+ # to store a path
181
+ cdef vector[int] A_path
182
+ cdef vector[int] left_traverse
183
+ cdef vector[int] right_traverse
184
+
185
+ cdef bint* seen # for method re_init
186
+ cdef int* stack # stack of vertices for DFS in re_init
187
+ cdef vector[vector[int]] tree_edges # used to organise the edges of the trees
188
+ cdef vector[vector[int]] F # used to store a proven k-intersection (copy of tree_edges)
189
+ cdef vector[vector[int]] tree_edges_incident # lists of incident edges of a given tree
190
+
191
+ cdef queue[int] my_Q # queue of labeled edges
192
+ cdef queue[pair[int, int]] joining_edges # queue of tuples (edge id, edge state)
193
+ cdef queue[int] incident_edges_Q # queue of edges
194
+
195
+ cdef int num_start_f_trees # number of f-trees at the beginning of an iteration
196
+ cdef int num_joins # number of joined vertices from dfs
197
+ cdef bint* T # whether an edge is in the proven k-intersection
198
+ cdef bint* visited # for method find_dfs_tree
199
+ cdef int * incident_edge_index # used for DFS initialization
200
+ cdef bint dfs_preprocessing # whether to use DFS-based fast initialization
201
+ cdef bint use_rec # whether to use the recursive DFS initialization
202
+
203
+ def __init__(self, G, dfs_preprocessing=True, use_rec=False):
204
+ r"""
205
+ Initialize this object.
206
+
207
+ INPUT:
208
+
209
+ - ``G`` -- a :class:`~sage.graphs.digraph.DiGraph`
210
+
211
+ - ``dfs_preprocessing`` -- boolean (default: ``True``); whether to use
212
+ the DFS-based speed-up initialization proposed in [GKLP2021]_
213
+
214
+ - ``use_rec`` -- boolean (default: ``False``); whether to use a
215
+ recursive or non-recursive DFS for ``dfs_preprocessing``. The
216
+ recursive DFS tends to be faster than the non-recursive version on
217
+ complete digraphs and slower on other graphs. This parameter is
218
+ ignored when ``dfs_preprocessing`` is ``False``.
219
+
220
+ EXAMPLES::
221
+
222
+ sage: from sage.graphs.edge_connectivity import GabowEdgeConnectivity
223
+ sage: D = digraphs.Complete(5)
224
+ sage: GabowEdgeConnectivity(D).edge_connectivity()
225
+ 4
226
+ """
227
+ self.dfs_preprocessing = dfs_preprocessing
228
+ self.use_rec = use_rec
229
+ self.ec_checked = False
230
+ from sage.graphs.digraph import DiGraph
231
+ if not isinstance(G, DiGraph):
232
+ raise ValueError("this method is for directed graphs only")
233
+ G._scream_if_not_simple(allow_loops=True)
234
+ if G.size() > INT_MAX - 2:
235
+ raise ValueError("the graph is too large for this code")
236
+
237
+ # Trivial cases
238
+ if not G or not G.is_strongly_connected():
239
+ self.ec = 0
240
+ self.ec_checked = True
241
+ self.F.clear()
242
+ return
243
+
244
+ #
245
+ # Initialize some data structures
246
+ #
247
+ self.G = <GenericGraph_pyx?>G
248
+ self.n = G.order()
249
+ self.m = G.size()
250
+ self.mem = MemoryAllocator()
251
+
252
+ # Build compact graph data structure with out and in adjacencies.
253
+ # Loops are removed from the graph.
254
+ self.build_graph_data_structure()
255
+ # From now on, vertices are numbered in [0..n-1] and edges in [0..m-1]
256
+ # where m is the number of edges after the removal of the loops
257
+
258
+ # Set upper bound on the edge connectivity
259
+ cdef int i, d
260
+ self.max_ec = INT_MAX
261
+ for i in range(self.n):
262
+ d = self.g_out[i].size()
263
+ if d < self.max_ec:
264
+ self.max_ec = d
265
+ d = self.g_in[i].size()
266
+ if d < self.max_ec:
267
+ self.max_ec = d
268
+
269
+ self.labels = <int*>self.mem.calloc(self.m, sizeof(int))
270
+ self.tree_flag = <bint*>self.mem.calloc(self.max_ec, sizeof(bint))
271
+ self.forests = <bint*>self.mem.calloc(self.n, sizeof(bint))
272
+ self.L_roots = <int*>self.mem.calloc(self.max_ec, sizeof(int))
273
+ self.labeled = <bint**>self.mem.calloc(self.max_ec, sizeof(bint*))
274
+ self.seen = <bint*>self.mem.calloc(self.n, sizeof(bint))
275
+ self.root = <int*>self.mem.calloc(self.n, sizeof(int))
276
+ self.edge_state_1 = <int*>self.mem.calloc(self.m, sizeof(int))
277
+ self.edge_state_2 = <int*>self.mem.calloc(self.m, sizeof(int))
278
+ self.parent_1 = <int**>self.mem.calloc(self.max_ec, sizeof(int*))
279
+ self.parent_2 = <int**>self.mem.calloc(self.max_ec, sizeof(int*))
280
+ self.parent_edge_id_1 = <int**>self.mem.calloc(self.max_ec, sizeof(int*))
281
+ self.parent_edge_id_2 = <int**>self.mem.calloc(self.max_ec, sizeof(int*))
282
+ self.depth_1 = <int**>self.mem.calloc(self.max_ec, sizeof(int*))
283
+ self.depth_2 = <int**>self.mem.calloc(self.max_ec, sizeof(int*))
284
+ self.stack = <int*>self.mem.calloc(self.n, sizeof(int))
285
+ self.incident_edge_index = <int*>self.mem.calloc(self.n, sizeof(int))
286
+ self.tree_edges.resize(self.max_ec)
287
+ self.tree_edges_incident.resize(self.n)
288
+ self.T = <bint*>self.mem.calloc(self.m, sizeof(bint))
289
+ self.visited = <bint*>self.mem.calloc(self.n, sizeof(bint))
290
+
291
+ # Set some constants
292
+ self.UNUSED = INT_MAX
293
+ self.FIRSTEDGE = INT_MAX - 1
294
+
295
+ for i in range(self.m):
296
+ self.edge_state_1[i] = self.UNUSED # edge i is unused
297
+ self.edge_state_2[i] = self.UNUSED
298
+ self.labels[i] = self.UNUSED # edge i is unlabeled
299
+ self.T[i] = False # edge i doesn't belong to any k-intersection yet
300
+
301
+ _ = self.compute_edge_connectivity()
302
+ sig_check()
303
+
304
+ cdef build_graph_data_structure(self):
305
+ r"""
306
+ Build graph data structures.
307
+
308
+ We assign each arc (u, v) a unique id and store in arrays the tail/head
309
+ of each arc. We use vector of vectors to quickly access incident edges.
310
+
311
+ EXAMPLES::
312
+
313
+ sage: from sage.graphs.edge_connectivity import GabowEdgeConnectivity
314
+ sage: D = digraphs.Complete(5)
315
+ sage: GabowEdgeConnectivity(D).edge_connectivity()
316
+ 4
317
+ """
318
+ cdef int i
319
+ self.int_to_vertex = list(self.G)
320
+ cdef dict vertex_to_int = {u: i for i, u in enumerate(self.int_to_vertex)}
321
+
322
+ self.tail = <int*>self.mem.calloc(self.m, sizeof(int))
323
+ self.head = <int*>self.mem.calloc(self.m, sizeof(int))
324
+ self.g_out.resize(self.n)
325
+ self.g_in.resize(self.n)
326
+ for i in range(self.n):
327
+ self.g_out[i].clear()
328
+ self.g_in[i].clear()
329
+
330
+ cdef int x, y
331
+ cdef int e_id = 0
332
+ for x, u in enumerate(self.int_to_vertex):
333
+ for v in self.G.neighbor_out_iterator(u):
334
+ y = vertex_to_int[v]
335
+ if x != y:
336
+ self.g_out[x].push_back(e_id)
337
+ self.g_in[y].push_back(e_id)
338
+ self.tail[e_id] = x
339
+ self.head[e_id] = y
340
+ e_id += 1
341
+ # Loops have been removed, so we update the number of edges
342
+ self.m = e_id
343
+
344
+ cdef bint compute_edge_connectivity(self) except -1:
345
+ """
346
+ Compute the edge connectivity using Round Robin algorithm.
347
+
348
+ The method returns ``True`` if the computation ends normally. Otherwise
349
+ an exception is raised, for instance due to a keyboard interruption.
350
+
351
+ EXAMPLES::
352
+
353
+ sage: from sage.graphs.edge_connectivity import GabowEdgeConnectivity
354
+ sage: D = digraphs.Complete(5)
355
+ sage: GabowEdgeConnectivity(D).edge_connectivity()
356
+ 4
357
+ """
358
+ cdef int i
359
+
360
+ self.root_vertex = 0
361
+ self.next_f_tree = 0
362
+
363
+ # Search successively trees in g_in and g_out
364
+ self.ec = 0
365
+ for i in range(self.max_ec):
366
+ if self.construct_trees(False, i) and self.construct_trees(True, i):
367
+ # We found both an in-arborescence and an out-arborescence.
368
+ # So we can increase the edge connectivity
369
+ self.ec += 1
370
+ # and save the current k-intersection
371
+ self.save_current_k_intersection()
372
+ sig_check()
373
+ self.ec_checked = True
374
+ return True
375
+
376
+ cdef bint construct_trees(self, bint reverse, int tree) except -1:
377
+ r"""
378
+ Search for an in or out arborescence.
379
+
380
+ INPUT:
381
+
382
+ - ``reverse`` -- boolean; whether to search for an in-arborescence
383
+ (``True``) or an out-arborescence (``False``)
384
+
385
+ - ``tree`` -- integer; index of the tree
386
+
387
+ EXAMPLES::
388
+
389
+ sage: from sage.graphs.edge_connectivity import GabowEdgeConnectivity
390
+ sage: D = digraphs.Complete(5)
391
+ sage: GabowEdgeConnectivity(D).edge_connectivity()
392
+ 4
393
+ """
394
+ if reverse:
395
+ # Search for a spanning tree in g-reversed
396
+ self.my_g = self.g_out
397
+ self.my_g_reversed = self.g_in
398
+ self.my_from = self.head
399
+ self.my_to = self.tail
400
+ self.my_parent = self.parent_2
401
+ self.my_depth = self.depth_2
402
+ self.my_parent_edge_id = self.parent_edge_id_2
403
+ self.my_edge_state = self.edge_state_2
404
+ else:
405
+ # Search for a spanning tree in g using incoming arcs
406
+ self.my_g = self.g_in
407
+ self.my_g_reversed = self.g_out
408
+ self.my_from = self.tail
409
+ self.my_to = self.head
410
+ self.my_parent = self.parent_1
411
+ self.my_depth = self.depth_1
412
+ self.my_parent_edge_id = self.parent_edge_id_1
413
+ self.my_edge_state = self.edge_state_1
414
+
415
+ self.current_tree = tree
416
+ self.increase_memory_for_new_tree(tree)
417
+
418
+ cdef int njoins = 0
419
+ cdef int z
420
+
421
+ self.num_start_f_trees = self.n - self.num_joins
422
+ # There are fewer than n f-trees. We prepare to join them. If there's
423
+ # only one f-tree, we just save the edges and advance to the next
424
+ # iteration
425
+ if self.dfs_preprocessing and self.num_start_f_trees < self.n - 1:
426
+ self.re_init(tree)
427
+
428
+ # There are n f-trees, and we try to join them
429
+ while njoins < self.num_start_f_trees-1:
430
+ # Get the root of an active subtree or INT_MAX if none exists
431
+ z = self.choose_root()
432
+ while z != INT_MAX:
433
+ if self.search_joining(z):
434
+ # We have augmented the root of the corresponding f_tree
435
+ njoins += 1
436
+ else:
437
+ # We cannot find a tree
438
+ return False
439
+
440
+ z = self.choose_root()
441
+
442
+ # Trace the paths in order to transfer the edges to the appropriate
443
+ # tree Ti
444
+ self.augmentation_algorithm()
445
+ # Reinitialize data structures and make all f_trees active for next round
446
+ self.re_init(tree)
447
+ sig_check()
448
+
449
+ return True
450
+
451
+ cdef void increase_memory_for_new_tree(self, int tree) noexcept:
452
+ """
453
+ Allocate data structure for the new tree/forest.
454
+
455
+ This method also initializes data structures for this tree index. Data
456
+ structures for a given tree index are allocated only once.
457
+
458
+ INPUT:
459
+
460
+ - ``tree`` -- integer; index of the tree
461
+
462
+ EXAMPLES::
463
+
464
+ sage: from sage.graphs.edge_connectivity import GabowEdgeConnectivity
465
+ sage: D = digraphs.Complete(5)
466
+ sage: GabowEdgeConnectivity(D).edge_connectivity()
467
+ 4
468
+ """
469
+ if not self.labeled[tree]:
470
+ self.labeled[tree] = <bint*>self.mem.calloc(self.n, sizeof(bint))
471
+ if not self.my_parent[tree]:
472
+ self.my_parent[tree] = <int*>self.mem.calloc(self.n, sizeof(int))
473
+ if not self.my_depth[tree]:
474
+ self.my_depth[tree] = <int*>self.mem.calloc(self.n, sizeof(int))
475
+ if not self.my_parent_edge_id[tree]:
476
+ self.my_parent_edge_id[tree] = <int*>self.mem.calloc(self.n, sizeof(int))
477
+
478
+ cdef int j
479
+ for j in range(self.n):
480
+ self.my_parent[tree][j] = 0
481
+ self.my_parent_edge_id[tree][j] = self.UNUSED
482
+ self.my_depth[tree][j] = 0
483
+ self.labeled[tree][j] = False
484
+ self.root[j] = j
485
+ self.forests[j] = True
486
+
487
+ self.num_joins = 0
488
+
489
+ # Initialize T_k to be a DFS spanning forest of G \ T
490
+ if self.dfs_preprocessing:
491
+ self.compute_dfs_tree()
492
+
493
+ # Set inactive the f-trees of the root vertex
494
+ self.forests[self.root_vertex] = False
495
+
496
+ self.L_roots[tree] = self.UNUSED
497
+ self.tree_flag[tree] = False
498
+
499
+ cdef void compute_dfs_tree(self) noexcept:
500
+ r"""
501
+ Find a DFS spanning forest of `G \backslash T`.
502
+
503
+ This is the DFS-based speed-up initialization proposed in [GKLP2021]_.
504
+
505
+ EXAMPLES::
506
+
507
+ sage: from sage.graphs.edge_connectivity import GabowEdgeConnectivity
508
+ sage: D = digraphs.Complete(5)
509
+ sage: GabowEdgeConnectivity(D, dfs_preprocessing=True).edge_connectivity()
510
+ 4
511
+ sage: GabowEdgeConnectivity(D, dfs_preprocessing=False).edge_connectivity()
512
+ 4
513
+ """
514
+ # Mark all vertices as unvisited
515
+ cdef int i
516
+ for i in range(self.n):
517
+ self.visited[i] = False
518
+
519
+ cdef int r
520
+ for r in range(self.n):
521
+ if not self.visited[r]:
522
+ # Make this vertex the root of the following dfs tree
523
+ self.root[r] = r
524
+ # Make the f-tree rooted at this vertex active
525
+ self.forests[r] = True
526
+ # Find connected vertices of the f-tree rooted at r
527
+ if self.use_rec:
528
+ self.find_dfs_tree_rec(r, r)
529
+ else:
530
+ self.find_dfs_tree(r)
531
+ # Each call of find_dfs_tree creates an f-tree
532
+ self.num_start_f_trees += 1
533
+
534
+ cdef void find_dfs_tree(self, int r) noexcept:
535
+ r"""
536
+ Find more vertices of the f-tree rooted at `r`.
537
+
538
+ This is part of the DFS-based speed-up initialization proposed in
539
+ [GKLP2021]_.
540
+
541
+ EXAMPLES::
542
+
543
+ sage: from sage.graphs.edge_connectivity import GabowEdgeConnectivity
544
+ sage: D = digraphs.Complete(5)
545
+ sage: GabowEdgeConnectivity(D, dfs_preprocessing=True, use_rec=False).edge_connectivity()
546
+ 4
547
+ """
548
+ cdef int u, v, e_id
549
+ cdef int * stack = self.stack
550
+ cdef int * edge_index = self.incident_edge_index
551
+ # We initialize the stack and mark the root as visited
552
+ cdef int t = 0 # index pointing to the top of the stack
553
+ stack[0] = r
554
+ edge_index[r] = self.my_g_reversed[r].size()
555
+ self.visited[r] = True
556
+
557
+ while t >= 0:
558
+ u = stack[t]
559
+ if edge_index[u]:
560
+ # Visit the next incident edge of u
561
+ edge_index[u] -= 1
562
+ e_id = self.my_g_reversed[u][edge_index[u]]
563
+ if not self.T[e_id]:
564
+ v = self.my_to[e_id]
565
+ if not self.visited[v] and v != self.root_vertex:
566
+ # Make v belong to the f-tree rooted at r
567
+ self.root[v] = r
568
+ self.forests[v] = False
569
+ self.my_edge_state[e_id] = self.current_tree
570
+ self.num_joins += 1
571
+ self.visited[v] = True
572
+ # add v to the stack
573
+ t += 1
574
+ stack[t] = v
575
+ edge_index[v] = self.my_g_reversed[v].size()
576
+ # and proceed with v
577
+ else:
578
+ # We are done with u. We pop.
579
+ t -= 1
580
+
581
+ cdef void find_dfs_tree_rec(self, int u, int r) noexcept:
582
+ r"""
583
+ Find more vertices of the f-tree rooted at `r`.
584
+
585
+ This is part of the DFS-based speed-up initialization proposed in
586
+ [GKLP2021]_.
587
+
588
+ EXAMPLES::
589
+
590
+ sage: from sage.graphs.edge_connectivity import GabowEdgeConnectivity
591
+ sage: D = digraphs.Complete(5)
592
+ sage: GabowEdgeConnectivity(D, dfs_preprocessing=True, use_rec=True).edge_connectivity()
593
+ 4
594
+ """
595
+ # Mark vertex u as visited to avoid visiting it multiple times
596
+ self.visited[u] = True
597
+
598
+ # Visit outgoing arcs of current vertex
599
+ cdef int e_id, v
600
+ for e_id in self.my_g_reversed[u]:
601
+ v = self.my_to[e_id]
602
+ # Ensure a vertex is not visited, is not a proven k-intersection edge
603
+ # and root_vertex remains deficient
604
+ if not self.visited[v] and not self.T[e_id] and v != self.root_vertex:
605
+ # Make current vertex belong to the f_tree rooted at r
606
+ self.root[v] = r
607
+ self.forests[v] = False
608
+ self.my_edge_state[e_id] = self.current_tree
609
+ self.num_joins += 1
610
+ # recursively find more vertices and grow the subtree rooted at r
611
+ self.find_dfs_tree_rec(v, r)
612
+
613
+ cdef int choose_root(self) noexcept:
614
+ """
615
+ Return the root of an active f_tree, or INT_MAX if none exists.
616
+
617
+ EXAMPLES::
618
+
619
+ sage: from sage.graphs.edge_connectivity import GabowEdgeConnectivity
620
+ sage: D = digraphs.Complete(5)
621
+ sage: GabowEdgeConnectivity(D).edge_connectivity()
622
+ 4
623
+ """
624
+ cdef int v
625
+ cdef int i
626
+
627
+ for i in range(self.next_f_tree, self.n):
628
+ v = self.root[i]
629
+ if self.forests[v]:
630
+ # this forest is active
631
+ self.next_f_tree = i + 1
632
+ return v
633
+ return INT_MAX
634
+
635
+ cdef bint search_joining(self, int x) except -1:
636
+ """
637
+ Try to augment the f_tree rooted at x.
638
+
639
+ EXAMPLES::
640
+
641
+ sage: from sage.graphs.edge_connectivity import GabowEdgeConnectivity
642
+ sage: D = digraphs.Complete(5)
643
+ sage: GabowEdgeConnectivity(D).edge_connectivity()
644
+ 4
645
+ """
646
+ cdef int y
647
+ cdef int joining_edge
648
+ cdef int e_id, ep
649
+
650
+ # Store the vertex that is about to be augmented
651
+ self.augmenting_root = x
652
+
653
+ # Consider the incoming arcs of x
654
+ for e_id in self.my_g[x]:
655
+ y = self.my_from[e_id]
656
+ # find the root of the f_tree
657
+ y = self.root[y]
658
+
659
+ if self.my_edge_state[e_id] == self.UNUSED:
660
+ # The edge is available
661
+ if x != y:
662
+ # ... and the f_trees have different roots. We set the
663
+ # label of edges in the queue to UNUSED and clear the queue
664
+ while not self.my_Q.empty():
665
+ ep = self.my_Q.front()
666
+ self.my_Q.pop()
667
+ self.labels[ep] = self.UNUSED
668
+ # We then assign the edge to the current_tree
669
+ self.join(e_id)
670
+ return True
671
+ else:
672
+ # The f_trees have the same root (cycle).
673
+ # We add the edge to the queue
674
+ self.my_Q.push(e_id)
675
+ # and indicate the first edge of the path
676
+ self.labels[e_id] = self.FIRSTEDGE
677
+
678
+ # If we did not find a free joining edge, we check for a sequence of
679
+ # swaps in order to free a joining edge
680
+
681
+ # Initialize the L_i tree of every T_i with vertex x and make x labeled
682
+ cdef int i
683
+ for i in range(self.current_tree + 1):
684
+ self.L_roots[i] = x
685
+ self.labeled[i][x] = True
686
+
687
+ # Start cycle_scanning algorithm
688
+ joining_edge = self.next_joining_edge_step()
689
+ sig_check()
690
+
691
+ if joining_edge != INT_MAX:
692
+ # We found a joining edge
693
+ self.joining_edges.push((joining_edge, self.my_edge_state[joining_edge]))
694
+ self.join(joining_edge)
695
+ return True
696
+ return False
697
+
698
+ cdef void join(self, int e_id) noexcept:
699
+ """
700
+ Assign edge e_id to current tree.
701
+
702
+ This method joins 2 f_trees and updates the root of the new f_tree.
703
+
704
+ EXAMPLES::
705
+
706
+ sage: from sage.graphs.edge_connectivity import GabowEdgeConnectivity
707
+ sage: D = digraphs.Complete(5)
708
+ sage: GabowEdgeConnectivity(D).edge_connectivity()
709
+ 4
710
+ """
711
+ cdef int x = self.my_from[e_id]
712
+ cdef int y = self.my_to[e_id]
713
+ cdef int root_x = self.root[x]
714
+ cdef int root_y = self.root[y]
715
+
716
+ # Add the edge to the current tree
717
+ self.my_edge_state[e_id] = self.current_tree
718
+
719
+ # Make the 2 joined f_trees inactive
720
+ self.forests[root_x] = False
721
+ self.forests[root_y] = False
722
+
723
+ # Update the root of the joining f_tree
724
+ if self.augmenting_root == root_y:
725
+ self.root[root_y] = self.root[root_x]
726
+ else:
727
+ self.root[root_x] = self.root[root_y]
728
+
729
+ # Empty the queue
730
+ while not self.my_Q.empty():
731
+ self.my_Q.pop()
732
+
733
+ cdef int next_joining_edge_step(self) except -1:
734
+ """
735
+ Process edges in the queue and start labeling until the queue is empty
736
+ or a joining edge is found.
737
+
738
+ EXAMPLES::
739
+
740
+ sage: from sage.graphs.edge_connectivity import GabowEdgeConnectivity
741
+ sage: D = digraphs.Complete(5)
742
+ sage: GabowEdgeConnectivity(D).edge_connectivity()
743
+ 4
744
+ """
745
+ cdef int e_id
746
+ cdef int found_joining
747
+ cdef int tree = 0
748
+
749
+ while not self.my_Q.empty():
750
+ e_id = self.my_Q.front()
751
+ self.my_Q.pop()
752
+
753
+ if self.my_edge_state[e_id] == tree:
754
+ # edge e_id is in Ti
755
+ tree += 1
756
+ if tree > self.current_tree:
757
+ tree = 0
758
+
759
+ self.tree_flag[tree] = True
760
+
761
+ # Search for the fundamental cycle of e_id in Ti
762
+ found_joining = self.fundamental_cycle_step(e_id, tree)
763
+ sig_check()
764
+ if found_joining != INT_MAX:
765
+ return found_joining
766
+
767
+ return INT_MAX
768
+
769
+ cdef int fundamental_cycle_step(self, int e_id, int tree) except -1:
770
+ """
771
+ Traverse tree paths from the endpoints of edge e_id to build A_path
772
+
773
+ EXAMPLES::
774
+
775
+ sage: from sage.graphs.edge_connectivity import GabowEdgeConnectivity
776
+ sage: D = digraphs.Complete(5)
777
+ sage: GabowEdgeConnectivity(D).edge_connectivity()
778
+ 4
779
+ """
780
+ cdef int x = self.my_to[e_id]
781
+ cdef int y = self.my_from[e_id]
782
+ cdef bint left_first = True
783
+
784
+ if self.labeled[tree][x]:
785
+ # Node x is labeled. We go to the root of Li
786
+ x = self.L_roots[tree]
787
+ elif not self.labeled[tree][y]:
788
+ raise ValueError("error in labeling")
789
+ if self.labeled[tree][y]:
790
+ # Node y is labeled. We go to the root of Li
791
+ y = self.L_roots[tree]
792
+ left_first = False
793
+ if x == y:
794
+ # The fundamental cycle contains no unlabeled edge
795
+ return INT_MAX
796
+
797
+ cdef bint stop = False
798
+ cdef int q
799
+ cdef vector[int] left_traverse
800
+ cdef vector[int] right_traverse
801
+ left_traverse.clear()
802
+ right_traverse.clear()
803
+
804
+ # Start double traversal
805
+ while True:
806
+
807
+ while self.my_depth[tree][x] >= self.my_depth[tree][y]:
808
+ self.labeled[tree][x] = True
809
+ q = self.my_parent_edge_id[tree][x]
810
+ if q == self.UNUSED:
811
+ raise ValueError("did not find the right edge")
812
+ # We check if edge q is unlabeled
813
+ if self.labels[q] == self.UNUSED:
814
+ # If so, we place it in left_traverse array
815
+ left_traverse.push_back(q)
816
+ if self.is_joining_edge(q):
817
+ self.labels[q] = e_id
818
+ return q
819
+ x = self.my_parent[tree][x]
820
+ else:
821
+ # Otherwise, we stop
822
+ stop = True
823
+ break
824
+ if x == y:
825
+ break
826
+
827
+ while self.my_depth[tree][y] > self.my_depth[tree][x]:
828
+ self.labeled[tree][y] = True
829
+ q = self.my_parent_edge_id[tree][y]
830
+ if q == self.UNUSED:
831
+ raise ValueError("did not find the right edge")
832
+ # We check if edge q is unlabeled
833
+ if self.labels[q] == self.UNUSED:
834
+ # If so, we place it in right_traverse array
835
+ right_traverse.push_back(q)
836
+ if self.is_joining_edge(q):
837
+ self.labels[q] = e_id
838
+ return q
839
+ y = self.my_parent[tree][y]
840
+ else:
841
+ # Otherwise, we stop
842
+ stop = True
843
+ break
844
+
845
+ if x == y or stop:
846
+ break
847
+
848
+ if x == y:
849
+ # Update the L_root of the tree
850
+ self.L_roots[tree] = x
851
+ self.labeled[tree][x] = True
852
+
853
+ # Compute A_path
854
+ self.A_path.clear()
855
+ if left_first:
856
+ for x in left_traverse:
857
+ self.A_path.push_back(x)
858
+ for x in range(right_traverse.size() - 1, -1, -1):
859
+ self.A_path.push_back(right_traverse[x])
860
+ else:
861
+ for x in right_traverse:
862
+ self.A_path.push_back(x)
863
+ for x in range(left_traverse.size() - 1, -1, -1):
864
+ self.A_path.push_back(left_traverse[x])
865
+
866
+ return self.label_A_path(e_id)
867
+
868
+ cdef bint is_joining_edge(self, int e_id) noexcept:
869
+ """
870
+ Check if edge e_id is joining.
871
+
872
+ EXAMPLES::
873
+
874
+ sage: from sage.graphs.edge_connectivity import GabowEdgeConnectivity
875
+ sage: D = digraphs.Complete(5)
876
+ sage: GabowEdgeConnectivity(D).edge_connectivity()
877
+ 4
878
+ """
879
+ cdef int root_x = self.root[self.my_from[e_id]]
880
+ cdef int root_y = self.root[self.my_to[e_id]]
881
+ return (root_x != root_y) and (root_x == self.augmenting_root or root_y == self.augmenting_root)
882
+
883
+ cdef int label_A_path(self, int e_id) noexcept:
884
+ """
885
+ Labels the incident unused edges as the label_A_step of the algorithm
886
+
887
+ EXAMPLES::
888
+
889
+ sage: from sage.graphs.edge_connectivity import GabowEdgeConnectivity
890
+ sage: D = digraphs.Complete(5)
891
+ sage: GabowEdgeConnectivity(D).edge_connectivity()
892
+ 4
893
+ """
894
+ cdef int e, ep
895
+
896
+ for e in self.A_path:
897
+ # Run label step with edge e and label e_id
898
+ if self.label_step(e, e_id):
899
+ return e
900
+
901
+ if self.any_unused_is_unlabeled(self.my_to[e]):
902
+ while not self.incident_edges_Q.empty():
903
+ ep = self.incident_edges_Q.front()
904
+ self.incident_edges_Q.pop()
905
+ if e != ep:
906
+ # Label each unused and unlabeled edge ep with e
907
+ if self.label_step(ep, e):
908
+ while not self.incident_edges_Q.empty():
909
+ self.incident_edges_Q.pop()
910
+ return ep
911
+
912
+ while not self.incident_edges_Q.empty():
913
+ self.incident_edges_Q.pop()
914
+
915
+ return INT_MAX
916
+
917
+ cdef bint label_step(self, int e_id, int e_label) noexcept:
918
+ """
919
+ Label edge e_id with e_label and check whether edge e_id is joining.
920
+
921
+ EXAMPLES::
922
+
923
+ sage: from sage.graphs.edge_connectivity import GabowEdgeConnectivity
924
+ sage: D = digraphs.Complete(5)
925
+ sage: GabowEdgeConnectivity(D).edge_connectivity()
926
+ 4
927
+ """
928
+ self.labels[e_id] = e_label
929
+
930
+ cdef int root_x = self.root[self.my_from[e_id]]
931
+ cdef int root_y = self.root[self.my_to[e_id]]
932
+
933
+ if root_x == root_y:
934
+ self.my_Q.push(e_id)
935
+ return False
936
+ # The roots are different. Check whether one of them is on the f_tree
937
+ return root_x == self.augmenting_root or root_y == self.augmenting_root
938
+
939
+ cdef bint any_unused_is_unlabeled(self, int x) noexcept:
940
+ """
941
+ Check if each unused edge directed to x is unlabeled
942
+
943
+ EXAMPLES::
944
+
945
+ sage: from sage.graphs.edge_connectivity import GabowEdgeConnectivity
946
+ sage: D = digraphs.Complete(5)
947
+ sage: GabowEdgeConnectivity(D).edge_connectivity()
948
+ 4
949
+ """
950
+ cdef int e_id
951
+ for e_id in self.my_g[x]:
952
+ if self.my_edge_state[e_id] == self.UNUSED:
953
+ if self.labels[e_id] != self.UNUSED:
954
+ return False
955
+ self.incident_edges_Q.push(e_id)
956
+
957
+ return True
958
+
959
+ cdef void augmentation_algorithm(self) noexcept:
960
+ """
961
+ Trace the path of the found joining edges
962
+
963
+ EXAMPLES::
964
+
965
+ sage: from sage.graphs.edge_connectivity import GabowEdgeConnectivity
966
+ sage: D = digraphs.Complete(5)
967
+ sage: GabowEdgeConnectivity(D).edge_connectivity()
968
+ 4
969
+ """
970
+ cdef int e_id, e_state
971
+ while not self.joining_edges.empty():
972
+ e_id, e_state = self.joining_edges.front()
973
+ self.joining_edges.pop()
974
+ self.trace_back(e_id, e_state)
975
+
976
+ cdef void trace_back(self, int e_id, int e_state) noexcept:
977
+ """
978
+ Trace the path of a joining edge and transfer the edges to the
979
+ appropriate tree Ti.
980
+
981
+ EXAMPLES::
982
+
983
+ sage: from sage.graphs.edge_connectivity import GabowEdgeConnectivity
984
+ sage: D = digraphs.Complete(5)
985
+ sage: GabowEdgeConnectivity(D).edge_connectivity()
986
+ 4
987
+ """
988
+ # Previous state (tree Ti or unused) of an edge
989
+ cdef int previous_state = self.FIRSTEDGE
990
+
991
+ cdef int tree
992
+ cdef int e = self.labels[e_id]
993
+ cdef int ep = self.labels[e]
994
+
995
+ if e_state == self.UNUSED:
996
+ tree = self.my_edge_state[e]
997
+ previous_state = self.my_edge_state[ep]
998
+
999
+ # Transfer edge ep to tree Ti and remove edge e
1000
+ self.my_edge_state[ep] = tree
1001
+ self.my_edge_state[e] = self.UNUSED
1002
+
1003
+ e = ep
1004
+ ep = self.labels[e]
1005
+ else:
1006
+ tree = e_state + 1
1007
+ if tree > self.current_tree:
1008
+ tree = 0
1009
+ e = e_id
1010
+ ep = self.labels[e]
1011
+
1012
+ # Transfer edges to the appropriate Ti
1013
+ while ep != self.FIRSTEDGE:
1014
+ tree -= 1
1015
+ if tree < 0:
1016
+ tree = self.current_tree
1017
+
1018
+ if previous_state == self.UNUSED:
1019
+ e = ep
1020
+ ep = self.labels[e]
1021
+ self.my_edge_state[e] = self.UNUSED
1022
+
1023
+ previous_state = self.my_edge_state[ep]
1024
+ self.my_edge_state[ep] = tree
1025
+ e = ep
1026
+ ep = self.labels[e]
1027
+
1028
+ cdef re_init(self, int tree):
1029
+ """
1030
+ Make f_trees active (except the f_tree of the root), update depths and
1031
+ parent values, and clear the labels.
1032
+
1033
+ This method is called at the end of each round of method
1034
+ construct_trees, right after the call to augmentation_algorithm.
1035
+
1036
+ EXAMPLES::
1037
+
1038
+ sage: from sage.graphs.edge_connectivity import GabowEdgeConnectivity
1039
+ sage: D = digraphs.Complete(5)
1040
+ sage: GabowEdgeConnectivity(D).edge_connectivity()
1041
+ 4
1042
+ """
1043
+ cdef int i, j
1044
+ for j in range(self.m):
1045
+ self.labels[j] = self.UNUSED
1046
+
1047
+ # Arrange the edges of each tree
1048
+ for j in range(tree + 1):
1049
+ if self.dfs_preprocessing:
1050
+ for e_id in self.tree_edges[j]:
1051
+ self.T[e_id] = False
1052
+ self.tree_edges[j].clear()
1053
+ for j in range(self.m):
1054
+ if self.my_edge_state[j] != self.UNUSED:
1055
+ self.tree_edges[self.my_edge_state[j]].push_back(j)
1056
+ if self.dfs_preprocessing:
1057
+ self.T[j] = True
1058
+
1059
+ for j in range(tree + 1):
1060
+ if not j or j == tree or self.tree_flag[j]:
1061
+ # Build adjacency lists of incident edges (ignore direction)
1062
+ for i in range(self.n):
1063
+ self.tree_edges_incident[i].clear()
1064
+ for i in self.tree_edges[j]:
1065
+ self.tree_edges_incident[self.my_from[i]].push_back(i)
1066
+ self.tree_edges_incident[self.my_to[i]].push_back(i)
1067
+
1068
+ self.update_parents_depths(j)
1069
+
1070
+ for i in range(tree + 1):
1071
+ self.L_roots[i] = self.UNUSED # clear the root of each Li
1072
+ self.tree_flag[i] = False
1073
+
1074
+ # Unlabel all nodes from every Ti
1075
+ for j in range(self.n):
1076
+ self.labeled[i][j] = False
1077
+
1078
+ self.next_f_tree = 0
1079
+
1080
+ # Finally, set active the roots of subtrees
1081
+ for i in range(self.n):
1082
+ j = self.root[i]
1083
+ if j != self.root_vertex:
1084
+ self.forests[j] = True
1085
+
1086
+ cdef void update_parents_depths(self, int tree) noexcept:
1087
+ """
1088
+ Update parents, depths, and, if current_tree is k, the vertex labels to
1089
+ the root of each f_tree.
1090
+
1091
+ EXAMPLES::
1092
+
1093
+ sage: from sage.graphs.edge_connectivity import GabowEdgeConnectivity
1094
+ sage: D = digraphs.Complete(5)
1095
+ sage: GabowEdgeConnectivity(D).edge_connectivity()
1096
+ 4
1097
+ """
1098
+ cdef int i, v
1099
+
1100
+ for i in range(self.n):
1101
+ self.my_parent[tree][i] = i
1102
+ self.my_depth[tree][i] = 0
1103
+ self.seen[i] = False
1104
+
1105
+ self.update_parents_dfs(tree, self.root_vertex)
1106
+
1107
+ if tree == self.current_tree:
1108
+ for i in range(self.n):
1109
+ v = self.root[i]
1110
+ if self.root[v] != v:
1111
+ v = self.root[v]
1112
+ if not self.seen[v]:
1113
+ self.update_parents_dfs(tree, v)
1114
+ self.root[i] = self.root[v]
1115
+
1116
+ cdef void update_parents_dfs(self, int tree, int x) noexcept:
1117
+ """
1118
+ Helper method for ``update_parents_depths``.
1119
+
1120
+ This method updates parents and depths in specified ``tree`` starting
1121
+ from vertex ``x`` in depth first search manner.
1122
+
1123
+ INPUT:
1124
+
1125
+ - ``tree`` -- integer; index of the tree in which to update data
1126
+
1127
+ - ``x`` -- integer; vertex from which to start the DFS
1128
+
1129
+ EXAMPLES::
1130
+
1131
+ sage: from sage.graphs.edge_connectivity import GabowEdgeConnectivity
1132
+ sage: D = digraphs.Complete(5)
1133
+ sage: GabowEdgeConnectivity(D).edge_connectivity()
1134
+ 4
1135
+ """
1136
+ cdef int u, v, e_id
1137
+ cdef int depth
1138
+ cdef int i = 1
1139
+ self.stack[0] = x
1140
+ self.seen[x] = True
1141
+
1142
+ while i > 0:
1143
+ i -= 1
1144
+ u = self.stack[i]
1145
+ depth = self.my_depth[tree][u] + 1
1146
+ for e_id in self.tree_edges_incident[u]:
1147
+ v = self.my_to[e_id]
1148
+ if v == u:
1149
+ v = self.my_from[e_id]
1150
+ if not self.seen[v]:
1151
+ self.stack[i] = v
1152
+ i += 1
1153
+ self.seen[v] = True
1154
+ self.my_parent[tree][v] = u
1155
+ self.my_parent_edge_id[tree][v] = e_id
1156
+ self.my_depth[tree][v] = depth
1157
+
1158
+ cdef void save_current_k_intersection(self) noexcept:
1159
+ """
1160
+ Save the current k-intersection.
1161
+
1162
+ This method is called each time the upper bound on the edge connectivity
1163
+ has been increased. The k-intersection will be used to extract the
1164
+ edge-disjoint spanning trees. If asking for the edge connectivity only,
1165
+ there is no need to call this method.
1166
+
1167
+ EXAMPLES::
1168
+
1169
+ sage: from sage.graphs.edge_connectivity import GabowEdgeConnectivity
1170
+ sage: D = digraphs.Complete(5)
1171
+ sage: GabowEdgeConnectivity(D).edge_connectivity()
1172
+ 4
1173
+ """
1174
+ cdef int i, j
1175
+ cdef int size = self.tree_edges.size()
1176
+ self.F.resize(size)
1177
+ for i in range(size):
1178
+ self.F[i].clear()
1179
+ for j in self.tree_edges[i]:
1180
+ self.F[i].push_back(j)
1181
+
1182
+ def edge_connectivity(self):
1183
+ """
1184
+ Return the edge connectivity of the digraph.
1185
+
1186
+ EXAMPLES::
1187
+
1188
+ sage: from sage.graphs.edge_connectivity import GabowEdgeConnectivity
1189
+ sage: D = digraphs.Complete(5)
1190
+ sage: GabowEdgeConnectivity(D).edge_connectivity()
1191
+ 4
1192
+ """
1193
+ if self.ec_checked:
1194
+ return self.ec
1195
+ raise ValueError("the value of the edge connectivity has not been "
1196
+ "properly computed. This may result from an interruption")
1197
+
1198
+ #
1199
+ # Packing arborescences
1200
+ #
1201
+
1202
+ def edge_disjoint_spanning_trees(self):
1203
+ r"""
1204
+ Iterator over the edge disjoint spanning trees.
1205
+
1206
+ EXAMPLES::
1207
+
1208
+ sage: from sage.graphs.edge_connectivity import GabowEdgeConnectivity
1209
+ sage: D = digraphs.Complete(5)
1210
+ sage: GabowEdgeConnectivity(D).edge_disjoint_spanning_trees()
1211
+ Traceback (most recent call last):
1212
+ ...
1213
+ NotImplementedError: this method has not been implemented yet
1214
+ """
1215
+ raise NotImplementedError('this method has not been implemented yet')