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