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.
- passagemath_graphs-10.6.1rc1.dist-info/METADATA +292 -0
- passagemath_graphs-10.6.1rc1.dist-info/RECORD +260 -0
- passagemath_graphs-10.6.1rc1.dist-info/WHEEL +5 -0
- passagemath_graphs-10.6.1rc1.dist-info/top_level.txt +2 -0
- passagemath_graphs.libs/libgcc_s-69c45f16.so.1 +0 -0
- passagemath_graphs.libs/libgmp-8e78bd9b.so.10.5.0 +0 -0
- passagemath_graphs.libs/libstdc++-1f1a71be.so.6.0.33 +0 -0
- sage/all__sagemath_graphs.py +39 -0
- sage/combinat/abstract_tree.py +2723 -0
- sage/combinat/all__sagemath_graphs.py +34 -0
- sage/combinat/binary_tree.py +5306 -0
- sage/combinat/cluster_algebra_quiver/all.py +22 -0
- sage/combinat/cluster_algebra_quiver/cluster_seed.py +5208 -0
- sage/combinat/cluster_algebra_quiver/interact.py +124 -0
- sage/combinat/cluster_algebra_quiver/mutation_class.py +625 -0
- sage/combinat/cluster_algebra_quiver/mutation_type.py +1555 -0
- sage/combinat/cluster_algebra_quiver/quiver.py +2290 -0
- sage/combinat/cluster_algebra_quiver/quiver_mutation_type.py +2468 -0
- sage/combinat/designs/MOLS_handbook_data.py +570 -0
- sage/combinat/designs/all.py +58 -0
- sage/combinat/designs/bibd.py +1655 -0
- sage/combinat/designs/block_design.py +1071 -0
- sage/combinat/designs/covering_array.py +269 -0
- sage/combinat/designs/covering_design.py +530 -0
- sage/combinat/designs/database.py +5615 -0
- sage/combinat/designs/design_catalog.py +122 -0
- sage/combinat/designs/designs_pyx.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/combinat/designs/designs_pyx.pxd +21 -0
- sage/combinat/designs/designs_pyx.pyx +993 -0
- sage/combinat/designs/difference_family.py +3951 -0
- sage/combinat/designs/difference_matrices.py +279 -0
- sage/combinat/designs/evenly_distributed_sets.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/combinat/designs/evenly_distributed_sets.pyx +661 -0
- sage/combinat/designs/ext_rep.py +1064 -0
- sage/combinat/designs/gen_quadrangles_with_spread.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/combinat/designs/gen_quadrangles_with_spread.pyx +339 -0
- sage/combinat/designs/group_divisible_designs.py +361 -0
- sage/combinat/designs/incidence_structures.py +2357 -0
- sage/combinat/designs/latin_squares.py +581 -0
- sage/combinat/designs/orthogonal_arrays.py +2244 -0
- sage/combinat/designs/orthogonal_arrays_build_recursive.py +1780 -0
- sage/combinat/designs/orthogonal_arrays_find_recursive.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/combinat/designs/orthogonal_arrays_find_recursive.pyx +967 -0
- sage/combinat/designs/resolvable_bibd.py +815 -0
- sage/combinat/designs/steiner_quadruple_systems.py +1306 -0
- sage/combinat/designs/subhypergraph_search.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/combinat/designs/subhypergraph_search.pyx +530 -0
- sage/combinat/designs/twographs.py +306 -0
- sage/combinat/finite_state_machine.py +14874 -0
- sage/combinat/finite_state_machine_generators.py +2006 -0
- sage/combinat/graph_path.py +448 -0
- sage/combinat/interval_posets.py +3908 -0
- sage/combinat/nu_tamari_lattice.py +269 -0
- sage/combinat/ordered_tree.py +1446 -0
- sage/combinat/posets/all.py +46 -0
- sage/combinat/posets/bubble_shuffle.py +247 -0
- sage/combinat/posets/cartesian_product.py +493 -0
- sage/combinat/posets/d_complete.py +182 -0
- sage/combinat/posets/elements.py +273 -0
- sage/combinat/posets/forest.py +30 -0
- sage/combinat/posets/hasse_cython.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/combinat/posets/hasse_cython.pyx +174 -0
- sage/combinat/posets/hasse_diagram.py +3672 -0
- sage/combinat/posets/hochschild_lattice.py +158 -0
- sage/combinat/posets/incidence_algebras.py +794 -0
- sage/combinat/posets/lattices.py +5117 -0
- sage/combinat/posets/linear_extension_iterator.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/combinat/posets/linear_extension_iterator.pyx +292 -0
- sage/combinat/posets/linear_extensions.py +1037 -0
- sage/combinat/posets/mobile.py +275 -0
- sage/combinat/posets/moebius_algebra.py +776 -0
- sage/combinat/posets/poset_examples.py +2178 -0
- sage/combinat/posets/posets.py +9360 -0
- sage/combinat/rooted_tree.py +1070 -0
- sage/combinat/shard_order.py +239 -0
- sage/combinat/tamari_lattices.py +384 -0
- sage/combinat/yang_baxter_graph.py +923 -0
- sage/databases/all__sagemath_graphs.py +1 -0
- sage/databases/knotinfo_db.py +1231 -0
- sage/ext_data/all__sagemath_graphs.py +1 -0
- sage/ext_data/graphs/graph_plot_js.html +330 -0
- sage/ext_data/kenzo/CP2.txt +45 -0
- sage/ext_data/kenzo/CP3.txt +349 -0
- sage/ext_data/kenzo/CP4.txt +4774 -0
- sage/ext_data/kenzo/README.txt +49 -0
- sage/ext_data/kenzo/S4.txt +20 -0
- sage/graphs/all.py +42 -0
- sage/graphs/asteroidal_triples.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/asteroidal_triples.pyx +320 -0
- sage/graphs/base/all.py +1 -0
- sage/graphs/base/boost_graph.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/base/boost_graph.pxd +106 -0
- sage/graphs/base/boost_graph.pyx +3045 -0
- sage/graphs/base/c_graph.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/base/c_graph.pxd +106 -0
- sage/graphs/base/c_graph.pyx +5096 -0
- sage/graphs/base/dense_graph.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/base/dense_graph.pxd +28 -0
- sage/graphs/base/dense_graph.pyx +801 -0
- sage/graphs/base/graph_backends.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/base/graph_backends.pxd +5 -0
- sage/graphs/base/graph_backends.pyx +797 -0
- sage/graphs/base/overview.py +85 -0
- sage/graphs/base/sparse_graph.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/base/sparse_graph.pxd +90 -0
- sage/graphs/base/sparse_graph.pyx +1653 -0
- sage/graphs/base/static_dense_graph.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/base/static_dense_graph.pxd +5 -0
- sage/graphs/base/static_dense_graph.pyx +1032 -0
- sage/graphs/base/static_sparse_backend.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/base/static_sparse_backend.pxd +27 -0
- sage/graphs/base/static_sparse_backend.pyx +1583 -0
- sage/graphs/base/static_sparse_graph.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/base/static_sparse_graph.pxd +37 -0
- sage/graphs/base/static_sparse_graph.pyx +1375 -0
- sage/graphs/bipartite_graph.py +2732 -0
- sage/graphs/centrality.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/centrality.pyx +1038 -0
- sage/graphs/cographs.py +519 -0
- sage/graphs/comparability.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/comparability.pyx +851 -0
- sage/graphs/connectivity.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/connectivity.pxd +157 -0
- sage/graphs/connectivity.pyx +4813 -0
- sage/graphs/convexity_properties.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/convexity_properties.pxd +16 -0
- sage/graphs/convexity_properties.pyx +870 -0
- sage/graphs/digraph.py +4754 -0
- sage/graphs/digraph_generators.py +1993 -0
- sage/graphs/distances_all_pairs.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/distances_all_pairs.pxd +12 -0
- sage/graphs/distances_all_pairs.pyx +2938 -0
- sage/graphs/domination.py +1363 -0
- sage/graphs/dot2tex_utils.py +100 -0
- sage/graphs/edge_connectivity.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/edge_connectivity.pyx +1215 -0
- sage/graphs/generators/all.py +1 -0
- sage/graphs/generators/basic.py +1769 -0
- sage/graphs/generators/chessboard.py +538 -0
- sage/graphs/generators/classical_geometries.py +1611 -0
- sage/graphs/generators/degree_sequence.py +235 -0
- sage/graphs/generators/distance_regular.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/generators/distance_regular.pyx +2846 -0
- sage/graphs/generators/families.py +4759 -0
- sage/graphs/generators/intersection.py +565 -0
- sage/graphs/generators/platonic_solids.py +262 -0
- sage/graphs/generators/random.py +2623 -0
- sage/graphs/generators/smallgraphs.py +5741 -0
- sage/graphs/generators/world_map.py +724 -0
- sage/graphs/generic_graph.py +26867 -0
- sage/graphs/generic_graph_pyx.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/generic_graph_pyx.pxd +34 -0
- sage/graphs/generic_graph_pyx.pyx +1673 -0
- sage/graphs/genus.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/genus.pyx +622 -0
- sage/graphs/graph.py +9645 -0
- sage/graphs/graph_coloring.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_coloring.pyx +2284 -0
- sage/graphs/graph_database.py +1177 -0
- sage/graphs/graph_decompositions/all.py +1 -0
- sage/graphs/graph_decompositions/bandwidth.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_decompositions/bandwidth.pyx +428 -0
- sage/graphs/graph_decompositions/clique_separators.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_decompositions/clique_separators.pyx +616 -0
- sage/graphs/graph_decompositions/cutwidth.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_decompositions/cutwidth.pyx +753 -0
- sage/graphs/graph_decompositions/fast_digraph.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_decompositions/fast_digraph.pxd +13 -0
- sage/graphs/graph_decompositions/fast_digraph.pyx +212 -0
- sage/graphs/graph_decompositions/graph_products.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_decompositions/graph_products.pyx +508 -0
- sage/graphs/graph_decompositions/modular_decomposition.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_decompositions/modular_decomposition.pxd +27 -0
- sage/graphs/graph_decompositions/modular_decomposition.pyx +1536 -0
- sage/graphs/graph_decompositions/slice_decomposition.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_decompositions/slice_decomposition.pxd +18 -0
- sage/graphs/graph_decompositions/slice_decomposition.pyx +1106 -0
- sage/graphs/graph_decompositions/tree_decomposition.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_decompositions/tree_decomposition.pxd +17 -0
- sage/graphs/graph_decompositions/tree_decomposition.pyx +1996 -0
- sage/graphs/graph_decompositions/vertex_separation.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_decompositions/vertex_separation.pxd +5 -0
- sage/graphs/graph_decompositions/vertex_separation.pyx +1963 -0
- sage/graphs/graph_editor.py +82 -0
- sage/graphs/graph_generators.py +3314 -0
- sage/graphs/graph_generators_pyx.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_generators_pyx.pyx +95 -0
- sage/graphs/graph_input.py +812 -0
- sage/graphs/graph_latex.py +2064 -0
- sage/graphs/graph_list.py +410 -0
- sage/graphs/graph_plot.py +1756 -0
- sage/graphs/graph_plot_js.py +338 -0
- sage/graphs/hyperbolicity.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/hyperbolicity.pyx +1704 -0
- sage/graphs/hypergraph_generators.py +364 -0
- sage/graphs/independent_sets.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/independent_sets.pxd +13 -0
- sage/graphs/independent_sets.pyx +402 -0
- sage/graphs/isgci.py +1033 -0
- sage/graphs/isoperimetric_inequalities.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/isoperimetric_inequalities.pyx +489 -0
- sage/graphs/line_graph.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/line_graph.pyx +743 -0
- sage/graphs/lovasz_theta.py +77 -0
- sage/graphs/matching.py +1633 -0
- sage/graphs/matching_covered_graph.py +3590 -0
- sage/graphs/orientations.py +1489 -0
- sage/graphs/partial_cube.py +459 -0
- sage/graphs/path_enumeration.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/path_enumeration.pyx +2040 -0
- sage/graphs/pq_trees.py +1129 -0
- sage/graphs/print_graphs.py +201 -0
- sage/graphs/schnyder.py +865 -0
- sage/graphs/spanning_tree.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/spanning_tree.pyx +1457 -0
- sage/graphs/strongly_regular_db.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/strongly_regular_db.pyx +3340 -0
- sage/graphs/traversals.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/traversals.pxd +9 -0
- sage/graphs/traversals.pyx +1872 -0
- sage/graphs/trees.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/trees.pxd +15 -0
- sage/graphs/trees.pyx +310 -0
- sage/graphs/tutte_polynomial.py +713 -0
- sage/graphs/views.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/views.pyx +794 -0
- sage/graphs/weakly_chordal.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/weakly_chordal.pyx +604 -0
- sage/groups/all__sagemath_graphs.py +1 -0
- sage/groups/perm_gps/all__sagemath_graphs.py +1 -0
- sage/groups/perm_gps/partn_ref/all__sagemath_graphs.py +1 -0
- sage/groups/perm_gps/partn_ref/refinement_graphs.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/groups/perm_gps/partn_ref/refinement_graphs.pxd +38 -0
- sage/groups/perm_gps/partn_ref/refinement_graphs.pyx +1666 -0
- sage/knots/all.py +6 -0
- sage/knots/free_knotinfo_monoid.py +507 -0
- sage/knots/gauss_code.py +291 -0
- sage/knots/knot.py +682 -0
- sage/knots/knot_table.py +284 -0
- sage/knots/knotinfo.py +2900 -0
- sage/knots/link.py +4715 -0
- sage/sandpiles/all.py +13 -0
- sage/sandpiles/examples.py +225 -0
- sage/sandpiles/sandpile.py +6365 -0
- sage/topology/all.py +22 -0
- sage/topology/cell_complex.py +1214 -0
- sage/topology/cubical_complex.py +1976 -0
- sage/topology/delta_complex.py +1806 -0
- sage/topology/filtered_simplicial_complex.py +744 -0
- sage/topology/moment_angle_complex.py +823 -0
- sage/topology/simplicial_complex.py +5160 -0
- sage/topology/simplicial_complex_catalog.py +92 -0
- sage/topology/simplicial_complex_examples.py +1680 -0
- sage/topology/simplicial_complex_homset.py +205 -0
- sage/topology/simplicial_complex_morphism.py +836 -0
- sage/topology/simplicial_set.py +4102 -0
- sage/topology/simplicial_set_catalog.py +55 -0
- sage/topology/simplicial_set_constructions.py +2954 -0
- sage/topology/simplicial_set_examples.py +865 -0
- 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')
|