passagemath-graphs 10.6.1rc1__cp310-cp310-musllinux_1_2_aarch64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (260) hide show
  1. passagemath_graphs-10.6.1rc1.dist-info/METADATA +292 -0
  2. passagemath_graphs-10.6.1rc1.dist-info/RECORD +260 -0
  3. passagemath_graphs-10.6.1rc1.dist-info/WHEEL +5 -0
  4. passagemath_graphs-10.6.1rc1.dist-info/top_level.txt +2 -0
  5. passagemath_graphs.libs/libgcc_s-69c45f16.so.1 +0 -0
  6. passagemath_graphs.libs/libgmp-8e78bd9b.so.10.5.0 +0 -0
  7. passagemath_graphs.libs/libstdc++-1f1a71be.so.6.0.33 +0 -0
  8. sage/all__sagemath_graphs.py +39 -0
  9. sage/combinat/abstract_tree.py +2723 -0
  10. sage/combinat/all__sagemath_graphs.py +34 -0
  11. sage/combinat/binary_tree.py +5306 -0
  12. sage/combinat/cluster_algebra_quiver/all.py +22 -0
  13. sage/combinat/cluster_algebra_quiver/cluster_seed.py +5208 -0
  14. sage/combinat/cluster_algebra_quiver/interact.py +124 -0
  15. sage/combinat/cluster_algebra_quiver/mutation_class.py +625 -0
  16. sage/combinat/cluster_algebra_quiver/mutation_type.py +1555 -0
  17. sage/combinat/cluster_algebra_quiver/quiver.py +2290 -0
  18. sage/combinat/cluster_algebra_quiver/quiver_mutation_type.py +2468 -0
  19. sage/combinat/designs/MOLS_handbook_data.py +570 -0
  20. sage/combinat/designs/all.py +58 -0
  21. sage/combinat/designs/bibd.py +1655 -0
  22. sage/combinat/designs/block_design.py +1071 -0
  23. sage/combinat/designs/covering_array.py +269 -0
  24. sage/combinat/designs/covering_design.py +530 -0
  25. sage/combinat/designs/database.py +5615 -0
  26. sage/combinat/designs/design_catalog.py +122 -0
  27. sage/combinat/designs/designs_pyx.cpython-310-aarch64-linux-gnu.so +0 -0
  28. sage/combinat/designs/designs_pyx.pxd +21 -0
  29. sage/combinat/designs/designs_pyx.pyx +993 -0
  30. sage/combinat/designs/difference_family.py +3951 -0
  31. sage/combinat/designs/difference_matrices.py +279 -0
  32. sage/combinat/designs/evenly_distributed_sets.cpython-310-aarch64-linux-gnu.so +0 -0
  33. sage/combinat/designs/evenly_distributed_sets.pyx +661 -0
  34. sage/combinat/designs/ext_rep.py +1064 -0
  35. sage/combinat/designs/gen_quadrangles_with_spread.cpython-310-aarch64-linux-gnu.so +0 -0
  36. sage/combinat/designs/gen_quadrangles_with_spread.pyx +339 -0
  37. sage/combinat/designs/group_divisible_designs.py +361 -0
  38. sage/combinat/designs/incidence_structures.py +2357 -0
  39. sage/combinat/designs/latin_squares.py +581 -0
  40. sage/combinat/designs/orthogonal_arrays.py +2244 -0
  41. sage/combinat/designs/orthogonal_arrays_build_recursive.py +1780 -0
  42. sage/combinat/designs/orthogonal_arrays_find_recursive.cpython-310-aarch64-linux-gnu.so +0 -0
  43. sage/combinat/designs/orthogonal_arrays_find_recursive.pyx +967 -0
  44. sage/combinat/designs/resolvable_bibd.py +815 -0
  45. sage/combinat/designs/steiner_quadruple_systems.py +1306 -0
  46. sage/combinat/designs/subhypergraph_search.cpython-310-aarch64-linux-gnu.so +0 -0
  47. sage/combinat/designs/subhypergraph_search.pyx +530 -0
  48. sage/combinat/designs/twographs.py +306 -0
  49. sage/combinat/finite_state_machine.py +14874 -0
  50. sage/combinat/finite_state_machine_generators.py +2006 -0
  51. sage/combinat/graph_path.py +448 -0
  52. sage/combinat/interval_posets.py +3908 -0
  53. sage/combinat/nu_tamari_lattice.py +269 -0
  54. sage/combinat/ordered_tree.py +1446 -0
  55. sage/combinat/posets/all.py +46 -0
  56. sage/combinat/posets/bubble_shuffle.py +247 -0
  57. sage/combinat/posets/cartesian_product.py +493 -0
  58. sage/combinat/posets/d_complete.py +182 -0
  59. sage/combinat/posets/elements.py +273 -0
  60. sage/combinat/posets/forest.py +30 -0
  61. sage/combinat/posets/hasse_cython.cpython-310-aarch64-linux-gnu.so +0 -0
  62. sage/combinat/posets/hasse_cython.pyx +174 -0
  63. sage/combinat/posets/hasse_diagram.py +3672 -0
  64. sage/combinat/posets/hochschild_lattice.py +158 -0
  65. sage/combinat/posets/incidence_algebras.py +794 -0
  66. sage/combinat/posets/lattices.py +5117 -0
  67. sage/combinat/posets/linear_extension_iterator.cpython-310-aarch64-linux-gnu.so +0 -0
  68. sage/combinat/posets/linear_extension_iterator.pyx +292 -0
  69. sage/combinat/posets/linear_extensions.py +1037 -0
  70. sage/combinat/posets/mobile.py +275 -0
  71. sage/combinat/posets/moebius_algebra.py +776 -0
  72. sage/combinat/posets/poset_examples.py +2178 -0
  73. sage/combinat/posets/posets.py +9360 -0
  74. sage/combinat/rooted_tree.py +1070 -0
  75. sage/combinat/shard_order.py +239 -0
  76. sage/combinat/tamari_lattices.py +384 -0
  77. sage/combinat/yang_baxter_graph.py +923 -0
  78. sage/databases/all__sagemath_graphs.py +1 -0
  79. sage/databases/knotinfo_db.py +1231 -0
  80. sage/ext_data/all__sagemath_graphs.py +1 -0
  81. sage/ext_data/graphs/graph_plot_js.html +330 -0
  82. sage/ext_data/kenzo/CP2.txt +45 -0
  83. sage/ext_data/kenzo/CP3.txt +349 -0
  84. sage/ext_data/kenzo/CP4.txt +4774 -0
  85. sage/ext_data/kenzo/README.txt +49 -0
  86. sage/ext_data/kenzo/S4.txt +20 -0
  87. sage/graphs/all.py +42 -0
  88. sage/graphs/asteroidal_triples.cpython-310-aarch64-linux-gnu.so +0 -0
  89. sage/graphs/asteroidal_triples.pyx +320 -0
  90. sage/graphs/base/all.py +1 -0
  91. sage/graphs/base/boost_graph.cpython-310-aarch64-linux-gnu.so +0 -0
  92. sage/graphs/base/boost_graph.pxd +106 -0
  93. sage/graphs/base/boost_graph.pyx +3045 -0
  94. sage/graphs/base/c_graph.cpython-310-aarch64-linux-gnu.so +0 -0
  95. sage/graphs/base/c_graph.pxd +106 -0
  96. sage/graphs/base/c_graph.pyx +5096 -0
  97. sage/graphs/base/dense_graph.cpython-310-aarch64-linux-gnu.so +0 -0
  98. sage/graphs/base/dense_graph.pxd +28 -0
  99. sage/graphs/base/dense_graph.pyx +801 -0
  100. sage/graphs/base/graph_backends.cpython-310-aarch64-linux-gnu.so +0 -0
  101. sage/graphs/base/graph_backends.pxd +5 -0
  102. sage/graphs/base/graph_backends.pyx +797 -0
  103. sage/graphs/base/overview.py +85 -0
  104. sage/graphs/base/sparse_graph.cpython-310-aarch64-linux-gnu.so +0 -0
  105. sage/graphs/base/sparse_graph.pxd +90 -0
  106. sage/graphs/base/sparse_graph.pyx +1653 -0
  107. sage/graphs/base/static_dense_graph.cpython-310-aarch64-linux-gnu.so +0 -0
  108. sage/graphs/base/static_dense_graph.pxd +5 -0
  109. sage/graphs/base/static_dense_graph.pyx +1032 -0
  110. sage/graphs/base/static_sparse_backend.cpython-310-aarch64-linux-gnu.so +0 -0
  111. sage/graphs/base/static_sparse_backend.pxd +27 -0
  112. sage/graphs/base/static_sparse_backend.pyx +1583 -0
  113. sage/graphs/base/static_sparse_graph.cpython-310-aarch64-linux-gnu.so +0 -0
  114. sage/graphs/base/static_sparse_graph.pxd +37 -0
  115. sage/graphs/base/static_sparse_graph.pyx +1375 -0
  116. sage/graphs/bipartite_graph.py +2732 -0
  117. sage/graphs/centrality.cpython-310-aarch64-linux-gnu.so +0 -0
  118. sage/graphs/centrality.pyx +1038 -0
  119. sage/graphs/cographs.py +519 -0
  120. sage/graphs/comparability.cpython-310-aarch64-linux-gnu.so +0 -0
  121. sage/graphs/comparability.pyx +851 -0
  122. sage/graphs/connectivity.cpython-310-aarch64-linux-gnu.so +0 -0
  123. sage/graphs/connectivity.pxd +157 -0
  124. sage/graphs/connectivity.pyx +4813 -0
  125. sage/graphs/convexity_properties.cpython-310-aarch64-linux-gnu.so +0 -0
  126. sage/graphs/convexity_properties.pxd +16 -0
  127. sage/graphs/convexity_properties.pyx +870 -0
  128. sage/graphs/digraph.py +4754 -0
  129. sage/graphs/digraph_generators.py +1993 -0
  130. sage/graphs/distances_all_pairs.cpython-310-aarch64-linux-gnu.so +0 -0
  131. sage/graphs/distances_all_pairs.pxd +12 -0
  132. sage/graphs/distances_all_pairs.pyx +2938 -0
  133. sage/graphs/domination.py +1363 -0
  134. sage/graphs/dot2tex_utils.py +100 -0
  135. sage/graphs/edge_connectivity.cpython-310-aarch64-linux-gnu.so +0 -0
  136. sage/graphs/edge_connectivity.pyx +1215 -0
  137. sage/graphs/generators/all.py +1 -0
  138. sage/graphs/generators/basic.py +1769 -0
  139. sage/graphs/generators/chessboard.py +538 -0
  140. sage/graphs/generators/classical_geometries.py +1611 -0
  141. sage/graphs/generators/degree_sequence.py +235 -0
  142. sage/graphs/generators/distance_regular.cpython-310-aarch64-linux-gnu.so +0 -0
  143. sage/graphs/generators/distance_regular.pyx +2846 -0
  144. sage/graphs/generators/families.py +4759 -0
  145. sage/graphs/generators/intersection.py +565 -0
  146. sage/graphs/generators/platonic_solids.py +262 -0
  147. sage/graphs/generators/random.py +2623 -0
  148. sage/graphs/generators/smallgraphs.py +5741 -0
  149. sage/graphs/generators/world_map.py +724 -0
  150. sage/graphs/generic_graph.py +26867 -0
  151. sage/graphs/generic_graph_pyx.cpython-310-aarch64-linux-gnu.so +0 -0
  152. sage/graphs/generic_graph_pyx.pxd +34 -0
  153. sage/graphs/generic_graph_pyx.pyx +1673 -0
  154. sage/graphs/genus.cpython-310-aarch64-linux-gnu.so +0 -0
  155. sage/graphs/genus.pyx +622 -0
  156. sage/graphs/graph.py +9645 -0
  157. sage/graphs/graph_coloring.cpython-310-aarch64-linux-gnu.so +0 -0
  158. sage/graphs/graph_coloring.pyx +2284 -0
  159. sage/graphs/graph_database.py +1177 -0
  160. sage/graphs/graph_decompositions/all.py +1 -0
  161. sage/graphs/graph_decompositions/bandwidth.cpython-310-aarch64-linux-gnu.so +0 -0
  162. sage/graphs/graph_decompositions/bandwidth.pyx +428 -0
  163. sage/graphs/graph_decompositions/clique_separators.cpython-310-aarch64-linux-gnu.so +0 -0
  164. sage/graphs/graph_decompositions/clique_separators.pyx +616 -0
  165. sage/graphs/graph_decompositions/cutwidth.cpython-310-aarch64-linux-gnu.so +0 -0
  166. sage/graphs/graph_decompositions/cutwidth.pyx +753 -0
  167. sage/graphs/graph_decompositions/fast_digraph.cpython-310-aarch64-linux-gnu.so +0 -0
  168. sage/graphs/graph_decompositions/fast_digraph.pxd +13 -0
  169. sage/graphs/graph_decompositions/fast_digraph.pyx +212 -0
  170. sage/graphs/graph_decompositions/graph_products.cpython-310-aarch64-linux-gnu.so +0 -0
  171. sage/graphs/graph_decompositions/graph_products.pyx +508 -0
  172. sage/graphs/graph_decompositions/modular_decomposition.cpython-310-aarch64-linux-gnu.so +0 -0
  173. sage/graphs/graph_decompositions/modular_decomposition.pxd +27 -0
  174. sage/graphs/graph_decompositions/modular_decomposition.pyx +1536 -0
  175. sage/graphs/graph_decompositions/slice_decomposition.cpython-310-aarch64-linux-gnu.so +0 -0
  176. sage/graphs/graph_decompositions/slice_decomposition.pxd +18 -0
  177. sage/graphs/graph_decompositions/slice_decomposition.pyx +1106 -0
  178. sage/graphs/graph_decompositions/tree_decomposition.cpython-310-aarch64-linux-gnu.so +0 -0
  179. sage/graphs/graph_decompositions/tree_decomposition.pxd +17 -0
  180. sage/graphs/graph_decompositions/tree_decomposition.pyx +1996 -0
  181. sage/graphs/graph_decompositions/vertex_separation.cpython-310-aarch64-linux-gnu.so +0 -0
  182. sage/graphs/graph_decompositions/vertex_separation.pxd +5 -0
  183. sage/graphs/graph_decompositions/vertex_separation.pyx +1963 -0
  184. sage/graphs/graph_editor.py +82 -0
  185. sage/graphs/graph_generators.py +3314 -0
  186. sage/graphs/graph_generators_pyx.cpython-310-aarch64-linux-gnu.so +0 -0
  187. sage/graphs/graph_generators_pyx.pyx +95 -0
  188. sage/graphs/graph_input.py +812 -0
  189. sage/graphs/graph_latex.py +2064 -0
  190. sage/graphs/graph_list.py +410 -0
  191. sage/graphs/graph_plot.py +1756 -0
  192. sage/graphs/graph_plot_js.py +338 -0
  193. sage/graphs/hyperbolicity.cpython-310-aarch64-linux-gnu.so +0 -0
  194. sage/graphs/hyperbolicity.pyx +1704 -0
  195. sage/graphs/hypergraph_generators.py +364 -0
  196. sage/graphs/independent_sets.cpython-310-aarch64-linux-gnu.so +0 -0
  197. sage/graphs/independent_sets.pxd +13 -0
  198. sage/graphs/independent_sets.pyx +402 -0
  199. sage/graphs/isgci.py +1033 -0
  200. sage/graphs/isoperimetric_inequalities.cpython-310-aarch64-linux-gnu.so +0 -0
  201. sage/graphs/isoperimetric_inequalities.pyx +489 -0
  202. sage/graphs/line_graph.cpython-310-aarch64-linux-gnu.so +0 -0
  203. sage/graphs/line_graph.pyx +743 -0
  204. sage/graphs/lovasz_theta.py +77 -0
  205. sage/graphs/matching.py +1633 -0
  206. sage/graphs/matching_covered_graph.py +3590 -0
  207. sage/graphs/orientations.py +1489 -0
  208. sage/graphs/partial_cube.py +459 -0
  209. sage/graphs/path_enumeration.cpython-310-aarch64-linux-gnu.so +0 -0
  210. sage/graphs/path_enumeration.pyx +2040 -0
  211. sage/graphs/pq_trees.py +1129 -0
  212. sage/graphs/print_graphs.py +201 -0
  213. sage/graphs/schnyder.py +865 -0
  214. sage/graphs/spanning_tree.cpython-310-aarch64-linux-gnu.so +0 -0
  215. sage/graphs/spanning_tree.pyx +1457 -0
  216. sage/graphs/strongly_regular_db.cpython-310-aarch64-linux-gnu.so +0 -0
  217. sage/graphs/strongly_regular_db.pyx +3340 -0
  218. sage/graphs/traversals.cpython-310-aarch64-linux-gnu.so +0 -0
  219. sage/graphs/traversals.pxd +9 -0
  220. sage/graphs/traversals.pyx +1872 -0
  221. sage/graphs/trees.cpython-310-aarch64-linux-gnu.so +0 -0
  222. sage/graphs/trees.pxd +15 -0
  223. sage/graphs/trees.pyx +310 -0
  224. sage/graphs/tutte_polynomial.py +713 -0
  225. sage/graphs/views.cpython-310-aarch64-linux-gnu.so +0 -0
  226. sage/graphs/views.pyx +794 -0
  227. sage/graphs/weakly_chordal.cpython-310-aarch64-linux-gnu.so +0 -0
  228. sage/graphs/weakly_chordal.pyx +604 -0
  229. sage/groups/all__sagemath_graphs.py +1 -0
  230. sage/groups/perm_gps/all__sagemath_graphs.py +1 -0
  231. sage/groups/perm_gps/partn_ref/all__sagemath_graphs.py +1 -0
  232. sage/groups/perm_gps/partn_ref/refinement_graphs.cpython-310-aarch64-linux-gnu.so +0 -0
  233. sage/groups/perm_gps/partn_ref/refinement_graphs.pxd +38 -0
  234. sage/groups/perm_gps/partn_ref/refinement_graphs.pyx +1666 -0
  235. sage/knots/all.py +6 -0
  236. sage/knots/free_knotinfo_monoid.py +507 -0
  237. sage/knots/gauss_code.py +291 -0
  238. sage/knots/knot.py +682 -0
  239. sage/knots/knot_table.py +284 -0
  240. sage/knots/knotinfo.py +2900 -0
  241. sage/knots/link.py +4715 -0
  242. sage/sandpiles/all.py +13 -0
  243. sage/sandpiles/examples.py +225 -0
  244. sage/sandpiles/sandpile.py +6365 -0
  245. sage/topology/all.py +22 -0
  246. sage/topology/cell_complex.py +1214 -0
  247. sage/topology/cubical_complex.py +1976 -0
  248. sage/topology/delta_complex.py +1806 -0
  249. sage/topology/filtered_simplicial_complex.py +744 -0
  250. sage/topology/moment_angle_complex.py +823 -0
  251. sage/topology/simplicial_complex.py +5160 -0
  252. sage/topology/simplicial_complex_catalog.py +92 -0
  253. sage/topology/simplicial_complex_examples.py +1680 -0
  254. sage/topology/simplicial_complex_homset.py +205 -0
  255. sage/topology/simplicial_complex_morphism.py +836 -0
  256. sage/topology/simplicial_set.py +4102 -0
  257. sage/topology/simplicial_set_catalog.py +55 -0
  258. sage/topology/simplicial_set_constructions.py +2954 -0
  259. sage/topology/simplicial_set_examples.py +865 -0
  260. sage/topology/simplicial_set_morphism.py +1464 -0
