passagemath-graphs 10.5.43__cp39-cp39-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 (258) hide show
  1. passagemath_graphs-10.5.43.dist-info/METADATA +293 -0
  2. passagemath_graphs-10.5.43.dist-info/RECORD +258 -0
  3. passagemath_graphs-10.5.43.dist-info/WHEEL +5 -0
  4. passagemath_graphs-10.5.43.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 +2552 -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 +125 -0
  15. sage/combinat/cluster_algebra_quiver/mutation_class.py +625 -0
  16. sage/combinat/cluster_algebra_quiver/mutation_type.py +1556 -0
  17. sage/combinat/cluster_algebra_quiver/quiver.py +2262 -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 +534 -0
  25. sage/combinat/designs/database.py +5614 -0
  26. sage/combinat/designs/design_catalog.py +122 -0
  27. sage/combinat/designs/designs_pyx.cpython-39-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-39-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-39-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 +548 -0
  40. sage/combinat/designs/orthogonal_arrays.py +2243 -0
  41. sage/combinat/designs/orthogonal_arrays_build_recursive.py +1780 -0
  42. sage/combinat/designs/orthogonal_arrays_find_recursive.cpython-39-aarch64-linux-gnu.so +0 -0
  43. sage/combinat/designs/orthogonal_arrays_find_recursive.pyx +966 -0
  44. sage/combinat/designs/resolvable_bibd.py +781 -0
  45. sage/combinat/designs/steiner_quadruple_systems.py +1306 -0
  46. sage/combinat/designs/subhypergraph_search.cpython-39-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/cartesian_product.py +493 -0
  57. sage/combinat/posets/d_complete.py +182 -0
  58. sage/combinat/posets/elements.py +273 -0
  59. sage/combinat/posets/forest.py +30 -0
  60. sage/combinat/posets/hasse_cython.cpython-39-aarch64-linux-gnu.so +0 -0
  61. sage/combinat/posets/hasse_cython.pyx +174 -0
  62. sage/combinat/posets/hasse_diagram.py +3678 -0
  63. sage/combinat/posets/incidence_algebras.py +796 -0
  64. sage/combinat/posets/lattices.py +5119 -0
  65. sage/combinat/posets/linear_extension_iterator.cpython-39-aarch64-linux-gnu.so +0 -0
  66. sage/combinat/posets/linear_extension_iterator.pyx +292 -0
  67. sage/combinat/posets/linear_extensions.py +1039 -0
  68. sage/combinat/posets/mobile.py +275 -0
  69. sage/combinat/posets/moebius_algebra.py +776 -0
  70. sage/combinat/posets/poset_examples.py +2131 -0
  71. sage/combinat/posets/posets.py +9169 -0
  72. sage/combinat/rooted_tree.py +1070 -0
  73. sage/combinat/shard_order.py +239 -0
  74. sage/combinat/tamari_lattices.py +384 -0
  75. sage/combinat/yang_baxter_graph.py +923 -0
  76. sage/databases/all__sagemath_graphs.py +1 -0
  77. sage/databases/knotinfo_db.py +1230 -0
  78. sage/ext_data/all__sagemath_graphs.py +1 -0
  79. sage/ext_data/graphs/graph_plot_js.html +330 -0
  80. sage/ext_data/kenzo/CP2.txt +45 -0
  81. sage/ext_data/kenzo/CP3.txt +349 -0
  82. sage/ext_data/kenzo/CP4.txt +4774 -0
  83. sage/ext_data/kenzo/README.txt +49 -0
  84. sage/ext_data/kenzo/S4.txt +20 -0
  85. sage/graphs/all.py +42 -0
  86. sage/graphs/asteroidal_triples.cpython-39-aarch64-linux-gnu.so +0 -0
  87. sage/graphs/asteroidal_triples.pyx +299 -0
  88. sage/graphs/base/all.py +1 -0
  89. sage/graphs/base/boost_graph.cpython-39-aarch64-linux-gnu.so +0 -0
  90. sage/graphs/base/boost_graph.pxd +106 -0
  91. sage/graphs/base/boost_graph.pyx +3045 -0
  92. sage/graphs/base/c_graph.cpython-39-aarch64-linux-gnu.so +0 -0
  93. sage/graphs/base/c_graph.pxd +106 -0
  94. sage/graphs/base/c_graph.pyx +5096 -0
  95. sage/graphs/base/dense_graph.cpython-39-aarch64-linux-gnu.so +0 -0
  96. sage/graphs/base/dense_graph.pxd +26 -0
  97. sage/graphs/base/dense_graph.pyx +757 -0
  98. sage/graphs/base/graph_backends.cpython-39-aarch64-linux-gnu.so +0 -0
  99. sage/graphs/base/graph_backends.pxd +5 -0
  100. sage/graphs/base/graph_backends.pyx +797 -0
  101. sage/graphs/base/overview.py +85 -0
  102. sage/graphs/base/sparse_graph.cpython-39-aarch64-linux-gnu.so +0 -0
  103. sage/graphs/base/sparse_graph.pxd +90 -0
  104. sage/graphs/base/sparse_graph.pyx +1653 -0
  105. sage/graphs/base/static_dense_graph.cpython-39-aarch64-linux-gnu.so +0 -0
  106. sage/graphs/base/static_dense_graph.pxd +5 -0
  107. sage/graphs/base/static_dense_graph.pyx +1032 -0
  108. sage/graphs/base/static_sparse_backend.cpython-39-aarch64-linux-gnu.so +0 -0
  109. sage/graphs/base/static_sparse_backend.pxd +27 -0
  110. sage/graphs/base/static_sparse_backend.pyx +1580 -0
  111. sage/graphs/base/static_sparse_graph.cpython-39-aarch64-linux-gnu.so +0 -0
  112. sage/graphs/base/static_sparse_graph.pxd +37 -0
  113. sage/graphs/base/static_sparse_graph.pyx +1304 -0
  114. sage/graphs/bipartite_graph.py +2709 -0
  115. sage/graphs/centrality.cpython-39-aarch64-linux-gnu.so +0 -0
  116. sage/graphs/centrality.pyx +965 -0
  117. sage/graphs/cographs.py +519 -0
  118. sage/graphs/comparability.cpython-39-aarch64-linux-gnu.so +0 -0
  119. sage/graphs/comparability.pyx +813 -0
  120. sage/graphs/connectivity.cpython-39-aarch64-linux-gnu.so +0 -0
  121. sage/graphs/connectivity.pxd +157 -0
  122. sage/graphs/connectivity.pyx +4813 -0
  123. sage/graphs/convexity_properties.cpython-39-aarch64-linux-gnu.so +0 -0
  124. sage/graphs/convexity_properties.pxd +16 -0
  125. sage/graphs/convexity_properties.pyx +827 -0
  126. sage/graphs/digraph.py +4410 -0
  127. sage/graphs/digraph_generators.py +1921 -0
  128. sage/graphs/distances_all_pairs.cpython-39-aarch64-linux-gnu.so +0 -0
  129. sage/graphs/distances_all_pairs.pxd +12 -0
  130. sage/graphs/distances_all_pairs.pyx +2938 -0
  131. sage/graphs/domination.py +1363 -0
  132. sage/graphs/dot2tex_utils.py +100 -0
  133. sage/graphs/edge_connectivity.cpython-39-aarch64-linux-gnu.so +0 -0
  134. sage/graphs/edge_connectivity.pyx +1215 -0
  135. sage/graphs/generators/all.py +1 -0
  136. sage/graphs/generators/basic.py +1769 -0
  137. sage/graphs/generators/chessboard.py +538 -0
  138. sage/graphs/generators/classical_geometries.py +1611 -0
  139. sage/graphs/generators/degree_sequence.py +235 -0
  140. sage/graphs/generators/distance_regular.cpython-39-aarch64-linux-gnu.so +0 -0
  141. sage/graphs/generators/distance_regular.pyx +2846 -0
  142. sage/graphs/generators/families.py +4749 -0
  143. sage/graphs/generators/intersection.py +565 -0
  144. sage/graphs/generators/platonic_solids.py +262 -0
  145. sage/graphs/generators/random.py +2623 -0
  146. sage/graphs/generators/smallgraphs.py +5741 -0
  147. sage/graphs/generators/world_map.py +724 -0
  148. sage/graphs/generic_graph.py +26395 -0
  149. sage/graphs/generic_graph_pyx.cpython-39-aarch64-linux-gnu.so +0 -0
  150. sage/graphs/generic_graph_pyx.pxd +34 -0
  151. sage/graphs/generic_graph_pyx.pyx +1626 -0
  152. sage/graphs/genus.cpython-39-aarch64-linux-gnu.so +0 -0
  153. sage/graphs/genus.pyx +623 -0
  154. sage/graphs/graph.py +9362 -0
  155. sage/graphs/graph_coloring.cpython-39-aarch64-linux-gnu.so +0 -0
  156. sage/graphs/graph_coloring.pyx +2284 -0
  157. sage/graphs/graph_database.py +1122 -0
  158. sage/graphs/graph_decompositions/all.py +1 -0
  159. sage/graphs/graph_decompositions/bandwidth.cpython-39-aarch64-linux-gnu.so +0 -0
  160. sage/graphs/graph_decompositions/bandwidth.pyx +428 -0
  161. sage/graphs/graph_decompositions/clique_separators.cpython-39-aarch64-linux-gnu.so +0 -0
  162. sage/graphs/graph_decompositions/clique_separators.pyx +595 -0
  163. sage/graphs/graph_decompositions/cutwidth.cpython-39-aarch64-linux-gnu.so +0 -0
  164. sage/graphs/graph_decompositions/cutwidth.pyx +753 -0
  165. sage/graphs/graph_decompositions/fast_digraph.cpython-39-aarch64-linux-gnu.so +0 -0
  166. sage/graphs/graph_decompositions/fast_digraph.pxd +13 -0
  167. sage/graphs/graph_decompositions/fast_digraph.pyx +212 -0
  168. sage/graphs/graph_decompositions/graph_products.cpython-39-aarch64-linux-gnu.so +0 -0
  169. sage/graphs/graph_decompositions/graph_products.pyx +462 -0
  170. sage/graphs/graph_decompositions/modular_decomposition.cpython-39-aarch64-linux-gnu.so +0 -0
  171. sage/graphs/graph_decompositions/modular_decomposition.pxd +27 -0
  172. sage/graphs/graph_decompositions/modular_decomposition.pyx +1536 -0
  173. sage/graphs/graph_decompositions/slice_decomposition.cpython-39-aarch64-linux-gnu.so +0 -0
  174. sage/graphs/graph_decompositions/slice_decomposition.pxd +18 -0
  175. sage/graphs/graph_decompositions/slice_decomposition.pyx +1080 -0
  176. sage/graphs/graph_decompositions/tree_decomposition.cpython-39-aarch64-linux-gnu.so +0 -0
  177. sage/graphs/graph_decompositions/tree_decomposition.pxd +17 -0
  178. sage/graphs/graph_decompositions/tree_decomposition.pyx +1996 -0
  179. sage/graphs/graph_decompositions/vertex_separation.cpython-39-aarch64-linux-gnu.so +0 -0
  180. sage/graphs/graph_decompositions/vertex_separation.pxd +5 -0
  181. sage/graphs/graph_decompositions/vertex_separation.pyx +1963 -0
  182. sage/graphs/graph_editor.py +82 -0
  183. sage/graphs/graph_generators.py +3301 -0
  184. sage/graphs/graph_generators_pyx.cpython-39-aarch64-linux-gnu.so +0 -0
  185. sage/graphs/graph_generators_pyx.pyx +95 -0
  186. sage/graphs/graph_input.py +812 -0
  187. sage/graphs/graph_latex.py +2064 -0
  188. sage/graphs/graph_list.py +367 -0
  189. sage/graphs/graph_plot.py +1749 -0
  190. sage/graphs/graph_plot_js.py +338 -0
  191. sage/graphs/hyperbolicity.cpython-39-aarch64-linux-gnu.so +0 -0
  192. sage/graphs/hyperbolicity.pyx +1702 -0
  193. sage/graphs/hypergraph_generators.py +364 -0
  194. sage/graphs/independent_sets.cpython-39-aarch64-linux-gnu.so +0 -0
  195. sage/graphs/independent_sets.pxd +13 -0
  196. sage/graphs/independent_sets.pyx +402 -0
  197. sage/graphs/isgci.py +1033 -0
  198. sage/graphs/isoperimetric_inequalities.cpython-39-aarch64-linux-gnu.so +0 -0
  199. sage/graphs/isoperimetric_inequalities.pyx +453 -0
  200. sage/graphs/line_graph.cpython-39-aarch64-linux-gnu.so +0 -0
  201. sage/graphs/line_graph.pyx +627 -0
  202. sage/graphs/lovasz_theta.py +77 -0
  203. sage/graphs/matching.py +1633 -0
  204. sage/graphs/matching_covered_graph.py +3566 -0
  205. sage/graphs/orientations.py +1504 -0
  206. sage/graphs/partial_cube.py +459 -0
  207. sage/graphs/path_enumeration.cpython-39-aarch64-linux-gnu.so +0 -0
  208. sage/graphs/path_enumeration.pyx +2040 -0
  209. sage/graphs/pq_trees.py +1129 -0
  210. sage/graphs/print_graphs.py +201 -0
  211. sage/graphs/schnyder.py +865 -0
  212. sage/graphs/spanning_tree.cpython-39-aarch64-linux-gnu.so +0 -0
  213. sage/graphs/spanning_tree.pyx +1457 -0
  214. sage/graphs/strongly_regular_db.cpython-39-aarch64-linux-gnu.so +0 -0
  215. sage/graphs/strongly_regular_db.pyx +3340 -0
  216. sage/graphs/traversals.cpython-39-aarch64-linux-gnu.so +0 -0
  217. sage/graphs/traversals.pxd +9 -0
  218. sage/graphs/traversals.pyx +1871 -0
  219. sage/graphs/trees.cpython-39-aarch64-linux-gnu.so +0 -0
  220. sage/graphs/trees.pxd +15 -0
  221. sage/graphs/trees.pyx +310 -0
  222. sage/graphs/tutte_polynomial.py +713 -0
  223. sage/graphs/views.cpython-39-aarch64-linux-gnu.so +0 -0
  224. sage/graphs/views.pyx +794 -0
  225. sage/graphs/weakly_chordal.cpython-39-aarch64-linux-gnu.so +0 -0
  226. sage/graphs/weakly_chordal.pyx +562 -0
  227. sage/groups/all__sagemath_graphs.py +1 -0
  228. sage/groups/perm_gps/all__sagemath_graphs.py +1 -0
  229. sage/groups/perm_gps/partn_ref/all__sagemath_graphs.py +1 -0
  230. sage/groups/perm_gps/partn_ref/refinement_graphs.cpython-39-aarch64-linux-gnu.so +0 -0
  231. sage/groups/perm_gps/partn_ref/refinement_graphs.pxd +38 -0
  232. sage/groups/perm_gps/partn_ref/refinement_graphs.pyx +1666 -0
  233. sage/knots/all.py +6 -0
  234. sage/knots/free_knotinfo_monoid.py +507 -0
  235. sage/knots/gauss_code.py +291 -0
  236. sage/knots/knot.py +682 -0
  237. sage/knots/knot_table.py +284 -0
  238. sage/knots/knotinfo.py +2880 -0
  239. sage/knots/link.py +4682 -0
  240. sage/sandpiles/all.py +13 -0
  241. sage/sandpiles/examples.py +225 -0
  242. sage/sandpiles/sandpile.py +6365 -0
  243. sage/topology/all.py +22 -0
  244. sage/topology/cell_complex.py +1214 -0
  245. sage/topology/cubical_complex.py +1977 -0
  246. sage/topology/delta_complex.py +1806 -0
  247. sage/topology/filtered_simplicial_complex.py +744 -0
  248. sage/topology/moment_angle_complex.py +823 -0
  249. sage/topology/simplicial_complex.py +5161 -0
  250. sage/topology/simplicial_complex_catalog.py +86 -0
  251. sage/topology/simplicial_complex_examples.py +1692 -0
  252. sage/topology/simplicial_complex_homset.py +205 -0
  253. sage/topology/simplicial_complex_morphism.py +836 -0
  254. sage/topology/simplicial_set.py +4102 -0
  255. sage/topology/simplicial_set_catalog.py +55 -0
  256. sage/topology/simplicial_set_constructions.py +2954 -0
  257. sage/topology/simplicial_set_examples.py +865 -0
  258. sage/topology/simplicial_set_morphism.py +1464 -0
