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
Binary file
|
@@ -0,0 +1,489 @@
|
|
1
|
+
# sage_setup: distribution = sagemath-graphs
|
2
|
+
# cython: binding = True
|
3
|
+
r"""
|
4
|
+
Isoperimetric inequalities
|
5
|
+
|
6
|
+
This module contains various functions to compute isoperimetric numbers
|
7
|
+
of a graph.
|
8
|
+
|
9
|
+
Authors:
|
10
|
+
|
11
|
+
- Peleg Michaeli
|
12
|
+
- Vincent Delecroix
|
13
|
+
"""
|
14
|
+
# ****************************************************************************
|
15
|
+
# Copyright (C) 2018 Vincent Delecroix <20100.delecroix@gmail.com>
|
16
|
+
#
|
17
|
+
# Distributed under the terms of the GNU General Public License (GPL)
|
18
|
+
# as published by the Free Software Foundation; either version 2 of
|
19
|
+
# the License, or (at your option) any later version.
|
20
|
+
# https://www.gnu.org/licenses/
|
21
|
+
# ****************************************************************************
|
22
|
+
|
23
|
+
|
24
|
+
from cysignals.signals cimport sig_on, sig_off
|
25
|
+
from cysignals.memory cimport check_malloc, sig_free
|
26
|
+
|
27
|
+
from sage.data_structures.binary_matrix cimport *
|
28
|
+
from sage.graphs.base.static_dense_graph cimport dense_graph_init
|
29
|
+
from sage.graphs.base.static_sparse_backend cimport StaticSparseCGraph
|
30
|
+
from sage.graphs.base.static_sparse_backend cimport StaticSparseBackend
|
31
|
+
from sage.graphs.base.static_sparse_graph cimport short_digraph, init_short_digraph, free_short_digraph
|
32
|
+
|
33
|
+
from sage.rings.infinity import Infinity
|
34
|
+
from sage.rings.rational_field import QQ
|
35
|
+
|
36
|
+
|
37
|
+
def cheeger_constant(g):
|
38
|
+
r"""
|
39
|
+
Return the cheeger constant of the graph.
|
40
|
+
|
41
|
+
The Cheeger constant of a graph `G = (V,E)` is the minimum of `|\partial S|
|
42
|
+
/ |Vol(S)|` where `Vol(S)` is the sum of degrees of element in `S`,
|
43
|
+
`\partial S` is the edge boundary of `S` (number of edges with one end in
|
44
|
+
`S` and one end in `V \setminus S`) and the minimum is taken over all
|
45
|
+
non-empty subsets `S` of vertices so that `|Vol(S)| \leq |E|`.
|
46
|
+
|
47
|
+
.. SEEALSO::
|
48
|
+
|
49
|
+
Alternative but similar quantities can be obtained via the methods
|
50
|
+
:meth:`edge_isoperimetric_number` and :meth:`vertex_isoperimetric_number`.
|
51
|
+
|
52
|
+
EXAMPLES::
|
53
|
+
|
54
|
+
sage: graphs.PetersenGraph().cheeger_constant()
|
55
|
+
1/3
|
56
|
+
|
57
|
+
The Cheeger constant of a cycle on `n` vertices is
|
58
|
+
`1/\lfloor n/2 \rfloor`::
|
59
|
+
|
60
|
+
sage: [graphs.CycleGraph(k).cheeger_constant() for k in range(2,10)]
|
61
|
+
[1, 1, 1/2, 1/2, 1/3, 1/3, 1/4, 1/4]
|
62
|
+
|
63
|
+
The Cheeger constant of a complete graph on `n` vertices is
|
64
|
+
`\lceil n/2 \rceil / (n-1)`::
|
65
|
+
|
66
|
+
sage: [graphs.CompleteGraph(k).cheeger_constant() for k in range(2,10)]
|
67
|
+
[1, 1, 2/3, 3/4, 3/5, 2/3, 4/7, 5/8]
|
68
|
+
|
69
|
+
For complete bipartite::
|
70
|
+
|
71
|
+
sage: [graphs.CompleteBipartiteGraph(i,j).cheeger_constant() for i in range(2,7) for j in range(2, i)]
|
72
|
+
[3/5, 1/2, 3/5, 5/9, 4/7, 5/9, 1/2, 5/9, 1/2, 5/9]
|
73
|
+
|
74
|
+
More examples::
|
75
|
+
|
76
|
+
sage: G = Graph([(0, 1), (0, 3), (0, 8), (1, 4), (1, 6), (2, 4), (2, 7), (2, 9),
|
77
|
+
....: (3, 6), (3, 8), (4, 9), (5, 6), (5, 7), (5, 8), (7, 9)])
|
78
|
+
sage: G.cheeger_constant()
|
79
|
+
1/6
|
80
|
+
|
81
|
+
sage: G = Graph([(0, 1), (0, 2), (1, 2), (1, 3), (1, 4), (1, 5), (2, 3), (3, 4), (3, 5)])
|
82
|
+
sage: G.cheeger_constant()
|
83
|
+
1/2
|
84
|
+
|
85
|
+
sage: Graph([[1,2,3,4],[(1,2),(3,4)]]).cheeger_constant()
|
86
|
+
0
|
87
|
+
|
88
|
+
TESTS::
|
89
|
+
|
90
|
+
sage: graphs.EmptyGraph().cheeger_constant()
|
91
|
+
Traceback (most recent call last):
|
92
|
+
...
|
93
|
+
ValueError: Cheeger constant is not defined for the empty graph
|
94
|
+
|
95
|
+
Immutable graph::
|
96
|
+
|
97
|
+
sage: G = graphs.RandomGNP(10, .7)
|
98
|
+
sage: G._backend
|
99
|
+
<sage.graphs.base.sparse_graph.SparseGraphBackend ...>
|
100
|
+
sage: H = Graph(G, immutable=True)
|
101
|
+
sage: H._backend
|
102
|
+
<sage.graphs.base.static_sparse_backend.StaticSparseBackend ...>
|
103
|
+
sage: G.cheeger_constant() == H.cheeger_constant()
|
104
|
+
True
|
105
|
+
"""
|
106
|
+
if g.is_directed():
|
107
|
+
raise ValueError("Cheeger constant is only defined on non-oriented graph")
|
108
|
+
g._scream_if_not_simple()
|
109
|
+
if g.num_verts() == 0:
|
110
|
+
raise ValueError("Cheeger constant is not defined for the empty graph")
|
111
|
+
elif g.num_verts() == 1:
|
112
|
+
return Infinity
|
113
|
+
elif not g.is_connected():
|
114
|
+
return QQ.zero()
|
115
|
+
|
116
|
+
cdef StaticSparseCGraph cg
|
117
|
+
cdef short_digraph sd # a copy of the graph g
|
118
|
+
cdef int * subgraph # vertices of the subgraph (stack)
|
119
|
+
cdef int * bitsubgraph # vertices of the subgraph (bit array of +1 (in) or -1 (not in))
|
120
|
+
cdef int k = 0 # number of vertices in subgraph
|
121
|
+
cdef int vol = 0 # number of edges in the subgraph
|
122
|
+
cdef int boundary = 0 # number of edges in the boundary
|
123
|
+
cdef int u = 0 # current vertex
|
124
|
+
cdef unsigned long bmin = 1 # value of boundary for the min
|
125
|
+
cdef unsigned long vmin = 1 # value of the volume for the min
|
126
|
+
cdef int i
|
127
|
+
|
128
|
+
if isinstance(g, StaticSparseBackend):
|
129
|
+
cg = <StaticSparseCGraph> g._cg
|
130
|
+
sd = <short_digraph> cg.g
|
131
|
+
else:
|
132
|
+
init_short_digraph(sd, g, edge_labelled=False, vertex_list=list(g))
|
133
|
+
|
134
|
+
subgraph = <int *> check_malloc(sd.n * sizeof(int))
|
135
|
+
bitsubgraph = <int *> check_malloc(sd.n * sizeof(int))
|
136
|
+
|
137
|
+
sig_on()
|
138
|
+
try:
|
139
|
+
for i in range(sd.n):
|
140
|
+
bitsubgraph[i] = -1
|
141
|
+
while True:
|
142
|
+
while True:
|
143
|
+
# add vertex u to the subgraph, update the boundary/volume
|
144
|
+
# we repeat the operation until we reach the maximum volume
|
145
|
+
# or have no more vertex available
|
146
|
+
for i in range(sd.neighbors[u+1] - sd.neighbors[u]):
|
147
|
+
boundary -= bitsubgraph[sd.neighbors[u][i]]
|
148
|
+
vol += 1
|
149
|
+
|
150
|
+
bitsubgraph[u] = 1
|
151
|
+
subgraph[k] = u
|
152
|
+
u += 1
|
153
|
+
k += 1
|
154
|
+
|
155
|
+
if vol > sd.m:
|
156
|
+
break
|
157
|
+
|
158
|
+
if boundary * vmin < bmin * vol:
|
159
|
+
bmin = boundary
|
160
|
+
vmin = vol
|
161
|
+
|
162
|
+
if u == sd.n:
|
163
|
+
break
|
164
|
+
|
165
|
+
# backtrack
|
166
|
+
k -= 1
|
167
|
+
u = subgraph[k]
|
168
|
+
|
169
|
+
bitsubgraph[u] = -1
|
170
|
+
for i in range(sd.neighbors[u+1] - sd.neighbors[u]):
|
171
|
+
boundary += bitsubgraph[sd.neighbors[u][i]]
|
172
|
+
vol -= 1
|
173
|
+
u += 1
|
174
|
+
|
175
|
+
if u == sd.n:
|
176
|
+
if k == 0:
|
177
|
+
# end of the loop
|
178
|
+
break
|
179
|
+
else:
|
180
|
+
# remove one more vertex in order to continue
|
181
|
+
k -= 1
|
182
|
+
u = subgraph[k]
|
183
|
+
|
184
|
+
bitsubgraph[u] = -1
|
185
|
+
for i in range(sd.neighbors[u+1] - sd.neighbors[u]):
|
186
|
+
boundary += bitsubgraph[sd.neighbors[u][i]]
|
187
|
+
vol -= 1
|
188
|
+
u += 1
|
189
|
+
return QQ((bmin, vmin))
|
190
|
+
|
191
|
+
finally:
|
192
|
+
if not isinstance(g, StaticSparseBackend):
|
193
|
+
free_short_digraph(sd)
|
194
|
+
sig_free(subgraph)
|
195
|
+
sig_free(bitsubgraph)
|
196
|
+
sig_off()
|
197
|
+
|
198
|
+
|
199
|
+
def edge_isoperimetric_number(g):
|
200
|
+
r"""
|
201
|
+
Return the edge-isoperimetric number of the graph.
|
202
|
+
|
203
|
+
The edge-isoperimetric number of a graph `G = (V,E)` is also sometimes
|
204
|
+
called the *isoperimetric number*. It is defined as the minimum of
|
205
|
+
`|\partial S| / |S|` where `\partial S` is the edge boundary of `S` (number
|
206
|
+
of edges with one end in `S` and one end in `V \setminus S`) and the
|
207
|
+
minimum is taken over all subsets of vertices whose cardinality does not
|
208
|
+
exceed half the size `|V|` of the graph.
|
209
|
+
|
210
|
+
.. SEEALSO::
|
211
|
+
|
212
|
+
Alternative but similar quantities can be obtained via the methods
|
213
|
+
:meth:`cheeger_constant` and :meth:`vertex_isoperimetric_number`.
|
214
|
+
|
215
|
+
EXAMPLES:
|
216
|
+
|
217
|
+
The edge-isoperimetric number of a complete graph on `n` vertices is
|
218
|
+
`\lceil n/2 \rceil`::
|
219
|
+
|
220
|
+
sage: [graphs.CompleteGraph(n).edge_isoperimetric_number() for n in range(2,10)]
|
221
|
+
[1, 2, 2, 3, 3, 4, 4, 5]
|
222
|
+
|
223
|
+
The edge-isoperimetric constant of a cycle on `n` vertices is
|
224
|
+
`2/\lfloor n/2 \rfloor`::
|
225
|
+
|
226
|
+
sage: [graphs.CycleGraph(n).edge_isoperimetric_number() for n in range(2,15)]
|
227
|
+
[1, 2, 1, 1, 2/3, 2/3, 1/2, 1/2, 2/5, 2/5, 1/3, 1/3, 2/7]
|
228
|
+
|
229
|
+
In general, for `d`-regular graphs the edge-isoperimetric number is
|
230
|
+
`d` times larger than the Cheeger constant of the graph::
|
231
|
+
|
232
|
+
sage: g = graphs.RandomRegular(3, 10) # needs networkx
|
233
|
+
sage: g.edge_isoperimetric_number() == g.cheeger_constant() * 3 # needs networkx
|
234
|
+
True
|
235
|
+
|
236
|
+
And the edge-isoperimetric constant of a disconnected graph is `0`::
|
237
|
+
|
238
|
+
sage: Graph([[1,2,3,4],[(1,2),(3,4)]]).edge_isoperimetric_number()
|
239
|
+
0
|
240
|
+
|
241
|
+
TESTS::
|
242
|
+
|
243
|
+
sage: graphs.EmptyGraph().edge_isoperimetric_number()
|
244
|
+
Traceback (most recent call last):
|
245
|
+
...
|
246
|
+
ValueError: edge-isoperimetric number not defined for the empty graph
|
247
|
+
|
248
|
+
Immutable graph::
|
249
|
+
|
250
|
+
sage: G = graphs.RandomGNP(10, .7)
|
251
|
+
sage: G._backend
|
252
|
+
<sage.graphs.base.sparse_graph.SparseGraphBackend ...>
|
253
|
+
sage: H = Graph(G, immutable=True)
|
254
|
+
sage: H._backend
|
255
|
+
<sage.graphs.base.static_sparse_backend.StaticSparseBackend ...>
|
256
|
+
sage: G.edge_isoperimetric_number() == H.edge_isoperimetric_number()
|
257
|
+
True
|
258
|
+
"""
|
259
|
+
if g.is_directed():
|
260
|
+
raise ValueError("edge isoperimetric number is only defined on non-oriented graph")
|
261
|
+
g._scream_if_not_simple()
|
262
|
+
if g.num_verts() == 0:
|
263
|
+
raise ValueError("edge-isoperimetric number not defined for the empty graph")
|
264
|
+
elif g.num_verts() == 1:
|
265
|
+
return Infinity
|
266
|
+
elif not g.is_connected():
|
267
|
+
return QQ((0, 1))
|
268
|
+
|
269
|
+
cdef StaticSparseCGraph cg
|
270
|
+
cdef short_digraph sd # a copy of the graph g
|
271
|
+
cdef int * subgraph # vertices of the subgraph (stack)
|
272
|
+
cdef int * bitsubgraph # vertices of the subgraph (bit array of +1 (in) or -1 (not in))
|
273
|
+
cdef int k = 0 # number of vertices in subgraph
|
274
|
+
cdef unsigned long vol = 0 # number of edges in the subgraph
|
275
|
+
cdef unsigned long boundary = 0 # number of edges in the boundary
|
276
|
+
cdef int u = 0 # current vertex
|
277
|
+
cdef int i
|
278
|
+
|
279
|
+
if isinstance(g, StaticSparseBackend):
|
280
|
+
cg = <StaticSparseCGraph> g._cg
|
281
|
+
sd = <short_digraph> cg.g
|
282
|
+
else:
|
283
|
+
init_short_digraph(sd, g, edge_labelled=False, vertex_list=list(g))
|
284
|
+
|
285
|
+
cdef unsigned long bmin = sd.neighbors[1] - sd.neighbors[0] # value of boundary for the min
|
286
|
+
cdef unsigned long vmin = 1 # value of the volume for the min
|
287
|
+
|
288
|
+
subgraph = <int *> check_malloc(sd.n * sizeof(int))
|
289
|
+
bitsubgraph = <int *> check_malloc(sd.n * sizeof(int))
|
290
|
+
|
291
|
+
sig_on()
|
292
|
+
try:
|
293
|
+
for i in range(sd.n):
|
294
|
+
bitsubgraph[i] = -1
|
295
|
+
|
296
|
+
while True:
|
297
|
+
while True:
|
298
|
+
# add vertex u to the subgraph, update the boundary/volume
|
299
|
+
# we repeat the operation until we reach the maximum volume
|
300
|
+
# or have no more vertex available
|
301
|
+
for i in range(sd.neighbors[u+1] - sd.neighbors[u]):
|
302
|
+
boundary -= bitsubgraph[sd.neighbors[u][i]]
|
303
|
+
vol += 1
|
304
|
+
|
305
|
+
bitsubgraph[u] = 1
|
306
|
+
subgraph[k] = u
|
307
|
+
u += 1
|
308
|
+
k += 1
|
309
|
+
|
310
|
+
if 2*vol > sd.n:
|
311
|
+
break
|
312
|
+
|
313
|
+
if boundary * vmin < bmin * vol:
|
314
|
+
bmin = boundary
|
315
|
+
vmin = vol
|
316
|
+
|
317
|
+
if u == sd.n:
|
318
|
+
break
|
319
|
+
|
320
|
+
# backtrack
|
321
|
+
k -= 1
|
322
|
+
u = subgraph[k]
|
323
|
+
|
324
|
+
bitsubgraph[u] = -1
|
325
|
+
for i in range(sd.neighbors[u+1] - sd.neighbors[u]):
|
326
|
+
boundary += bitsubgraph[sd.neighbors[u][i]]
|
327
|
+
vol -= 1
|
328
|
+
u += 1
|
329
|
+
|
330
|
+
if u == sd.n:
|
331
|
+
if k == 0:
|
332
|
+
# end of the loop
|
333
|
+
break
|
334
|
+
else:
|
335
|
+
# remove one more vertex in order to continue
|
336
|
+
k -= 1
|
337
|
+
u = subgraph[k]
|
338
|
+
|
339
|
+
bitsubgraph[u] = -1
|
340
|
+
for i in range(sd.neighbors[u+1] - sd.neighbors[u]):
|
341
|
+
boundary += bitsubgraph[sd.neighbors[u][i]]
|
342
|
+
vol -= 1
|
343
|
+
u += 1
|
344
|
+
|
345
|
+
return QQ((bmin, vmin))
|
346
|
+
|
347
|
+
finally:
|
348
|
+
sig_off()
|
349
|
+
if not isinstance(g, StaticSparseBackend):
|
350
|
+
free_short_digraph(sd)
|
351
|
+
sig_free(subgraph)
|
352
|
+
sig_free(bitsubgraph)
|
353
|
+
|
354
|
+
|
355
|
+
def vertex_isoperimetric_number(g):
|
356
|
+
r"""
|
357
|
+
Return the vertex-isoperimetric number of the graph.
|
358
|
+
|
359
|
+
The vertex-isoperimetric number of a graph `G = (V,E)` is also sometimes
|
360
|
+
called the *magnifying constant*. It is defined as the minimum of `|N(S)| /
|
361
|
+
|S|` where `|N(S)|` is the vertex boundary of `S` and the minimum is taken
|
362
|
+
over the subsets `S` of vertices of size at most half of the vertices.
|
363
|
+
|
364
|
+
.. SEEALSO::
|
365
|
+
|
366
|
+
Alternative but similar quantities can be obtained via the methods
|
367
|
+
:meth:`cheeger_constant` and :meth:`edge_isoperimetric_number`.
|
368
|
+
|
369
|
+
EXAMPLES:
|
370
|
+
|
371
|
+
The vertex-isoperimetric number of a complete graph on `n` vertices is
|
372
|
+
`\lceil n/2 \rceil/\lfloor n/2 \rfloor`::
|
373
|
+
|
374
|
+
sage: [graphs.CompleteGraph(k).vertex_isoperimetric_number() for k in range(2,15)]
|
375
|
+
[1, 2, 1, 3/2, 1, 4/3, 1, 5/4, 1, 6/5, 1, 7/6, 1]
|
376
|
+
|
377
|
+
The vertex-isoperimetric number of a cycle on `n` vertices is
|
378
|
+
`2/\lfloor n/2 \rfloor`::
|
379
|
+
|
380
|
+
sage: [graphs.CycleGraph(k).vertex_isoperimetric_number() for k in range(2,15)]
|
381
|
+
[1, 2, 1, 1, 2/3, 2/3, 1/2, 1/2, 2/5, 2/5, 1/3, 1/3, 2/7]
|
382
|
+
|
383
|
+
And the vertex-isoperimetric number of a disconnected graph is `0`::
|
384
|
+
|
385
|
+
sage: Graph([[1,2,3],[(1,2)]]).vertex_isoperimetric_number()
|
386
|
+
0
|
387
|
+
|
388
|
+
The vertex-isoperimetric number is independent of edge multiplicity::
|
389
|
+
|
390
|
+
sage: G = graphs.CycleGraph(6)
|
391
|
+
sage: G.vertex_isoperimetric_number()
|
392
|
+
2/3
|
393
|
+
sage: G.allow_multiple_edges(True)
|
394
|
+
sage: G.add_edges(G.edges(sort=False))
|
395
|
+
sage: G.vertex_isoperimetric_number()
|
396
|
+
2/3
|
397
|
+
|
398
|
+
TESTS::
|
399
|
+
|
400
|
+
sage: graphs.EmptyGraph().vertex_isoperimetric_number()
|
401
|
+
Traceback (most recent call last):
|
402
|
+
...
|
403
|
+
ValueError: vertex-isoperimetric number not defined for the empty graph
|
404
|
+
"""
|
405
|
+
if g.is_directed():
|
406
|
+
raise ValueError("vertex-isoperimetric number is only defined on non-oriented graph")
|
407
|
+
if not g:
|
408
|
+
raise ValueError("vertex-isoperimetric number not defined for the empty graph")
|
409
|
+
elif g.order() == 1:
|
410
|
+
return Infinity
|
411
|
+
elif not g.is_connected():
|
412
|
+
return QQ((0, 1))
|
413
|
+
|
414
|
+
# We convert the graph to a static dense graph
|
415
|
+
cdef binary_matrix_t DG
|
416
|
+
dense_graph_init(DG, g)
|
417
|
+
cdef int n = g.order()
|
418
|
+
cdef int k = n / 2 # maximum size of a subset
|
419
|
+
|
420
|
+
sig_on()
|
421
|
+
|
422
|
+
# We use a stack of bitsets. For that, we need 3 bitsets per level with at
|
423
|
+
# most n/2 + 1 levels, so 3 * (n / 2) + 3 bitsets. We also need another
|
424
|
+
# bitset that we create at the same time, so overall 3 * (n / 2) + 4 bitsets
|
425
|
+
cdef binary_matrix_t stack
|
426
|
+
binary_matrix_init(stack, 3 * (n / 2) + 4, n)
|
427
|
+
|
428
|
+
cdef bitset_t candidates = stack.rows[3 * (n / 2) + 3]
|
429
|
+
cdef bitset_t left # vertices not yet explored
|
430
|
+
cdef bitset_t current # vertices in the current subset
|
431
|
+
cdef bitset_t boundary # union of neighbors of vertices in current subset
|
432
|
+
|
433
|
+
cdef int level = 0
|
434
|
+
cdef int p = n
|
435
|
+
cdef int q = 0
|
436
|
+
cdef int c, b, v
|
437
|
+
|
438
|
+
# We initialize the first level
|
439
|
+
for v in range(3):
|
440
|
+
bitset_clear(stack.rows[v])
|
441
|
+
bitset_complement(stack.rows[0], stack.rows[0])
|
442
|
+
|
443
|
+
while level >= 0:
|
444
|
+
|
445
|
+
# We take the values at the top of the stack
|
446
|
+
left = stack.rows[level]
|
447
|
+
current = stack.rows[level + 1]
|
448
|
+
boundary = stack.rows[level + 2]
|
449
|
+
|
450
|
+
if bitset_isempty(current):
|
451
|
+
bitset_copy(candidates, left)
|
452
|
+
else:
|
453
|
+
bitset_and(candidates, left, boundary)
|
454
|
+
|
455
|
+
if bitset_isempty(candidates):
|
456
|
+
# We decrease l to pop the stack
|
457
|
+
level -= 3
|
458
|
+
|
459
|
+
# If the current set if non empty, we update the lower bound
|
460
|
+
c = bitset_len(current)
|
461
|
+
if c:
|
462
|
+
bitset_difference(boundary, boundary, current)
|
463
|
+
b = bitset_len(boundary)
|
464
|
+
if b * q < p * c:
|
465
|
+
p = b
|
466
|
+
q = c
|
467
|
+
|
468
|
+
else:
|
469
|
+
# Choose a candidate vertex v
|
470
|
+
v = bitset_first(candidates)
|
471
|
+
bitset_discard(left, v)
|
472
|
+
|
473
|
+
# Since we have not modified l, the bitsets for iterating without v
|
474
|
+
# in the subset current are now at the top of the stack, with
|
475
|
+
# correct values
|
476
|
+
|
477
|
+
if bitset_len(current) < k:
|
478
|
+
# We continue with v in the subset current
|
479
|
+
level += 3
|
480
|
+
bitset_copy(stack.rows[level], left)
|
481
|
+
bitset_copy(stack.rows[level + 1], current)
|
482
|
+
bitset_add(stack.rows[level + 1], v)
|
483
|
+
bitset_union(stack.rows[level + 2], boundary, DG.rows[v])
|
484
|
+
|
485
|
+
binary_matrix_free(stack)
|
486
|
+
binary_matrix_free(DG)
|
487
|
+
sig_off()
|
488
|
+
|
489
|
+
return QQ((p, q))
|
Binary file
|