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,616 @@
1
+ # sage_setup: distribution = sagemath-graphs
2
+ # cython: binding=True
3
+ # distutils: language = c++
4
+ r"""
5
+ Decomposition by clique minimal separators
6
+
7
+ This module implements methods related to the decomposition of a graph by clique
8
+ minimal separators. See [TY1984]_ and [BPS2010]_ for more details on the
9
+ algorithms.
10
+
11
+ Methods
12
+ -------
13
+ """
14
+ # ****************************************************************************
15
+ # Copyright (C) 2019 David Coudert <david.coudert@inria.fr>
16
+ #
17
+ # This program is free software: you can redistribute it and/or modify
18
+ # it under the terms of the GNU General Public License as published by
19
+ # the Free Software Foundation, either version 2 of the License, or
20
+ # (at your option) any later version.
21
+ # https://www.gnu.org/licenses/
22
+ # ****************************************************************************
23
+
24
+ from libcpp.vector cimport vector
25
+ from libc.stdint cimport uint32_t
26
+ from cysignals.signals cimport sig_on, sig_off, sig_check
27
+ from memory_allocator cimport MemoryAllocator
28
+
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
32
+ from sage.graphs.base.static_sparse_graph cimport init_short_digraph
33
+ from sage.graphs.base.static_sparse_graph cimport free_short_digraph
34
+ from sage.graphs.base.static_sparse_graph cimport has_edge
35
+
36
+ from sage.sets.set import Set
37
+ from sage.graphs.traversals cimport maximum_cardinality_search_M_short_digraph
38
+
39
+
40
+ def make_tree(atoms, cliques):
41
+ r"""
42
+ Return a tree of atoms and cliques.
43
+
44
+ The atoms are the leaves of the tree and the cliques are the internal
45
+ vertices. The number of atoms is the number of cliques plus one.
46
+
47
+ As a clique may appear several times in the list ``cliques``, vertices are
48
+ numbered by pairs `(i, S)`, where `0 \leq i < |atoms| + |cliques|` and `S`
49
+ is either an atom or a clique.
50
+
51
+ The root of the tree is the only vertex with even or null degree, i.e., 0 if
52
+ ``cliques`` is empty and 2 otherwise. When ``cliques`` is not empty, other
53
+ internal vertices (each of which is a clique) have degree 3, and the
54
+ leaves (vertices of degree 1) are the atoms.
55
+
56
+ INPUT:
57
+
58
+ - ``atoms`` -- list of atoms
59
+
60
+ - ``cliques`` -- list of cliques
61
+
62
+ EXAMPLES::
63
+
64
+ sage: from sage.graphs.graph_decompositions.clique_separators import make_tree
65
+ sage: G = graphs.Grid2dGraph(2, 4)
66
+ sage: A, Sc = G.atoms_and_clique_separators()
67
+ sage: T = make_tree(A, Sc)
68
+ sage: all(u[1] in A for u in T if T.degree(u) == 1)
69
+ True
70
+ sage: all(u[1] in Sc for u in T if T.degree(u) != 1)
71
+ True
72
+
73
+ TESTS::
74
+
75
+ sage: from sage.graphs.graph_decompositions.clique_separators import make_tree
76
+ sage: make_tree([0], [1, 2])
77
+ Traceback (most recent call last):
78
+ ...
79
+ ValueError: the number of atoms must be the number of cliques plus one
80
+ """
81
+ if (atoms or cliques) and len(atoms) != len(cliques) + 1:
82
+ raise ValueError("the number of atoms must be the number of cliques plus one")
83
+
84
+ from sage.graphs.graph import Graph
85
+ T = Graph()
86
+ if cliques:
87
+ # As a clique can appear several times, we number the vertices by
88
+ # pairs (int, Set), with 0 <= int < |atoms| + |cliques|
89
+ T.add_path(list(enumerate(cliques)))
90
+ j = len(cliques)
91
+ T.add_edges((s, (i + j, a)) for s, (i, a) in zip(enumerate(cliques), enumerate(atoms)))
92
+ # We have |atoms| = |cliques| + 1. So |atoms| + |cliques| = 2 * j + 1
93
+ T.add_edge((j - 1, cliques[-1]), (2 * j, atoms[-1]))
94
+
95
+ elif atoms:
96
+ # The graph has no clique separator
97
+ T.add_vertex(atoms[0])
98
+
99
+ return T
100
+
101
+
102
+ def make_labelled_rooted_tree(atoms, cliques):
103
+ r"""
104
+ Return a :class:`~LabelledRootedTree` of atoms and cliques.
105
+
106
+ The atoms are the leaves of the tree and the cliques are the internal
107
+ vertices. The number of atoms is the number of cliques plus one.
108
+
109
+ EXAMPLES::
110
+
111
+ sage: G = graphs.PathGraph(5)
112
+ sage: ascii_art(G.atoms_and_clique_separators(rooted_tree=True))
113
+ _____{3}_____
114
+ / /
115
+ {3, 4} ____{2}____
116
+ / /
117
+ {2, 3} __{1}__
118
+ / /
119
+ {0, 1} {1, 2}
120
+
121
+ TESTS::
122
+
123
+ sage: from sage.graphs.graph_decompositions.clique_separators import make_labelled_rooted_tree
124
+ sage: make_labelled_rooted_tree([0], [1, 2])
125
+ Traceback (most recent call last):
126
+ ...
127
+ ValueError: the number of atoms must be the number of cliques plus one
128
+ """
129
+ from sage.combinat.rooted_tree import LabelledRootedTree
130
+ if not atoms and not cliques:
131
+ return LabelledRootedTree([])
132
+
133
+ if len(atoms) != len(cliques) + 1:
134
+ raise ValueError("the number of atoms must be the number of cliques plus one")
135
+
136
+ def to_tree(i, n):
137
+ if i < n:
138
+ return LabelledRootedTree([LabelledRootedTree([], label=atoms[i]), to_tree(i + 1, n)],
139
+ label=cliques[i])
140
+ return LabelledRootedTree([], label=atoms[i])
141
+
142
+ return to_tree(0, len(cliques))
143
+
144
+
145
+ cdef inline bint is_clique(short_digraph sd, vector[int] Hx) noexcept:
146
+ """
147
+ Check if the subgraph sd[Hx] is a clique.
148
+
149
+ This is a helper function of ``atoms_and_clique_separators``.
150
+ """
151
+ cdef size_t Hx_size = Hx.size()
152
+ cdef size_t i, j
153
+ cdef int u
154
+ for i in range(Hx_size - 1):
155
+ u = Hx[i]
156
+ for j in range(i + 1, Hx_size):
157
+ if not has_edge(sd, u, Hx[j]):
158
+ return False
159
+ return True
160
+
161
+
162
+ def atoms_and_clique_separators(G, tree=False, rooted_tree=False, separators=False):
163
+ r"""
164
+ Return the atoms of the decomposition of `G` by clique minimal separators.
165
+
166
+ Let `G = (V, E)` be a graph. A set `S \subset V` is a clique separator if
167
+ `G[S]` is a clique and the graph `G \setminus S` has at least 2 connected
168
+ components. Let `C \subset V` be the vertices of a connected component of `G
169
+ \setminus S`. The graph `G[C + S]` is an *atom* if it has no clique
170
+ separator.
171
+
172
+ This method implements the algorithm proposed in [BPS2010]_, that improves
173
+ upon the algorithm proposed in [TY1984]_, for computing the atoms and the
174
+ clique minimal separators of a graph. This algorithm is based on the
175
+ :meth:`~sage.graphs.traversals.maximum_cardinality_search_M` graph traversal
176
+ and has time complexity in `O(|V|\cdot|E|)`.
177
+
178
+ If the graph is not connected, we insert empty separators between the lists
179
+ of separators of each connected components. See the examples below for more
180
+ details.
181
+
182
+ INPUT:
183
+
184
+ - ``G`` -- a Sage graph
185
+
186
+ - ``tree`` -- boolean (default: ``False``); whether to return the result as
187
+ a directed tree in which internal nodes are clique separators and leaves
188
+ are the atoms of the decomposition. Since a clique separator is repeated
189
+ when its removal partition the graph into 3 or more connected components,
190
+ vertices are labels by tuples `(i, S)`, where `S` is the set of vertices
191
+ of the atom or the clique separator, and `0 \leq i \leq |T|`.
192
+
193
+ - ``rooted_tree`` -- boolean (default: ``False``); whether to return the
194
+ result as a :class:`~sage.combinat.rooted_tree.LabelledRootedTree`. When
195
+ ``tree`` is ``True``, this parameter is ignored.
196
+
197
+ - ``separators`` -- boolean (default: ``False``); whether to also return the
198
+ complete list of separators considered during the execution of the
199
+ algorithm. When ``tree`` or ``rooted_tree`` is ``True``, this parameter is
200
+ ignored.
201
+
202
+ OUTPUT:
203
+
204
+ - By default, return a tuple `(A, S_c)`, where `A` is the list of atoms of
205
+ the graph in the order of discovery, and `S_c` is the list of clique
206
+ separators, with possible repetitions, in the order the separator has been
207
+ considered. If furthermore ``separators`` is ``True``, return a tuple `(A,
208
+ S_h, S_c)`, where `S_c` is the list of considered separators of the graph
209
+ in the order they have been considered.
210
+
211
+ - When ``tree`` is ``True``, format the result as a directed tree
212
+
213
+ - When ``rooted_tree`` is ``True`` and ``tree`` is ``False``, format the
214
+ output as a :class:`~sage.combinat.rooted_tree.LabelledRootedTree`
215
+
216
+ EXAMPLES:
217
+
218
+ Example of [BPS2010]_::
219
+
220
+ sage: G = Graph({'a': ['b', 'k'], 'b': ['c'], 'c': ['d', 'j', 'k'],
221
+ ....: 'd': ['e', 'f', 'j', 'k'], 'e': ['g'],
222
+ ....: 'f': ['g', 'j', 'k'], 'g': ['j', 'k'], 'h': ['i', 'j'],
223
+ ....: 'i': ['k'], 'j': ['k']})
224
+ sage: atoms, cliques = G.atoms_and_clique_separators()
225
+ sage: sorted(sorted(a) for a in atoms)
226
+ [['a', 'b', 'c', 'k'],
227
+ ['c', 'd', 'j', 'k'],
228
+ ['d', 'e', 'f', 'g', 'j', 'k'],
229
+ ['h', 'i', 'j', 'k']]
230
+ sage: sorted(sorted(c) for c in cliques)
231
+ [['c', 'k'], ['d', 'j', 'k'], ['j', 'k']]
232
+ sage: T = G.atoms_and_clique_separators(tree=True)
233
+ sage: T.is_tree()
234
+ True
235
+ sage: T.diameter() == len(atoms)
236
+ True
237
+ sage: all(u[1] in atoms for u in T if T.degree(u) == 1)
238
+ True
239
+ sage: all(u[1] in cliques for u in T if T.degree(u) != 1)
240
+ True
241
+
242
+ A graph without clique separator::
243
+
244
+ sage: G = graphs.CompleteGraph(5)
245
+ sage: G.atoms_and_clique_separators()
246
+ ([{0, 1, 2, 3, 4}], [])
247
+ sage: ascii_art(G.atoms_and_clique_separators(rooted_tree=True))
248
+ {0, 1, 2, 3, 4}
249
+
250
+ Graphs with several biconnected components::
251
+
252
+ sage: G = graphs.PathGraph(4)
253
+ sage: ascii_art(G.atoms_and_clique_separators(rooted_tree=True))
254
+ ____{2}____
255
+ / /
256
+ {2, 3} __{1}__
257
+ / /
258
+ {1, 2} {0, 1}
259
+
260
+ sage: G = graphs.WindmillGraph(3, 4)
261
+ sage: G.atoms_and_clique_separators()
262
+ ([{0, 1, 2}, {0, 3, 4}, {0, 5, 6}, {0, 8, 7}], [{0}, {0}, {0}])
263
+ sage: ascii_art(G.atoms_and_clique_separators(rooted_tree=True))
264
+ ________{0}________
265
+ / /
266
+ {0, 1, 2} _______{0}______
267
+ / /
268
+ {0, 3, 4} ____{0}___
269
+ / /
270
+ {0, 8, 7} {0, 5, 6}
271
+
272
+ When the removal of a clique separator results in `k > 2` connected
273
+ components, this separator is repeated `k - 1` times, but the repetitions
274
+ are not necessarily contiguous::
275
+
276
+ sage: G = Graph(2)
277
+ sage: for i in range(5):
278
+ ....: G.add_cycle([0, 1, G.add_vertex()])
279
+ sage: ascii_art(G.atoms_and_clique_separators(rooted_tree=True))
280
+ _________{0, 1}_____
281
+ / /
282
+ {0, 1, 4} ________{0, 1}_____
283
+ / /
284
+ {0, 1, 2} _______{0, 1}___
285
+ / /
286
+ {0, 1, 3} ____{0, 1}
287
+ / /
288
+ {0, 1, 5} {0, 1, 6}
289
+
290
+ sage: G = graphs.StarGraph(3)
291
+ sage: G.subdivide_edges(G.edges(sort=False), 2)
292
+ sage: ascii_art(G.atoms_and_clique_separators(rooted_tree=True))
293
+ ______{5}______
294
+ / /
295
+ {1, 5} ______{7}______
296
+ / /
297
+ {2, 7} ______{9}______
298
+ / /
299
+ {9, 3} ______{6}______
300
+ / /
301
+ {6, 7} ______{4}_____
302
+ / /
303
+ {4, 5} _____{0}_____
304
+ / /
305
+ {0, 6} ____{8}____
306
+ / /
307
+ {8, 9} __{0}__
308
+ / /
309
+ {0, 8} {0, 4}
310
+
311
+ If the graph is not connected, we insert empty separators between the lists
312
+ of separators of each connected components. For instance, let `G` be a graph
313
+ with 3 connected components. The method returns the list `S_c =
314
+ [S_0,\cdots,S_{i},\ldots, S_{j},\ldots,S_{k-1}]` of `k` clique separators,
315
+ where `i` and `j` are the indexes of the inserted empty separators and `0
316
+ \leq i < j < k - 1`. The method also returns the list `A =
317
+ [A_0,\ldots,S_{k}]` of the `k + 1` atoms, with `k + 1 \geq 3`. The lists of
318
+ atoms and clique separators of each of the connected components are
319
+ respectively `[A_0,\ldots,A_{i}]` and `[S_0,\ldots,S_{i-1}]`,
320
+ `[A_{i+1},\ldots,A_{j}]` and `[S_{i+1},\ldots,S_{j-1}]`, and
321
+ `[A_{j+1},\ldots,A_{k}]` and `[S_{j+1},\ldots,S_{k-1}]`. One can check that
322
+ for each connected component, we get one atom more than clique separators::
323
+
324
+ sage: G = graphs.PathGraph(3) * 3
325
+ sage: A, Sc = G.atoms_and_clique_separators()
326
+ sage: A
327
+ [{1, 2}, {0, 1}, {4, 5}, {3, 4}, {8, 7}, {6, 7}]
328
+ sage: Sc
329
+ [{1}, {}, {4}, {}, {7}]
330
+ sage: i , j = [i for i, s in enumerate(Sc) if not s]
331
+ sage: i, j
332
+ (1, 3)
333
+ sage: A[:i+1], Sc[:i]
334
+ ([{1, 2}, {0, 1}], [{1}])
335
+ sage: A[i+1:j+1], Sc[i+1:j]
336
+ ([{4, 5}, {3, 4}], [{4}])
337
+ sage: A[j+1:], Sc[j+1:]
338
+ ([{8, 7}, {6, 7}], [{7}])
339
+ sage: I = [-1, i, j, len(Sc)]
340
+ sage: for i, j in zip(I[:-1], I[1:]):
341
+ ....: print(A[i+1:j+1], Sc[i+1:j])
342
+ [{1, 2}, {0, 1}] [{1}]
343
+ [{4, 5}, {3, 4}] [{4}]
344
+ [{8, 7}, {6, 7}] [{7}]
345
+ sage: ascii_art(G.atoms_and_clique_separators(rooted_tree=True))
346
+ ______{1}______
347
+ / /
348
+ {1, 2} ______{}______
349
+ / /
350
+ {0, 1} _____{4}_____
351
+ / /
352
+ {4, 5} ____{}_____
353
+ / /
354
+ {3, 4} __{7}__
355
+ / /
356
+ {6, 7} {8, 7}
357
+
358
+ Loops and multiple edges are ignored::
359
+
360
+ sage: G.allow_loops(True)
361
+ sage: G.add_edges([(u, u) for u in G])
362
+ sage: G.allow_multiple_edges(True)
363
+ sage: G.add_edges(G.edges(sort=False))
364
+ sage: ascii_art(G.atoms_and_clique_separators(rooted_tree=True))
365
+ ______{1}______
366
+ / /
367
+ {1, 2} ______{}______
368
+ / /
369
+ {0, 1} _____{4}_____
370
+ / /
371
+ {4, 5} ____{}_____
372
+ / /
373
+ {3, 4} __{7}__
374
+ / /
375
+ {6, 7} {8, 7}
376
+
377
+ We can check that the returned list of separators is valid::
378
+
379
+ sage: G = graphs.RandomGNP(50, .1)
380
+ sage: while not G.is_connected():
381
+ ....: G = graphs.RandomGNP(50, .1)
382
+ sage: _, separators, _ = G.atoms_and_clique_separators(separators=True)
383
+ sage: for S in separators:
384
+ ....: H = G.copy()
385
+ ....: H.delete_vertices(S)
386
+ ....: if H.is_connected():
387
+ ....: raise ValueError("something goes wrong")
388
+
389
+ TESTS::
390
+
391
+ sage: EmptyGraph = Graph()
392
+ sage: EmptyGraph.atoms_and_clique_separators()
393
+ ([], [])
394
+ sage: EmptyGraph.atoms_and_clique_separators(separators=True)
395
+ ([], [], [])
396
+ sage: EmptyGraph.atoms_and_clique_separators(tree=True)
397
+ Graph on 0 vertices
398
+ sage: EmptyGraph.atoms_and_clique_separators(rooted_tree=True)
399
+ None[]
400
+ sage: ascii_art(EmptyGraph.atoms_and_clique_separators(rooted_tree=True))
401
+ None
402
+ sage: I4 = Graph(4)
403
+ sage: I4.atoms_and_clique_separators()
404
+ ([{0}, {1}, {2}, {3}], [{}, {}, {}])
405
+ sage: I4.atoms_and_clique_separators(separators=True)
406
+ ([{0}, {1}, {2}, {3}], [{}, {}, {}], [{}, {}, {}])
407
+ sage: I4.atoms_and_clique_separators(tree=True)
408
+ Graph on 7 vertices
409
+ sage: I4.atoms_and_clique_separators(rooted_tree=True)
410
+ {}[{0}[], {}[{1}[], {}[{3}[], {2}[]]]]
411
+ sage: ascii_art(I4.atoms_and_clique_separators(rooted_tree=True))
412
+ ___{}___
413
+ / /
414
+ {0} __{}___
415
+ / /
416
+ {1} _{}_
417
+ / /
418
+ {3} {2}
419
+
420
+ Immutable graphs::
421
+
422
+ sage: G = graphs.RandomGNP(10, .7)
423
+ sage: G._backend
424
+ <sage.graphs.base.sparse_graph.SparseGraphBackend ...>
425
+ sage: H = Graph(G, immutable=True)
426
+ sage: H._backend
427
+ <sage.graphs.base.static_sparse_backend.StaticSparseBackend ...>
428
+ sage: G.atoms_and_clique_separators() == H.atoms_and_clique_separators()
429
+ True
430
+ """
431
+ cdef list A = [] # atoms
432
+ cdef list Sh = [] # separators
433
+ cdef list Sc = [] # clique separators
434
+ cdef bint first = True
435
+
436
+ if not G.is_connected():
437
+ from sage.graphs.graph import Graph
438
+
439
+ for cc in G.connected_components(sort=False):
440
+ g = Graph([cc, G.edge_boundary(cc, cc, False, False)],
441
+ format='vertices_and_edges',
442
+ loops=True, multiedges=True)
443
+ res = g.atoms_and_clique_separators(tree=False, rooted_tree=False, separators=separators)
444
+
445
+ # Update lists of atoms, separators and clique separators
446
+ A.extend(res[0])
447
+ if separators:
448
+ if not first:
449
+ Sh.append(Set())
450
+ Sh.extend(res[1])
451
+ if not first:
452
+ Sc.append(Set())
453
+ if separators:
454
+ Sc.extend(res[2])
455
+ else:
456
+ Sc.extend(res[1])
457
+ first = False
458
+
459
+ # Format and return the result
460
+ if tree:
461
+ return make_tree(A, Sc)
462
+ elif rooted_tree:
463
+ return make_labelled_rooted_tree(A, Sc)
464
+ elif separators:
465
+ return A, Sh, Sc
466
+ return A, Sc
467
+
468
+ cdef int N = G.order()
469
+
470
+ # Copying the whole graph to obtain the list of neighbors quicker than by
471
+ # calling out_neighbors. This data structure is well documented in the
472
+ # module sage.graphs.base.static_sparse_graph
473
+ cdef list int_to_vertex
474
+ cdef StaticSparseCGraph cg
475
+ cdef short_digraph sd
476
+ if isinstance(G, StaticSparseBackend):
477
+ cg = <StaticSparseCGraph> G._cg
478
+ sd = <short_digraph> cg.g
479
+ int_to_vertex = cg._vertex_to_labels
480
+ else:
481
+ int_to_vertex = list(G)
482
+ init_short_digraph(sd, G, edge_labelled=False, vertex_list=int_to_vertex)
483
+
484
+ # variables for the manipulation of the short digraph
485
+ cdef uint32_t** p_vertices = sd.neighbors
486
+ cdef uint32_t* p_tmp
487
+ cdef uint32_t* p_end
488
+
489
+ cdef MemoryAllocator mem = MemoryAllocator()
490
+ cdef int* alpha = <int*>mem.calloc(N, sizeof(int))
491
+ cdef int* alpha_inv = <int*>mem.calloc(N, sizeof(int))
492
+ cdef bint* X = <bint*>mem.calloc(N, sizeof(bint))
493
+ cdef bint* active = <bint*>mem.calloc(N, sizeof(bint))
494
+ cdef int* waiting_list = <int*>mem.calloc(N, sizeof(int))
495
+ cdef int* seen = <int*>mem.calloc(N, sizeof(int))
496
+ cdef list F = []
497
+ cdef int u, v, waiting_begin, waiting_end
498
+
499
+ sig_on()
500
+ maximum_cardinality_search_M_short_digraph(sd, 0, alpha, alpha_inv, F, X)
501
+ sig_off()
502
+
503
+ # Instead of building the graph H of the triangulation, extracting the
504
+ # neighbors of vertex alpha[i] and then removing that vertex from H, we
505
+ # directly build the neighborhoods. Note that vertices are removed from the
506
+ # graph of the triangulation in the order of alpha. Hence, at step i, this
507
+ # graph has no vertex u such that alpha_inv[u] < i, and edge (u, v) is
508
+ # removed from the graph when min(alpha_inv[u], alpha_inv[v]) is removed.
509
+ # The neighborhood of x at step i is thus {v in N_H(x) | alpha_inv[v] > i}.
510
+ cdef vector[vector[int]] H
511
+ H.resize(N)
512
+ for u in range(N):
513
+ p_tmp = p_vertices[u]
514
+ p_end = p_vertices[u + 1]
515
+ while p_tmp < p_end:
516
+ v = p_tmp[0]
517
+ p_tmp += 1
518
+ if u < v:
519
+ # We consider edge (u, v) only once, when u > v, and the
520
+ # short_digraph data structure ensures that neighbors are sorted
521
+ break
522
+ if alpha_inv[u] < alpha_inv[v]:
523
+ if X[u]:
524
+ H[u].push_back(v)
525
+ elif X[v]:
526
+ H[v].push_back(u)
527
+ for u, v in F:
528
+ if alpha_inv[u] < alpha_inv[v]:
529
+ if X[u]:
530
+ H[u].push_back(v)
531
+ elif X[v]:
532
+ H[v].push_back(u)
533
+
534
+ # Instead of using a copy Gp of G and removing from it the vertices of the
535
+ # connected component of an atom after its discovery, we use an array of
536
+ # booleans to avoid visiting inactive vertices
537
+ for u in range(N):
538
+ active[u] = True
539
+ seen[u] = -1
540
+
541
+ cdef frozenset Sint
542
+ cdef vector[int] Sint_min
543
+ cdef vector[int] Cint
544
+ cdef vector[int] Hx
545
+
546
+ for i in range(N):
547
+ sig_check()
548
+ x = alpha[i]
549
+ if X[x] and not H[x].empty():
550
+ Hx = H[x]
551
+
552
+ if separators:
553
+ Sh.append(Set(int_to_vertex[u] for u in Hx))
554
+
555
+ if is_clique(sd, Hx):
556
+ # The subgraph G[H[x]] = G[S] is a clique.
557
+ # We extract the connected component of Gp - S containing x
558
+ Sint = frozenset(Hx)
559
+ Sint_min.clear()
560
+ Cint.clear()
561
+ Cint.push_back(x)
562
+ seen[x] = x
563
+ waiting_list[0] = x
564
+ waiting_begin = 0
565
+ waiting_end = 0
566
+ while waiting_begin <= waiting_end:
567
+
568
+ u = waiting_list[waiting_begin]
569
+ waiting_begin += 1
570
+ p_tmp = p_vertices[u]
571
+ end = p_vertices[u + 1]
572
+
573
+ while p_tmp < end:
574
+ v = p_tmp[0]
575
+ p_tmp += 1
576
+
577
+ if active[v] and seen[v] != x:
578
+ seen[v] = x
579
+ if v in Sint:
580
+ # We keep only the vertices of the clique
581
+ # separator incident to the connected component
582
+ # containing x
583
+ Sint_min.push_back(v)
584
+ else:
585
+ Cint.push_back(v)
586
+ waiting_end += 1
587
+ waiting_list[waiting_end] = v
588
+
589
+ # Store the atom Smin + C and the minimal clique separator Smin
590
+ Smin = Set(int_to_vertex[u] for u in Sint_min)
591
+ A.append(Set(Smin.set().union(int_to_vertex[u] for u in Cint)))
592
+ Sc.append(Smin)
593
+
594
+ # "Remove" the vertices of Cint from the graph Gp
595
+ for u in Cint:
596
+ active[u] = False
597
+
598
+ if not isinstance(G, StaticSparseBackend):
599
+ free_short_digraph(sd)
600
+ H.clear()
601
+
602
+ # We add the last atom
603
+ if Sc:
604
+ A.append(Set(int_to_vertex[x] for x in range(N) if active[x]))
605
+ elif G:
606
+ # The graph has no clique separator
607
+ A.append(Set(int_to_vertex))
608
+
609
+ # Format and return the result
610
+ if tree:
611
+ return make_tree(A, Sc)
612
+ elif rooted_tree:
613
+ return make_labelled_rooted_tree(A, Sc)
614
+ if separators:
615
+ return A, Sh, Sc
616
+ return A, Sc