@@ -0,0 +1,595 @@
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_graph cimport short_digraph
30
+ from sage.graphs.base.static_sparse_graph cimport init_short_digraph
31
+ from sage.graphs.base.static_sparse_graph cimport free_short_digraph
32
+ from sage.graphs.base.static_sparse_graph cimport has_edge
33
+
34
+ from sage.sets.set import Set
35
+ from sage.graphs.traversals cimport maximum_cardinality_search_M_short_digraph
36
+
37
+
38
+ def make_tree(atoms, cliques):
39
+ r"""
40
+ Return a tree of atoms and cliques.
41
+
42
+ The atoms are the leaves of the tree and the cliques are the internal
43
+ vertices. The number of atoms is the number of cliques plus one.
44
+
45
+ As a clique may appear several times in the list ``cliques``, vertices are
46
+ numbered by pairs `(i, S)`, where `0 \leq i < |atoms| + |cliques|` and `S`
47
+ is either an atom or a clique.
48
+
49
+ The root of the tree is the only vertex with even or null degree, i.e., 0 if
50
+ ``cliques`` is empty and 2 otherwise. When ``cliques`` is not empty, other
51
+ internal vertices (each of which is a clique) have degree 3, and the
52
+ leaves (vertices of degree 1) are the atoms.
53
+
54
+ INPUT:
55
+
56
+ - ``atoms`` -- list of atoms
57
+
58
+ - ``cliques`` -- list of cliques
59
+
60
+ EXAMPLES::
61
+
62
+ sage: from sage.graphs.graph_decompositions.clique_separators import make_tree
63
+ sage: G = graphs.Grid2dGraph(2, 4)
64
+ sage: A, Sc = G.atoms_and_clique_separators()
65
+ sage: T = make_tree(A, Sc)
66
+ sage: all(u[1] in A for u in T if T.degree(u) == 1)
67
+ True
68
+ sage: all(u[1] in Sc for u in T if T.degree(u) != 1)
69
+ True
70
+
71
+ TESTS::
72
+
73
+ sage: from sage.graphs.graph_decompositions.clique_separators import make_tree
74
+ sage: make_tree([0], [1, 2])
75
+ Traceback (most recent call last):
76
+ ...
77
+ ValueError: the number of atoms must be the number of cliques plus one
78
+ """
79
+ if (atoms or cliques) and len(atoms) != len(cliques) + 1:
80
+ raise ValueError("the number of atoms must be the number of cliques plus one")
81
+
82
+ from sage.graphs.graph import Graph
83
+ T = Graph()
84
+ if cliques:
85
+ # As a clique can appear several times, we number the vertices by
86
+ # pairs (int, Set), with 0 <= int < |atoms| + |cliques|
87
+ T.add_path(list(enumerate(cliques)))
88
+ j = len(cliques)
89
+ T.add_edges((s, (i + j, a)) for s, (i, a) in zip(enumerate(cliques), enumerate(atoms)))
90
+ # We have |atoms| = |cliques| + 1. So |atoms| + |cliques| = 2 * j + 1
91
+ T.add_edge((j - 1, cliques[-1]), (2 * j, atoms[-1]))
92
+
93
+ elif atoms:
94
+ # The graph has no clique separator
95
+ T.add_vertex(atoms[0])
96
+
97
+ return T
98
+
99
+
100
+ def make_labelled_rooted_tree(atoms, cliques):
101
+ r"""
102
+ Return a :class:`~LabelledRootedTree` of atoms and cliques.
103
+
104
+ The atoms are the leaves of the tree and the cliques are the internal
105
+ vertices. The number of atoms is the number of cliques plus one.
106
+
107
+ EXAMPLES::
108
+
109
+ sage: G = graphs.PathGraph(5)
110
+ sage: ascii_art(G.atoms_and_clique_separators(rooted_tree=True))
111
+ _____{3}_____
112
+ / /
113
+ {3, 4} ____{2}____
114
+ / /
115
+ {2, 3} __{1}__
116
+ / /
117
+ {0, 1} {1, 2}
118
+
119
+ TESTS::
120
+
121
+ sage: from sage.graphs.graph_decompositions.clique_separators import make_labelled_rooted_tree
122
+ sage: make_labelled_rooted_tree([0], [1, 2])
123
+ Traceback (most recent call last):
124
+ ...
125
+ ValueError: the number of atoms must be the number of cliques plus one
126
+ """
127
+ from sage.combinat.rooted_tree import LabelledRootedTree
128
+ if not atoms and not cliques:
129
+ return LabelledRootedTree([])
130
+
131
+ if len(atoms) != len(cliques) + 1:
132
+ raise ValueError("the number of atoms must be the number of cliques plus one")
133
+
134
+ def to_tree(i, n):
135
+ if i < n:
136
+ return LabelledRootedTree([LabelledRootedTree([], label=atoms[i]), to_tree(i + 1, n)],
137
+ label=cliques[i])
138
+ return LabelledRootedTree([], label=atoms[i])
139
+
140
+ return to_tree(0, len(cliques))
141
+
142
+
143
+ cdef inline bint is_clique(short_digraph sd, vector[int] Hx) noexcept:
144
+ """
145
+ Check if the subgraph sd[Hx] is a clique.
146
+
147
+ This is a helper function of ``atoms_and_clique_separators``.
148
+ """
149
+ cdef size_t Hx_size = Hx.size()
150
+ cdef size_t i, j
151
+ cdef int u
152
+ for i in range(Hx_size - 1):
153
+ u = Hx[i]
154
+ for j in range(i + 1, Hx_size):
155
+ if not has_edge(sd, u, Hx[j]):
156
+ return False
157
+ return True
158
+
159
+
160
+ def atoms_and_clique_separators(G, tree=False, rooted_tree=False, separators=False):
161
+ r"""
162
+ Return the atoms of the decomposition of `G` by clique minimal separators.
163
+
164
+ Let `G = (V, E)` be a graph. A set `S \subset V` is a clique separator if
165
+ `G[S]` is a clique and the graph `G \setminus S` has at least 2 connected
166
+ components. Let `C \subset V` be the vertices of a connected component of `G
167
+ \setminus S`. The graph `G[C + S]` is an *atom* if it has no clique
168
+ separator.
169
+
170
+ This method implements the algorithm proposed in [BPS2010]_, that improves
171
+ upon the algorithm proposed in [TY1984]_, for computing the atoms and the
172
+ clique minimal separators of a graph. This algorithm is based on the
173
+ :meth:`~sage.graphs.traversals.maximum_cardinality_search_M` graph traversal
174
+ and has time complexity in `O(|V|\cdot|E|)`.
175
+
176
+ If the graph is not connected, we insert empty separators between the lists
177
+ of separators of each connected components. See the examples below for more
178
+ details.
179
+
180
+ INPUT:
181
+
182
+ - ``G`` -- a Sage graph
183
+
184
+ - ``tree`` -- boolean (default: ``False``); whether to return the result as
185
+ a directed tree in which internal nodes are clique separators and leaves
186
+ are the atoms of the decomposition. Since a clique separator is repeated
187
+ when its removal partition the graph into 3 or more connected components,
188
+ vertices are labels by tuples `(i, S)`, where `S` is the set of vertices
189
+ of the atom or the clique separator, and `0 \leq i \leq |T|`.
190
+
191
+ - ``rooted_tree`` -- boolean (default: ``False``); whether to return the
192
+ result as a :class:`~sage.combinat.rooted_tree.LabelledRootedTree`. When
193
+ ``tree`` is ``True``, this parameter is ignored.
194
+
195
+ - ``separators`` -- boolean (default: ``False``); whether to also return the
196
+ complete list of separators considered during the execution of the
197
+ algorithm. When ``tree`` or ``rooted_tree`` is ``True``, this parameter is
198
+ ignored.
199
+
200
+ OUTPUT:
201
+
202
+ - By default, return a tuple `(A, S_c)`, where `A` is the list of atoms of
203
+ the graph in the order of discovery, and `S_c` is the list of clique
204
+ separators, with possible repetitions, in the order the separator has been
205
+ considered. If furthermore ``separators`` is ``True``, return a tuple `(A,
206
+ S_h, S_c)`, where `S_c` is the list of considered separators of the graph
207
+ in the order they have been considered.
208
+
209
+ - When ``tree`` is ``True``, format the result as a directed tree
210
+
211
+ - When ``rooted_tree`` is ``True`` and ``tree`` is ``False``, format the
212
+ output as a :class:`~sage.combinat.rooted_tree.LabelledRootedTree`
213
+
214
+ EXAMPLES:
215
+
216
+ Example of [BPS2010]_::
217
+
218
+ sage: G = Graph({'a': ['b', 'k'], 'b': ['c'], 'c': ['d', 'j', 'k'],
219
+ ....: 'd': ['e', 'f', 'j', 'k'], 'e': ['g'],
220
+ ....: 'f': ['g', 'j', 'k'], 'g': ['j', 'k'], 'h': ['i', 'j'],
221
+ ....: 'i': ['k'], 'j': ['k']})
222
+ sage: atoms, cliques = G.atoms_and_clique_separators()
223
+ sage: sorted(sorted(a) for a in atoms)
224
+ [['a', 'b', 'c', 'k'],
225
+ ['c', 'd', 'j', 'k'],
226
+ ['d', 'e', 'f', 'g', 'j', 'k'],
227
+ ['h', 'i', 'j', 'k']]
228
+ sage: sorted(sorted(c) for c in cliques)
229
+ [['c', 'k'], ['d', 'j', 'k'], ['j', 'k']]
230
+ sage: T = G.atoms_and_clique_separators(tree=True)
231
+ sage: T.is_tree()
232
+ True
233
+ sage: T.diameter() == len(atoms)
234
+ True
235
+ sage: all(u[1] in atoms for u in T if T.degree(u) == 1)
236
+ True
237
+ sage: all(u[1] in cliques for u in T if T.degree(u) != 1)
238
+ True
239
+
240
+ A graph without clique separator::
241
+
242
+ sage: G = graphs.CompleteGraph(5)
243
+ sage: G.atoms_and_clique_separators()
244
+ ([{0, 1, 2, 3, 4}], [])
245
+ sage: ascii_art(G.atoms_and_clique_separators(rooted_tree=True))
246
+ {0, 1, 2, 3, 4}
247
+
248
+ Graphs with several biconnected components::
249
+
250
+ sage: G = graphs.PathGraph(4)
251
+ sage: ascii_art(G.atoms_and_clique_separators(rooted_tree=True))
252
+ ____{2}____
253
+ / /
254
+ {2, 3} __{1}__
255
+ / /
256
+ {1, 2} {0, 1}
257
+
258
+ sage: G = graphs.WindmillGraph(3, 4)
259
+ sage: G.atoms_and_clique_separators()
260
+ ([{0, 1, 2}, {0, 3, 4}, {0, 5, 6}, {0, 8, 7}], [{0}, {0}, {0}])
261
+ sage: ascii_art(G.atoms_and_clique_separators(rooted_tree=True))
262
+ ________{0}________
263
+ / /
264
+ {0, 1, 2} _______{0}______
265
+ / /
266
+ {0, 3, 4} ____{0}___
267
+ / /
268
+ {0, 8, 7} {0, 5, 6}
269
+
270
+ When the removal of a clique separator results in `k > 2` connected
271
+ components, this separator is repeated `k - 1` times, but the repetitions
272
+ are not necessarily contiguous::
273
+
274
+ sage: G = Graph(2)
275
+ sage: for i in range(5):
276
+ ....: G.add_cycle([0, 1, G.add_vertex()])
277
+ sage: ascii_art(G.atoms_and_clique_separators(rooted_tree=True))
278
+ _________{0, 1}_____
279
+ / /
280
+ {0, 1, 4} ________{0, 1}_____
281
+ / /
282
+ {0, 1, 2} _______{0, 1}___
283
+ / /
284
+ {0, 1, 3} ____{0, 1}
285
+ / /
286
+ {0, 1, 5} {0, 1, 6}
287
+
288
+ sage: G = graphs.StarGraph(3)
289
+ sage: G.subdivide_edges(G.edges(sort=False), 2)
290
+ sage: ascii_art(G.atoms_and_clique_separators(rooted_tree=True))
291
+ ______{5}______
292
+ / /
293
+ {1, 5} ______{7}______
294
+ / /
295
+ {2, 7} ______{9}______
296
+ / /
297
+ {9, 3} ______{6}______
298
+ / /
299
+ {6, 7} ______{4}_____
300
+ / /
301
+ {4, 5} _____{0}_____
302
+ / /
303
+ {0, 6} ____{8}____
304
+ / /
305
+ {8, 9} __{0}__
306
+ / /
307
+ {0, 8} {0, 4}
308
+
309
+ If the graph is not connected, we insert empty separators between the lists
310
+ of separators of each connected components. For instance, let `G` be a graph
311
+ with 3 connected components. The method returns the list `S_c =
312
+ [S_0,\cdots,S_{i},\ldots, S_{j},\ldots,S_{k-1}]` of `k` clique separators,
313
+ where `i` and `j` are the indexes of the inserted empty separators and `0
314
+ \leq i < j < k - 1`. The method also returns the list `A =
315
+ [A_0,\ldots,S_{k}]` of the `k + 1` atoms, with `k + 1 \geq 3`. The lists of
316
+ atoms and clique separators of each of the connected components are
317
+ respectively `[A_0,\ldots,A_{i}]` and `[S_0,\ldots,S_{i-1}]`,
318
+ `[A_{i+1},\ldots,A_{j}]` and `[S_{i+1},\ldots,S_{j-1}]`, and
319
+ `[A_{j+1},\ldots,A_{k}]` and `[S_{j+1},\ldots,S_{k-1}]`. One can check that
320
+ for each connected component, we get one atom more than clique separators::
321
+
322
+ sage: G = graphs.PathGraph(3) * 3
323
+ sage: A, Sc = G.atoms_and_clique_separators()
324
+ sage: A
325
+ [{1, 2}, {0, 1}, {4, 5}, {3, 4}, {8, 7}, {6, 7}]
326
+ sage: Sc
327
+ [{1}, {}, {4}, {}, {7}]
328
+ sage: i , j = [i for i, s in enumerate(Sc) if not s]
329
+ sage: i, j
330
+ (1, 3)
331
+ sage: A[:i+1], Sc[:i]
332
+ ([{1, 2}, {0, 1}], [{1}])
333
+ sage: A[i+1:j+1], Sc[i+1:j]
334
+ ([{4, 5}, {3, 4}], [{4}])
335
+ sage: A[j+1:], Sc[j+1:]
336
+ ([{8, 7}, {6, 7}], [{7}])
337
+ sage: I = [-1, i, j, len(Sc)]
338
+ sage: for i, j in zip(I[:-1], I[1:]):
339
+ ....: print(A[i+1:j+1], Sc[i+1:j])
340
+ [{1, 2}, {0, 1}] [{1}]
341
+ [{4, 5}, {3, 4}] [{4}]
342
+ [{8, 7}, {6, 7}] [{7}]
343
+ sage: ascii_art(G.atoms_and_clique_separators(rooted_tree=True))
344
+ ______{1}______
345
+ / /
346
+ {1, 2} ______{}______
347
+ / /
348
+ {0, 1} _____{4}_____
349
+ / /
350
+ {4, 5} ____{}_____
351
+ / /
352
+ {3, 4} __{7}__
353
+ / /
354
+ {6, 7} {8, 7}
355
+
356
+ Loops and multiple edges are ignored::
357
+
358
+ sage: G.allow_loops(True)
359
+ sage: G.add_edges([(u, u) for u in G])
360
+ sage: G.allow_multiple_edges(True)
361
+ sage: G.add_edges(G.edges(sort=False))
362
+ sage: ascii_art(G.atoms_and_clique_separators(rooted_tree=True))
363
+ ______{1}______
364
+ / /
365
+ {1, 2} ______{}______
366
+ / /
367
+ {0, 1} _____{4}_____
368
+ / /
369
+ {4, 5} ____{}_____
370
+ / /
371
+ {3, 4} __{7}__
372
+ / /
373
+ {6, 7} {8, 7}
374
+
375
+ We can check that the returned list of separators is valid::
376
+
377
+ sage: G = graphs.RandomGNP(50, .1)
378
+ sage: while not G.is_connected():
379
+ ....: G = graphs.RandomGNP(50, .1)
380
+ sage: _, separators, _ = G.atoms_and_clique_separators(separators=True)
381
+ sage: for S in separators:
382
+ ....: H = G.copy()
383
+ ....: H.delete_vertices(S)
384
+ ....: if H.is_connected():
385
+ ....: raise ValueError("something goes wrong")
386
+
387
+ TESTS::
388
+
389
+ sage: EmptyGraph = Graph()
390
+ sage: EmptyGraph.atoms_and_clique_separators()
391
+ ([], [])
392
+ sage: EmptyGraph.atoms_and_clique_separators(separators=True)
393
+ ([], [], [])
394
+ sage: EmptyGraph.atoms_and_clique_separators(tree=True)
395
+ Graph on 0 vertices
396
+ sage: EmptyGraph.atoms_and_clique_separators(rooted_tree=True)
397
+ None[]
398
+ sage: ascii_art(EmptyGraph.atoms_and_clique_separators(rooted_tree=True))
399
+ None
400
+ sage: I4 = Graph(4)
401
+ sage: I4.atoms_and_clique_separators()
402
+ ([{0}, {1}, {2}, {3}], [{}, {}, {}])
403
+ sage: I4.atoms_and_clique_separators(separators=True)
404
+ ([{0}, {1}, {2}, {3}], [{}, {}, {}], [{}, {}, {}])
405
+ sage: I4.atoms_and_clique_separators(tree=True)
406
+ Graph on 7 vertices
407
+ sage: I4.atoms_and_clique_separators(rooted_tree=True)
408
+ {}[{0}[], {}[{1}[], {}[{3}[], {2}[]]]]
409
+ sage: ascii_art(I4.atoms_and_clique_separators(rooted_tree=True))
410
+ ___{}___
411
+ / /
412
+ {0} __{}___
413
+ / /
414
+ {1} _{}_
415
+ / /
416
+ {3} {2}
417
+ """
418
+ cdef list A = [] # atoms
419
+ cdef list Sh = [] # separators
420
+ cdef list Sc = [] # clique separators
421
+ cdef bint first = True
422
+
423
+ if not G.is_connected():
424
+ from sage.graphs.graph import Graph
425
+
426
+ for cc in G.connected_components(sort=False):
427
+ g = Graph([cc, G.edge_boundary(cc, cc, False, False)],
428
+ format='vertices_and_edges',
429
+ loops=True, multiedges=True)
430
+ res = g.atoms_and_clique_separators(tree=False, rooted_tree=False, separators=separators)
431
+
432
+ # Update lists of atoms, separators and clique separators
433
+ A.extend(res[0])
434
+ if separators:
435
+ if not first:
436
+ Sh.append(Set())
437
+ Sh.extend(res[1])
438
+ if not first:
439
+ Sc.append(Set())
440
+ if separators:
441
+ Sc.extend(res[2])
442
+ else:
443
+ Sc.extend(res[1])
444
+ first = False
445
+
446
+ # Format and return the result
447
+ if tree:
448
+ return make_tree(A, Sc)
449
+ elif rooted_tree:
450
+ return make_labelled_rooted_tree(A, Sc)
451
+ elif separators:
452
+ return A, Sh, Sc
453
+ return A, Sc
454
+
455
+ cdef int N = G.order()
456
+ cdef list int_to_vertex = list(G)
457
+
458
+ # Copying the whole graph to obtain the list of neighbors quicker than by
459
+ # calling out_neighbors. This data structure is well documented in the
460
+ # module sage.graphs.base.static_sparse_graph
461
+ cdef short_digraph sd
462
+ init_short_digraph(sd, G, edge_labelled=False, vertex_list=int_to_vertex)
463
+
464
+ # variables for the manipulation of the short digraph
465
+ cdef uint32_t** p_vertices = sd.neighbors
466
+ cdef uint32_t* p_tmp
467
+ cdef uint32_t* p_end
468
+
469
+ cdef MemoryAllocator mem = MemoryAllocator()
470
+ cdef int* alpha = <int*>mem.calloc(N, sizeof(int))
471
+ cdef int* alpha_inv = <int*>mem.calloc(N, sizeof(int))
472
+ cdef bint* X = <bint*>mem.calloc(N, sizeof(bint))
473
+ cdef bint* active = <bint*>mem.calloc(N, sizeof(bint))
474
+ cdef int* waiting_list = <int*>mem.calloc(N, sizeof(int))
475
+ cdef int* seen = <int*>mem.calloc(N, sizeof(int))
476
+ cdef list F = []
477
+ cdef int u, v, waiting_begin, waiting_end
478
+
479
+ sig_on()
480
+ maximum_cardinality_search_M_short_digraph(sd, 0, alpha, alpha_inv, F, X)
481
+ sig_off()
482
+
483
+ # Instead of building the graph H of the triangulation, extracting the
484
+ # neighbors of vertex alpha[i] and then removing that vertex from H, we
485
+ # directly build the neighborhoods. Note that vertices are removed from the
486
+ # graph of the triangulation in the order of alpha. Hence, at step i, this
487
+ # graph has no vertex u such that alpha_inv[u] < i, and edge (u, v) is
488
+ # removed from the graph when min(alpha_inv[u], alpha_inv[v]) is removed.
489
+ # The neighborhood of x at step i is thus {v in N_H(x) | alpha_inv[v] > i}.
490
+ cdef vector[vector[int]] H
491
+ H.resize(N)
492
+ for u in range(N):
493
+ p_tmp = p_vertices[u]
494
+ p_end = p_vertices[u + 1]
495
+ while p_tmp < p_end:
496
+ v = p_tmp[0]
497
+ p_tmp += 1
498
+ if u < v:
499
+ # We consider edge (u, v) only once, when u > v, and the
500
+ # short_digraph data structure ensures that neighbors are sorted
501
+ break
502
+ if alpha_inv[u] < alpha_inv[v]:
503
+ if X[u]:
504
+ H[u].push_back(v)
505
+ elif X[v]:
506
+ H[v].push_back(u)
507
+ for u, v in F:
508
+ if alpha_inv[u] < alpha_inv[v]:
509
+ if X[u]:
510
+ H[u].push_back(v)
511
+ elif X[v]:
512
+ H[v].push_back(u)
513
+
514
+ # Instead of using a copy Gp of G and removing from it the vertices of the
515
+ # connected component of an atom after its discovery, we use an array of
516
+ # booleans to avoid visiting inactive vertices
517
+ for u in range(N):
518
+ active[u] = True
519
+ seen[u] = -1
520
+
521
+ cdef frozenset Sint
522
+ cdef vector[int] Sint_min
523
+ cdef vector[int] Cint
524
+ cdef vector[int] Hx
525
+
526
+ for i in range(N):
527
+ sig_check()
528
+ x = alpha[i]
529
+ if X[x] and not H[x].empty():
530
+ Hx = H[x]
531
+
532
+ if separators:
533
+ Sh.append(Set(int_to_vertex[u] for u in Hx))
534
+
535
+ if is_clique(sd, Hx):
536
+ # The subgraph G[H[x]] = G[S] is a clique.
537
+ # We extract the connected component of Gp - S containing x
538
+ Sint = frozenset(Hx)
539
+ Sint_min.clear()
540
+ Cint.clear()
541
+ Cint.push_back(x)
542
+ seen[x] = x
543
+ waiting_list[0] = x
544
+ waiting_begin = 0
545
+ waiting_end = 0
546
+ while waiting_begin <= waiting_end:
547
+
548
+ u = waiting_list[waiting_begin]
549
+ waiting_begin += 1
550
+ p_tmp = p_vertices[u]
551
+ end = p_vertices[u + 1]
552
+
553
+ while p_tmp < end:
554
+ v = p_tmp[0]
555
+ p_tmp += 1
556
+
557
+ if active[v] and seen[v] != x:
558
+ seen[v] = x
559
+ if v in Sint:
560
+ # We keep only the vertices of the clique
561
+ # separator incident to the connected component
562
+ # containing x
563
+ Sint_min.push_back(v)
564
+ else:
565
+ Cint.push_back(v)
566
+ waiting_end += 1
567
+ waiting_list[waiting_end] = v
568
+
569
+ # Store the atom Smin + C and the minimal clique separator Smin
570
+ Smin = Set(int_to_vertex[u] for u in Sint_min)
571
+ A.append(Set(Smin.set().union(int_to_vertex[u] for u in Cint)))
572
+ Sc.append(Smin)
573
+
574
+ # "Remove" the vertices of Cint from the graph Gp
575
+ for u in Cint:
576
+ active[u] = False
577
+
578
+ free_short_digraph(sd)
579
+ H.clear()
580
+
581
+ # We add the last atom
582
+ if Sc:
583
+ A.append(Set(int_to_vertex[x] for x in range(N) if active[x]))
584
+ elif G:
585
+ # The graph has no clique separator
586
+ A.append(Set(int_to_vertex))
587
+
588
+ # Format and return the result
589
+ if tree:
590
+ return make_tree(A, Sc)
591
+ elif rooted_tree:
592
+ return make_labelled_rooted_tree(A, Sc)
593
+ if separators:
594
+ return A, Sh, Sc
595
+ return A, Sc