@@ -0,0 +1 @@
1
+ # sage_setup: distribution = sagemath-graphs
@@ -0,0 +1,428 @@
1
+ # sage_setup: distribution = sagemath-graphs
2
+ # cython: binding=True
3
+ r"""
4
+ Bandwidth of undirected graphs
5
+
6
+ Definition
7
+ ----------
8
+
9
+ The bandwidth `bw(M)` of a matrix `M` is the smallest integer `k` such that all
10
+ nonzero entries of `M` are at distance `k` from the diagonal. The bandwidth
11
+ `bw(G)` of an undirected graph `G` is the minimum bandwidth of the adjacency
12
+ matrix of `G`, over all possible relabellings of its vertices.
13
+
14
+ **Path spanner:** alternatively, the bandwidth measures how tightly a path
15
+ represents the distance of a graph `G`. Indeed, if the vertices of `G` can be
16
+ ordered as `v_1,...,v_n` in such a way that `k \times d_G(v_i,v_j) \geq |i-j|` then
17
+ `bw(G)\leq k`.
18
+
19
+ **Proof:** for all `v_i \sim v_j` (i.e. `d_G(v_i,v_j)=1`), the constraint
20
+ ensures that `k\geq |i-j|`, meaning that adjacent vertices are at distance
21
+ at most `k` in the path ordering. That alone is sufficient to ensure that
22
+ `bw(G)\leq k`.
23
+
24
+ As a byproduct, we obtain that `k \times d_G(v_i,v_j) \geq |i-j|` in
25
+ general: let `v_{s_0},...,v_{s_i}` be the vertices of a shortest
26
+ `(v_i,v_j)`-path. We have:
27
+
28
+ .. MATH::
29
+
30
+ k \times d_G(v_i,v_j) &= k\times d_G(v_i,v_{s_0}) + k\times d_G(v_{s_0},v_{s_1}) + \cdots + k\times d_G(v_{s_{i-1}},v_{s_i}) + k\times d_G(v_{s_i},v_j)\\
31
+ &\geq |v_i-v_{s_0}| + |v_{s_0}-v_{s_1}| + \cdots + |v_{s_{i-1}}-v_{s_i}| + |v_{s_i}-v_j|\\
32
+ &\geq |v_i-v_j|\\
33
+
34
+ Satisfiability of a partial assignment
35
+ --------------------------------------
36
+
37
+ Let us suppose that the first `i` vertices `v_1,...,v_i` of `G` have already
38
+ been assigned positions `p_1,...,p_i` in an ordering of `V(G)` of bandwidth
39
+ `\leq k`. Where can `v_{i+1}` appear ?
40
+
41
+ Because of the previous definition, `p_{i+1}` must be at distance at most
42
+ `k\times d_G(v_1,v_{i+1})` from `p_1`, and in general at distance at most
43
+ `k\times d_G(v_j,v_{i+1})` from `p_j`. Each range is an interval of
44
+ `\{1,...,n\}\backslash \{p_1,...,p_i\}`, and because the intersection of two
45
+ intervals is again an interval we deduce that in order to satisfy all these
46
+ constraints simultaneously `p_j` must belong to an interval defined from this
47
+ partial assignment.
48
+
49
+ Applying this rule to all non-assigned vertices, we deduce that each of them
50
+ must be assigned to a given interval of `\{1,...,n\}`. Note that this can also
51
+ be extended to the already assigned vertices, by saying that `v_j` with `j<i`
52
+ must be assigned within the interval `[p_j,p_j]`.
53
+
54
+ This problem is not always satisfiable, e.g. 5 vertices cannot all be assigned
55
+ to the elements of `[10,13]`. This is a matching problem which, because all
56
+ admissible sets are intervals, can be solved quickly.
57
+
58
+ Solving the matching problem
59
+ ----------------------------
60
+
61
+ Let `n` points `v_1,...,v_n` be given, along with two functions `m,M:[n]\mapsto
62
+ [n]`. Is there an ordering `p_1,...,p_n` of them such that `m(v_i) \leq p_i \leq
63
+ M(v_i)` ? This is equivalent to Hall's bipartite matching theorem, and can in
64
+ this specific case be solved by the following algorithm:
65
+
66
+ - Consider all vertices `v` sorted increasingly according to `M(v)`
67
+
68
+ - For each of them, assign to `v` the smallest position in `[m(v),M(v)]` which
69
+ has not been assigned yet. If there is none, the assignment problem is not
70
+ satisfiable.
71
+
72
+ Note that the latest operation can be performed with very few bitset operations
73
+ (provided that `n<64`).
74
+
75
+ The algorithm
76
+ -------------
77
+
78
+ This section contains totally subjective choices, that may be changed in the
79
+ hope to get better performances.
80
+
81
+ - Try to find a satisfiable ordering by filling positions, one after the other
82
+ (and not by trying to find each vertex' position)
83
+
84
+ - Fill the positions in this order: `0,n-1,1,n-2,3,n-3, ...`
85
+
86
+ .. NOTE::
87
+
88
+ There is some symmetry to break as the reverse of a satisfiable ordering is
89
+ also a satisfiable ordering.
90
+
91
+ This module contains the following methods
92
+ ------------------------------------------
93
+
94
+ .. csv-table::
95
+ :class: contentstable
96
+ :widths: 30, 70
97
+ :delim: |
98
+
99
+ :meth:`bandwidth` | Compute the bandwidth of an undirected graph
100
+ :meth:`~sage.graphs.base.boost_graph.bandwidth_heuristics` | Use Boost heuristics to approximate the bandwidth of the input graph
101
+
102
+ Functions
103
+ ---------
104
+ """
105
+
106
+ # ****************************************************************************
107
+ # Copyright (C) 2015 Nathann Cohen <nathann.cohen@gmail.com>
108
+ #
109
+ # This program is free software: you can redistribute it and/or modify
110
+ # it under the terms of the GNU General Public License as published by
111
+ # the Free Software Foundation, either version 2 of the License, or
112
+ # (at your option) any later version.
113
+ # https://www.gnu.org/licenses/
114
+ # ****************************************************************************
115
+
116
+ from libc.stdint cimport uint16_t
117
+ from cysignals.signals cimport sig_check
118
+ from memory_allocator cimport MemoryAllocator
119
+
120
+ from sage.graphs.distances_all_pairs cimport all_pairs_shortest_path_BFS
121
+
122
+ ctypedef uint16_t index_t
123
+
124
+ ctypedef struct range_t:
125
+ index_t m
126
+ index_t M
127
+
128
+
129
+ def bandwidth(G, k=None):
130
+ r"""
131
+ Compute the bandwidth of an undirected graph.
132
+
133
+ For a definition of the bandwidth of a graph, see the documentation of the
134
+ :mod:`~sage.graphs.graph_decompositions.bandwidth` module.
135
+
136
+ INPUT:
137
+
138
+ - ``G`` -- a graph
139
+
140
+ - ``k`` -- integer (default: ``None``); set to an integer value to test
141
+ whether `bw(G)\leq k`, or to ``None`` (default) to compute `bw(G)`
142
+
143
+ OUTPUT:
144
+
145
+ When `k` is an integer value, the function returns either ``False`` or an
146
+ ordering of cost `\leq k`.
147
+
148
+ When `k` is equal to ``None``, the function returns a pair ``(bw,
149
+ ordering)``.
150
+
151
+ .. SEEALSO::
152
+
153
+ :meth:`sage.graphs.generic_graph.GenericGraph.adjacency_matrix` --
154
+ return the adjacency matrix from an ordering of the vertices.
155
+
156
+ EXAMPLES::
157
+
158
+ sage: from sage.graphs.graph_decompositions.bandwidth import bandwidth
159
+ sage: G = graphs.PetersenGraph()
160
+ sage: bandwidth(G,3)
161
+ False
162
+ sage: bandwidth(G)
163
+ (5, [0, 4, 5, 8, 1, 9, 3, 7, 6, 2])
164
+ sage: G.adjacency_matrix(vertices=[0, 4, 5, 8, 1, 9, 3, 7, 6, 2]) # needs sage.modules
165
+ [0 1 1 0 1 0 0 0 0 0]
166
+ [1 0 0 0 0 1 1 0 0 0]
167
+ [1 0 0 1 0 0 0 1 0 0]
168
+ [0 0 1 0 0 0 1 0 1 0]
169
+ [1 0 0 0 0 0 0 0 1 1]
170
+ [0 1 0 0 0 0 0 1 1 0]
171
+ [0 1 0 1 0 0 0 0 0 1]
172
+ [0 0 1 0 0 1 0 0 0 1]
173
+ [0 0 0 1 1 1 0 0 0 0]
174
+ [0 0 0 0 1 0 1 1 0 0]
175
+ sage: G = graphs.ChvatalGraph()
176
+ sage: bandwidth(G)
177
+ (6, [0, 5, 9, 4, 10, 1, 6, 11, 3, 8, 7, 2])
178
+ sage: G.adjacency_matrix(vertices=[0, 5, 9, 4, 10, 1, 6, 11, 3, 8, 7, 2]) # needs sage.modules
179
+ [0 0 1 1 0 1 1 0 0 0 0 0]
180
+ [0 0 0 1 1 1 0 1 0 0 0 0]
181
+ [1 0 0 0 1 0 0 1 1 0 0 0]
182
+ [1 1 0 0 0 0 0 0 1 1 0 0]
183
+ [0 1 1 0 0 0 1 0 0 1 0 0]
184
+ [1 1 0 0 0 0 0 0 0 0 1 1]
185
+ [1 0 0 0 1 0 0 1 0 0 0 1]
186
+ [0 1 1 0 0 0 1 0 0 0 1 0]
187
+ [0 0 1 1 0 0 0 0 0 0 1 1]
188
+ [0 0 0 1 1 0 0 0 0 0 1 1]
189
+ [0 0 0 0 0 1 0 1 1 1 0 0]
190
+ [0 0 0 0 0 1 1 0 1 1 0 0]
191
+
192
+ TESTS::
193
+
194
+ sage: bandwidth(2*graphs.PetersenGraph())
195
+ (5, [0, 4, 5, 8, 1, 9, 3, 7, 6, 2, 10, 14, 11, 19, 15, 16, 13, 12, 17, 18])
196
+ sage: bandwidth(Graph())
197
+ (0, [])
198
+ sage: bandwidth(Graph(1))
199
+ (0, [0])
200
+ sage: bandwidth(Graph(3))
201
+ (0, [0, 1, 2])
202
+
203
+ Directed/weighted graphs::
204
+
205
+ sage: bandwidth(digraphs.Circuit(5))
206
+ Traceback (most recent call last):
207
+ ...
208
+ ValueError: this method only works on undirected graphs
209
+ sage: bandwidth(Graph(graphs.PetersenGraph(), weighted=True))
210
+ Traceback (most recent call last):
211
+ ...
212
+ ValueError: this method only works on unweighted graphs
213
+ """
214
+ if G.is_directed():
215
+ raise ValueError("this method only works on undirected graphs")
216
+ if G.weighted():
217
+ raise ValueError("this method only works on unweighted graphs")
218
+ # Trivial cases
219
+ if G.order() <= 1:
220
+ if k is None:
221
+ return 0, list(G)
222
+ else:
223
+ return list(G)
224
+
225
+ if not G.is_connected():
226
+ max_k = 0 if k is None else k
227
+ order = []
228
+ for GG in G.connected_components_subgraphs():
229
+ ans = bandwidth(GG, k=k)
230
+ if not ans:
231
+ return False
232
+ if k is None:
233
+ max_k = max(max_k, ans[0])
234
+ ans = ans[1:]
235
+ order.extend(ans[0])
236
+ return (max_k, order)
237
+
238
+ # All that this function does is allocate/free the memory for function
239
+ # bandwidth_C
240
+
241
+ cdef int n = G.order()
242
+ # Must be the same order than in all_pairs_shortest_path_BFS
243
+ cdef list int_to_vertex = list(G)
244
+
245
+ cdef MemoryAllocator mem = MemoryAllocator()
246
+
247
+ cdef unsigned short ** d = <unsigned short **> mem.allocarray(n, sizeof(unsigned short *))
248
+ cdef unsigned short * distances = <unsigned short *> mem.allocarray(n*n, sizeof(unsigned short))
249
+ cdef index_t * current = <index_t *> mem.allocarray(n, sizeof(index_t))
250
+ cdef index_t * ordering = <index_t *> mem.allocarray(n, sizeof(index_t))
251
+ cdef index_t * left_to_order = <index_t *> mem.allocarray(n, sizeof(index_t))
252
+ cdef index_t * index_array_tmp = <index_t *> mem.allocarray(n, sizeof(index_t))
253
+ cdef range_t * range_arrays = <range_t *> mem.allocarray(n*n, sizeof(range_t))
254
+ cdef range_t ** ith_range_array = <range_t **> mem.allocarray(n, sizeof(range_t *))
255
+ cdef range_t * range_array_tmp = <range_t *> mem.allocarray(n, sizeof(range_t))
256
+
257
+ cdef int i, kk
258
+ # compute the distance matrix
259
+ all_pairs_shortest_path_BFS(G, NULL, distances, NULL, vertex_list=int_to_vertex)
260
+
261
+ # fill d so that d[i][j] works
262
+ for i in range(n):
263
+ d[i] = distances + i * n
264
+
265
+ # ith_range_array
266
+ for i in range(n):
267
+ ith_range_array[i] = range_arrays + i * n
268
+
269
+ # initialize left_to_order
270
+ for i in range(n):
271
+ left_to_order[i] = i
272
+
273
+ if k is None:
274
+ for kk in range((n - 1) // G.diameter(), n):
275
+ if bandwidth_C(n, kk, d, current, ordering, left_to_order, index_array_tmp, ith_range_array, range_array_tmp):
276
+ ans = True
277
+ break
278
+ else:
279
+ ans = bool(bandwidth_C(n, k, d, current, ordering, left_to_order, index_array_tmp, ith_range_array, range_array_tmp))
280
+
281
+ if ans:
282
+ order = [int_to_vertex[ordering[i]] for i in range(n)]
283
+
284
+ if ans:
285
+ ans = (kk, order) if k is None else order
286
+
287
+ return ans
288
+
289
+
290
+ cdef bint bandwidth_C(int n, int k,
291
+ unsigned short ** d,
292
+ index_t * current, # choice of vertex for the current position
293
+ index_t * ordering, # the actual ordering of vertices
294
+ index_t * left_to_order, # begins with the assigned vertices, ends with the others
295
+ index_t * index_array_tmp, # tmp space
296
+ range_t ** ith_range_array, # array of ranges, for every step of the algorithm
297
+ range_t * range_array_tmp) noexcept: # tmp space
298
+
299
+ cdef int i, v
300
+ cdef int pi # the position for which a vertex is being chosen
301
+ cdef int vi # the vertex being tested at position pi
302
+ cdef int radius
303
+ current[0] = -1
304
+
305
+ # At first any vertex can be anywhere
306
+ for v in range(n):
307
+ ith_range_array[0][v].m = 0
308
+ ith_range_array[0][v].M = n - 1
309
+
310
+ i = 0
311
+ while True:
312
+ sig_check()
313
+
314
+ # There are (n-i) choices for vertex i, as i-1 have already been
315
+ # determined. Thus, i <= current[i] < n.
316
+ current[i] += 1
317
+
318
+ # All choices for this position i have been tested. We must change our
319
+ # (i-1)th choice:
320
+ if current[i] == n:
321
+ if i == 0:
322
+ return 0
323
+ i -= 1
324
+ left_to_order[i], left_to_order[current[i]] = left_to_order[current[i]], left_to_order[i]
325
+ continue
326
+
327
+ # The position of the ith vertex. p0 = 0, p1 = n-1, p2 = 1, p3 = n-2, ...
328
+ pi = (n - 1 - i // 2) if i % 2 else (i // 2)
329
+
330
+ # The ith vertex
331
+ vi = left_to_order[current[i]]
332
+
333
+ # If pi is not an admissible position for pi:
334
+ if ith_range_array[i][vi].m > pi or ith_range_array[i][vi].M < pi:
335
+ continue
336
+
337
+ # As the choice is admissible, we update left_to_order so that
338
+ # left_to_order[i] = vi.
339
+ left_to_order[i], left_to_order[current[i]] = left_to_order[current[i]], left_to_order[i]
340
+
341
+ # vi is at position pi in the final ordering.
342
+ ordering[pi] = vi
343
+
344
+ # If we found the position of the nth vertex, we are done.
345
+ if i == n - 1:
346
+ return 1
347
+
348
+ # As vertex vi has been assigned position pi, we use that information to
349
+ # update the intervals of admissible positions of all other vertices.
350
+ #
351
+ # \forall v, k*d[v][vi] >= |p_v-p_{vi}| (see module documentation)
352
+ for v in range(n):
353
+ radius = k * d[v][vi]
354
+ ith_range_array[i + 1][v].m = max(<int> ith_range_array[i][v].m, pi - radius)
355
+ ith_range_array[i + 1][v].M = min(<int> ith_range_array[i][v].M, pi + radius)
356
+
357
+ # Check the feasibility of a matching with the updated intervals of
358
+ # admissible positions (see module doc).
359
+ #
360
+ # If it is possible we explore deeper, otherwise we undo the changes as
361
+ # pi is not a good position for vi after all.
362
+ if is_matching_feasible(n, ith_range_array[i + 1], range_array_tmp, index_array_tmp):
363
+ i += 1
364
+ current[i] = i - 1
365
+ else:
366
+ # swap back
367
+ left_to_order[i], left_to_order[current[i]] = left_to_order[current[i]], left_to_order[i]
368
+
369
+ cdef bint is_matching_feasible(int n, range_t * range_array, range_t * range_array_tmp, index_t * index_array_tmp) noexcept:
370
+ r"""
371
+ Test if the matching is feasible
372
+
373
+ INPUT:
374
+
375
+ - ``n`` -- integer; number of points
376
+
377
+ - ``range_array`` -- associates to every point an interval in which the
378
+ point must be given a position
379
+
380
+ - ``range_array_tmp`` -- temporary spaces with the same characteristics as
381
+ ``range_array``
382
+
383
+ - ``index_array_tmp`` -- temporary space to associate an integer to every
384
+ point
385
+
386
+ OUTPUT:
387
+
388
+ The function must return a boolean, and does not change the content of
389
+ ``range_array``.
390
+ """
391
+ # Heuristic: check if some vertex has an empty range, that's an easy 'no'.
392
+ cdef int v, M, m, j
393
+ for v in range(n):
394
+ if range_array[v].M < range_array[v].m:
395
+ return 0
396
+ index_array_tmp[v] = 0
397
+
398
+ # Sort the guys according to increasing value of M in O(n).
399
+
400
+ # Step 1: count the occurrences of each M
401
+ for v in range(n):
402
+ index_array_tmp[range_array[v].M] += 1
403
+
404
+ # Step 2: sorted table
405
+ for v in range(1, n):
406
+ index_array_tmp[v] += index_array_tmp[v - 1]
407
+
408
+ for v in range(n):
409
+ M = range_array[v].M
410
+ m = range_array[v].m
411
+ index_array_tmp[M] -= 1
412
+ range_array_tmp[index_array_tmp[M]].M = M
413
+ range_array_tmp[index_array_tmp[M]].m = m
414
+
415
+ # Satisfiability. We use index_array_tmp as a bitset, and mark every
416
+ # assigned position.
417
+ for v in range(n):
418
+ index_array_tmp[v] = 0
419
+
420
+ for v in range(n):
421
+ sig_check()
422
+ for j in range(range_array_tmp[v].m, range_array_tmp[v].M + 1):
423
+ if index_array_tmp[j] == 0:
424
+ index_array_tmp[j] = 1
425
+ break
426
+ else:
427
+ return 0
428
+ return 1