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,508 @@
|
|
1
|
+
# sage_setup: distribution = sagemath-graphs
|
2
|
+
# cython: binding=True
|
3
|
+
r"""
|
4
|
+
Products of graphs
|
5
|
+
|
6
|
+
This module gathers everything related to graph products. At the moment it
|
7
|
+
contains an implementation of a recognition algorithm for graphs that can be
|
8
|
+
written as a Cartesian product of smaller ones.
|
9
|
+
|
10
|
+
Author:
|
11
|
+
|
12
|
+
- Nathann Cohen (May 2012 -- coded while watching the election of Francois
|
13
|
+
Hollande on TV)
|
14
|
+
|
15
|
+
Cartesian product of graphs -- the recognition problem
|
16
|
+
------------------------------------------------------
|
17
|
+
|
18
|
+
First, a definition:
|
19
|
+
|
20
|
+
**Definition** The Cartesian product of two graphs `G` and `H`, denoted
|
21
|
+
`G\square H`, is a graph defined on the pairs `(g, h)\in V(G)\times V(H)`.
|
22
|
+
|
23
|
+
Two elements `(g, h),(g', h')\in V(G\square H)` are adjacent in `G\square H`
|
24
|
+
if and only if :
|
25
|
+
|
26
|
+
- `g=g'` and `hh'\in H`; or
|
27
|
+
- `h=h'` and `gg'\in G`
|
28
|
+
|
29
|
+
Two remarks follow :
|
30
|
+
|
31
|
+
#. The Cartesian product is commutative
|
32
|
+
|
33
|
+
#. Any edge `uv` of a graph `G_1 \square \cdots \square G_k` can be given a
|
34
|
+
color `i` corresponding to the unique index `i` such that `u_i` and `v_i`
|
35
|
+
differ.
|
36
|
+
|
37
|
+
The problem that is of interest to us in the present module is the following:
|
38
|
+
|
39
|
+
**Recognition problem** Given a graph `G`, can we guess whether there exist
|
40
|
+
graphs `G_1, ..., G_k` such that `G=G_1\square \cdots \square G_k` ?
|
41
|
+
|
42
|
+
This problem can actually be solved, and the resulting factorization is
|
43
|
+
unique. What is explained below can be found in the book *Handbook of Product
|
44
|
+
Graphs* [HIK2011]_.
|
45
|
+
|
46
|
+
Everything is actually based on simple observations. Given a graph `G`, finding
|
47
|
+
out whether `G` can be written as the product of several graphs can be attempted
|
48
|
+
by trying to color its edges according to some rules. Indeed, if we are to color
|
49
|
+
the edges of `G` in such a way that each color class represents a factor of `G`,
|
50
|
+
we must ensure several things.
|
51
|
+
|
52
|
+
**Remark 1** In any cycle of `G` no color can appear exactly once.
|
53
|
+
|
54
|
+
Indeed, if only one edge `uv` of a cycle were labelled with color `i`, it
|
55
|
+
would mean that:
|
56
|
+
|
57
|
+
#. The only difference between `u` and `v` lies in their `i` th coordinate
|
58
|
+
|
59
|
+
#. It is possible to go from `u` to `v` by changing only coordinates
|
60
|
+
different from the `i` th
|
61
|
+
|
62
|
+
A contradiction indeed.
|
63
|
+
|
64
|
+
.. image:: ../../../media/cycle.png
|
65
|
+
|
66
|
+
That means that, for instance, the edges of a triangle necessarily have the
|
67
|
+
same color.
|
68
|
+
|
69
|
+
**Remark 2** If two consecutive edges `u_1u_2` and `u_2u_3` have different
|
70
|
+
colors, there necessarily exists a unique vertex `u_4` different from `u_2`
|
71
|
+
and incident to both `u_1` and `u_3`.
|
72
|
+
|
73
|
+
In this situation, opposed edges necessarily have the same colors because of
|
74
|
+
the previous remark.
|
75
|
+
|
76
|
+
.. image:: ../../../media/square.png
|
77
|
+
|
78
|
+
**1st criterion** : As a corollary, we know that:
|
79
|
+
|
80
|
+
#. If two vertices `u,v` have a *unique* common neighbor `x`, then `ux` and
|
81
|
+
`xv` have the same color.
|
82
|
+
|
83
|
+
#. If two vertices `u, v` have more that two common neighbors `x_1, ...,
|
84
|
+
x_k` then all edges between the `x_i` and the vertices of `u,v` have the
|
85
|
+
same color. This is also a consequence of the first remark.
|
86
|
+
|
87
|
+
**2nd criterion** : if two edges `uv` and `u'v'` of the product graph
|
88
|
+
`G\square H` are such that `d(u,u')+d(v,v')\neq d(u,v') + d(v,u')` then the
|
89
|
+
two edges `uv` and `u'v'` necessarily have the same color.
|
90
|
+
|
91
|
+
This is a consequence of the fact that for any two vertices `u,v` of
|
92
|
+
`G\square H` (where `u=(u_G,u_H)` and `v=(v_G,v_H)`), we have `d(u,v) =
|
93
|
+
d_G(u_G,v_G)+d_H(u_H,v_H)`. Indeed, a shortest path from `u` to `v` in
|
94
|
+
`G\square H` contains the information of a shortest path from `u_G` to `v_G`
|
95
|
+
in `G`, and a shortest path from `u_H` to `v_H` in `H`.
|
96
|
+
|
97
|
+
The algorithm
|
98
|
+
^^^^^^^^^^^^^
|
99
|
+
|
100
|
+
The previous remarks tell us that some edges are in some way equivalent to some
|
101
|
+
others, i.e. that their colors are equal. In order to compute the coloring we
|
102
|
+
are looking for, we therefore build a graph on the *edges* of a graph `G`,
|
103
|
+
linking two edges whenever they are found to be equivalent according to the
|
104
|
+
previous remarks.
|
105
|
+
|
106
|
+
All that is left to do is to compute the connected components of this new graph,
|
107
|
+
as each of them representing the edges of a factor. Of course, only one
|
108
|
+
connected component indicates that the graph has no factorization.
|
109
|
+
|
110
|
+
Then again, please refer to [HIK2011]_ for any technical question.
|
111
|
+
|
112
|
+
To Do
|
113
|
+
^^^^^
|
114
|
+
|
115
|
+
This implementation is made at Python level, and some parts of the algorithm
|
116
|
+
could be rewritten in Cython to save time. Especially when enumerating all pairs
|
117
|
+
of edges and computing their distances. This can easily be done in C with the
|
118
|
+
functions from the :mod:`sage.graphs.distances_all_pairs` module.
|
119
|
+
|
120
|
+
Methods
|
121
|
+
-------
|
122
|
+
"""
|
123
|
+
|
124
|
+
# ****************************************************************************
|
125
|
+
# Copyright (C) 2012 Nathann Cohen <nathann.cohen@gmail.com>
|
126
|
+
#
|
127
|
+
# This program is free software: you can redistribute it and/or modify
|
128
|
+
# it under the terms of the GNU General Public License as published by
|
129
|
+
# the Free Software Foundation, either version 2 of the License, or
|
130
|
+
# (at your option) any later version.
|
131
|
+
# https://www.gnu.org/licenses/
|
132
|
+
# ****************************************************************************
|
133
|
+
|
134
|
+
|
135
|
+
def is_cartesian_product(g, certificate=False, relabeling=False, immutable=None):
|
136
|
+
r"""
|
137
|
+
Test whether the graph is a Cartesian product.
|
138
|
+
|
139
|
+
INPUT:
|
140
|
+
|
141
|
+
- ``certificate`` -- boolean (default: ``False``); if ``certificate =
|
142
|
+
False`` (default) the method only returns ``True`` or ``False``
|
143
|
+
answers. If ``certificate = True``, the ``True`` answers are replaced by
|
144
|
+
the list of the factors of the graph.
|
145
|
+
|
146
|
+
- ``relabeling`` -- boolean (default: ``False``); if ``relabeling = True``
|
147
|
+
(implies ``certificate = True``), the method also returns a dictionary
|
148
|
+
associating to each vertex its natural coordinates as a vertex of a
|
149
|
+
product graph. If `g` is not a Cartesian product, ``None`` is returned
|
150
|
+
instead.
|
151
|
+
|
152
|
+
- ``immutable`` -- boolean (default: ``None``); whether to create a
|
153
|
+
mutable/immutable graph. ``immutable=None`` (default) means that the
|
154
|
+
graph and its factors will behave the same way.
|
155
|
+
|
156
|
+
.. SEEALSO::
|
157
|
+
|
158
|
+
- :meth:`sage.graphs.generic_graph.GenericGraph.cartesian_product`
|
159
|
+
|
160
|
+
- :mod:`~sage.graphs.graph_decompositions.graph_products` -- a module on
|
161
|
+
graph products
|
162
|
+
|
163
|
+
.. NOTE::
|
164
|
+
|
165
|
+
This algorithm may run faster whenever the graph's vertices are integers
|
166
|
+
(see :meth:`~sage.graphs.generic_graph.GenericGraph.relabel`). Give it a
|
167
|
+
try if it is too slow !
|
168
|
+
|
169
|
+
EXAMPLES:
|
170
|
+
|
171
|
+
The Petersen graph is prime::
|
172
|
+
|
173
|
+
sage: from sage.graphs.graph_decompositions.graph_products import is_cartesian_product
|
174
|
+
sage: g = graphs.PetersenGraph()
|
175
|
+
sage: is_cartesian_product(g)
|
176
|
+
False
|
177
|
+
|
178
|
+
A 2d grid is the product of paths::
|
179
|
+
|
180
|
+
sage: g = graphs.Grid2dGraph(5,5)
|
181
|
+
sage: p1, p2 = is_cartesian_product(g, certificate = True)
|
182
|
+
sage: p1.is_isomorphic(graphs.PathGraph(5))
|
183
|
+
True
|
184
|
+
sage: p2.is_isomorphic(graphs.PathGraph(5))
|
185
|
+
True
|
186
|
+
|
187
|
+
Forgetting the graph's labels, then finding them back::
|
188
|
+
|
189
|
+
sage: g.relabel()
|
190
|
+
sage: b,D = g.is_cartesian_product(g, relabeling=True)
|
191
|
+
sage: b
|
192
|
+
True
|
193
|
+
sage: D # random isomorphism
|
194
|
+
{0: (20, 0), 1: (20, 1), 2: (20, 2), 3: (20, 3), 4: (20, 4),
|
195
|
+
5: (15, 0), 6: (15, 1), 7: (15, 2), 8: (15, 3), 9: (15, 4),
|
196
|
+
10: (10, 0), 11: (10, 1), 12: (10, 2), 13: (10, 3), 14: (10, 4),
|
197
|
+
15: (5, 0), 16: (5, 1), 17: (5, 2), 18: (5, 3), 19: (5, 4),
|
198
|
+
20: (0, 0), 21: (0, 1), 22: (0, 2), 23: (0, 3), 24: (0, 4)}
|
199
|
+
|
200
|
+
And of course, we find the factors back when we build a graph from a
|
201
|
+
product::
|
202
|
+
|
203
|
+
sage: g = graphs.PetersenGraph().cartesian_product(graphs.CycleGraph(3))
|
204
|
+
sage: g1, g2 = is_cartesian_product(g, certificate = True)
|
205
|
+
sage: any( x.is_isomorphic(graphs.PetersenGraph()) for x in [g1,g2])
|
206
|
+
True
|
207
|
+
sage: any( x.is_isomorphic(graphs.CycleGraph(3)) for x in [g1,g2])
|
208
|
+
True
|
209
|
+
|
210
|
+
TESTS:
|
211
|
+
|
212
|
+
Wagner's Graph (:issue:`13599`)::
|
213
|
+
|
214
|
+
sage: g = graphs.WagnerGraph() # needs networkx
|
215
|
+
sage: g.is_cartesian_product() # needs networkx
|
216
|
+
False
|
217
|
+
|
218
|
+
Empty and one-element graph (:issue:`19546`)::
|
219
|
+
|
220
|
+
sage: Graph().is_cartesian_product()
|
221
|
+
False
|
222
|
+
sage: Graph({0:[]}).is_cartesian_product()
|
223
|
+
False
|
224
|
+
|
225
|
+
Check the behaviour of parameter ``immutable``::
|
226
|
+
|
227
|
+
sage: G = graphs.Grid2dGraph(3, 3)
|
228
|
+
sage: any(f.is_immutable() for f in G.is_cartesian_product(certificate=True))
|
229
|
+
False
|
230
|
+
sage: all(f.is_immutable() for f in G.is_cartesian_product(certificate=True, immutable=True))
|
231
|
+
True
|
232
|
+
sage: G = G.copy(immutable=True)
|
233
|
+
sage: all(f.is_immutable() for f in G.is_cartesian_product(certificate=True))
|
234
|
+
True
|
235
|
+
sage: any(f.is_immutable() for f in G.is_cartesian_product(certificate=True, immutable=False))
|
236
|
+
False
|
237
|
+
"""
|
238
|
+
g._scream_if_not_simple()
|
239
|
+
if g.is_directed():
|
240
|
+
raise NotImplementedError("recognition of Cartesian product is not implemented for directed graphs")
|
241
|
+
if relabeling:
|
242
|
+
certificate = True
|
243
|
+
|
244
|
+
from sage.rings.integer import Integer
|
245
|
+
|
246
|
+
if not g.is_connected():
|
247
|
+
raise NotImplementedError("recognition of Cartesian product is not implemented for disconnected graphs")
|
248
|
+
|
249
|
+
# Of course the number of vertices of g cannot be prime !
|
250
|
+
if g.order() <= 3 or Integer(g.order()).is_prime():
|
251
|
+
return (False, None) if relabeling else False
|
252
|
+
|
253
|
+
from sage.graphs.graph import Graph
|
254
|
+
|
255
|
+
# As we need the vertices of g to be linearly ordered, we copy the graph and
|
256
|
+
# relabel it
|
257
|
+
cdef list int_to_vertex = list(g)
|
258
|
+
cdef dict vertex_to_int = {vert: i for i, vert in enumerate(int_to_vertex)}
|
259
|
+
g_int = g.relabel(perm=vertex_to_int, inplace=False)
|
260
|
+
|
261
|
+
# Reorder the vertices of an edge
|
262
|
+
def r(x, y):
|
263
|
+
return (x, y) if x < y else (y, x)
|
264
|
+
|
265
|
+
cdef int x, y, u, v
|
266
|
+
cdef set un, intersect
|
267
|
+
|
268
|
+
# The equivalence graph on the edges of g
|
269
|
+
h = Graph()
|
270
|
+
h.add_vertices(r(x, y) for x, y in g_int.edge_iterator(labels=False))
|
271
|
+
|
272
|
+
# For all pairs of vertices u,v of G, according to their number of common
|
273
|
+
# neighbors... See the module's documentation !
|
274
|
+
for u in g_int:
|
275
|
+
un = set(g_int.neighbor_iterator(u))
|
276
|
+
for v in g_int.breadth_first_search(u):
|
277
|
+
|
278
|
+
# u and v are different
|
279
|
+
if u == v:
|
280
|
+
continue
|
281
|
+
|
282
|
+
# List of common neighbors
|
283
|
+
intersect = un & set(g_int.neighbor_iterator(v))
|
284
|
+
|
285
|
+
# If u and v have no neighbors and uv is not an edge then their
|
286
|
+
# distance is at least 3. As we enumerate the vertices in a
|
287
|
+
# breadth-first search, it means that we already checked all the
|
288
|
+
# vertices at distance less than two from u, and we are done with
|
289
|
+
# this loop !
|
290
|
+
if not intersect:
|
291
|
+
if g_int.has_edge(u, v):
|
292
|
+
continue
|
293
|
+
else:
|
294
|
+
break
|
295
|
+
|
296
|
+
# If uv is an edge
|
297
|
+
if g_int.has_edge(u, v):
|
298
|
+
h.add_path([r(u, x) for x in intersect] + [r(v, x) for x in intersect])
|
299
|
+
|
300
|
+
# Only one common neighbor
|
301
|
+
elif len(intersect) == 1:
|
302
|
+
x = intersect.pop()
|
303
|
+
h.add_edge(r(u, x), r(v, x))
|
304
|
+
|
305
|
+
# Exactly 2 neighbors
|
306
|
+
elif len(intersect) == 2:
|
307
|
+
x, y = intersect
|
308
|
+
h.add_edge(r(u, x), r(v, y))
|
309
|
+
h.add_edge(r(v, x), r(u, y))
|
310
|
+
# More
|
311
|
+
else:
|
312
|
+
h.add_path([r(u, x) for x in intersect] + [r(v, x) for x in intersect])
|
313
|
+
|
314
|
+
# Edges uv and u'v' such that d(u,u')+d(v,v') != d(u,v')+d(v,u') are also
|
315
|
+
# equivalent
|
316
|
+
|
317
|
+
cdef list edges = list(g_int.edges(labels=False, sort=False))
|
318
|
+
cdef dict d = g_int.distance_all_pairs()
|
319
|
+
cdef int uu, vv
|
320
|
+
for i, (u, v) in enumerate(edges):
|
321
|
+
du = d[u]
|
322
|
+
dv = d[v]
|
323
|
+
for j in range(i + 1, g_int.size()):
|
324
|
+
uu, vv = edges[j]
|
325
|
+
if du[uu] + dv[vv] != du[vv] + dv[uu]:
|
326
|
+
h.add_edge(r(u, v), r(uu, vv))
|
327
|
+
|
328
|
+
# Gathering the connected components, relabeling the vertices on-the-fly
|
329
|
+
edges = [[(int_to_vertex[u], int_to_vertex[v]) for u, v in cc]
|
330
|
+
for cc in h.connected_components(sort=False)]
|
331
|
+
|
332
|
+
# Only one connected component ?
|
333
|
+
if len(edges) == 1:
|
334
|
+
return (False, None) if relabeling else False
|
335
|
+
|
336
|
+
if immutable is None:
|
337
|
+
immutable = g.is_immutable()
|
338
|
+
|
339
|
+
# Building the list of factors
|
340
|
+
cdef list factors = []
|
341
|
+
for cc in edges:
|
342
|
+
tmp = Graph(cc, format='list_of_edges', immutable=immutable)
|
343
|
+
factors.append(tmp.subgraph(vertices=tmp.connected_components(sort=False)[0]))
|
344
|
+
|
345
|
+
# Computing the product of these graphs
|
346
|
+
answer = factors[0]
|
347
|
+
for i in range(1, len(factors)):
|
348
|
+
answer = answer.cartesian_product(factors[i])
|
349
|
+
|
350
|
+
# Checking that the resulting graph is indeed isomorphic to what we have.
|
351
|
+
isiso, dictt = g.is_isomorphic(answer, certificate=True)
|
352
|
+
if not isiso:
|
353
|
+
raise ValueError("something weird happened during the algorithm... "
|
354
|
+
"Please report the bug and give us the graph instance"
|
355
|
+
" that made it fail !")
|
356
|
+
if relabeling:
|
357
|
+
return isiso, dictt
|
358
|
+
if certificate:
|
359
|
+
return factors
|
360
|
+
return True
|
361
|
+
|
362
|
+
|
363
|
+
def rooted_product(G, H, root=None, immutable=None):
|
364
|
+
r"""
|
365
|
+
Return the rooted product of `G` and `H`.
|
366
|
+
|
367
|
+
The rooted product of two graphs `G` and `H` is the graph `R` defined as
|
368
|
+
follows: take a copy of `G` and `|V(G)|` copies of `H`, and for every vertex
|
369
|
+
`g_i` of `G`, identify `g_i` with the root of the `i`-th copy of `H`.
|
370
|
+
Mode formally, let `V(G) = \{g_1, g_2, \ldots, g_n\}`,
|
371
|
+
`V(H) = \{h_1, h_2, \ldots, h_m\}`, and let `h_1` be the root vertex of `H`.
|
372
|
+
The vertex set `V(R)` is equal to the cartesian product of the sets of
|
373
|
+
vertices `V(G)` and `V(H)`, that is
|
374
|
+
`V(R) = \{(g_i, h_j) : g_i \in V(G), h_j \in V(H)\}`. The edge set `E(R)`
|
375
|
+
is the union of the edges of a copy of `G`, that is
|
376
|
+
`\{((g_i, h_1), (g_j, h_1)) : (g_i, g_j) \in E(G)\}`, and the edges of the
|
377
|
+
copies of `H` for every `g_i \in V(G)`, that is
|
378
|
+
`\{((g_i, h_j), (g_i, h_k)) : (h_j, h_k) \in V(H)\}`.
|
379
|
+
|
380
|
+
See :wikipedia:`Rooted_product_of_graphs` for more details.
|
381
|
+
|
382
|
+
.. SEEALSO::
|
383
|
+
|
384
|
+
- :meth:`~sage.graphs.generic_graph.cartesian_product`
|
385
|
+
-- return the cartesian product of two graphs
|
386
|
+
|
387
|
+
- :mod:`~sage.graphs.graph_decompositions.graph_products`
|
388
|
+
-- a module on graph products
|
389
|
+
|
390
|
+
INPUT:
|
391
|
+
|
392
|
+
- ``G, H`` -- two (di)graphs
|
393
|
+
|
394
|
+
- ``immutable`` -- boolean (default: ``None``); whether to create a
|
395
|
+
mutable/immutable (di)graph. When ``immutable=None`` (default) the rooted
|
396
|
+
product will be mutable if one of ``G`` or ``H`` is mutable and immutable
|
397
|
+
otherwise.
|
398
|
+
|
399
|
+
EXAMPLES:
|
400
|
+
|
401
|
+
The rooted product of two trees is a tree::
|
402
|
+
|
403
|
+
sage: T1 = graphs.RandomTree(7)
|
404
|
+
sage: T2 = graphs.RandomTree(8)
|
405
|
+
sage: T = T1.rooted_product(T2)
|
406
|
+
sage: T.is_tree()
|
407
|
+
True
|
408
|
+
|
409
|
+
The rooted product of `G` and `H` depends on the selected root in `H`::
|
410
|
+
|
411
|
+
sage: G = graphs.CycleGraph(4)
|
412
|
+
sage: H = graphs.PathGraph(3)
|
413
|
+
sage: R1 = G.rooted_product(H, root=0)
|
414
|
+
sage: R2 = G.rooted_product(H, root=1)
|
415
|
+
sage: R1.is_isomorphic(R2)
|
416
|
+
False
|
417
|
+
sage: sorted(R1.degree())
|
418
|
+
[1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3]
|
419
|
+
sage: sorted(R2.degree())
|
420
|
+
[1, 1, 1, 1, 1, 1, 1, 1, 4, 4, 4, 4]
|
421
|
+
|
422
|
+
The domination number of the rooted product of any graph `G` and a path of
|
423
|
+
order 2 is the order of `G`::
|
424
|
+
|
425
|
+
sage: G = graphs.RandomGNP(20, .3)
|
426
|
+
sage: P = graphs.PathGraph(2)
|
427
|
+
sage: R = G.rooted_product(P)
|
428
|
+
sage: len(R.dominating_set()) == G.order() # needs sage.numerical.mip
|
429
|
+
True
|
430
|
+
sage: G = digraphs.RandomDirectedGNP(20, .3)
|
431
|
+
sage: P = digraphs.Path(2)
|
432
|
+
sage: R = G.rooted_product(P)
|
433
|
+
sage: len(R.dominating_set()) == G.order() # needs sage.numerical.mip
|
434
|
+
True
|
435
|
+
|
436
|
+
The rooted product of two graphs is a subgraph of the cartesian product of
|
437
|
+
the same two graphs::
|
438
|
+
|
439
|
+
sage: G = graphs.RandomGNP(6, .4)
|
440
|
+
sage: H = graphs.RandomGNP(7, .4)
|
441
|
+
sage: R = G.rooted_product(H)
|
442
|
+
sage: C = G.cartesian_product(H)
|
443
|
+
sage: R.is_subgraph(C, induced=False)
|
444
|
+
True
|
445
|
+
|
446
|
+
Corner cases::
|
447
|
+
|
448
|
+
sage: Graph().rooted_product(Graph())
|
449
|
+
Rooted product of Graph on 0 vertices and Graph on 0 vertices: Graph on 0 vertices
|
450
|
+
sage: Graph(1).rooted_product(Graph())
|
451
|
+
Rooted product of Graph on 1 vertex and Graph on 0 vertices: Graph on 0 vertices
|
452
|
+
sage: Graph().rooted_product(Graph(1))
|
453
|
+
Rooted product of Graph on 0 vertices and Graph on 1 vertex: Graph on 0 vertices
|
454
|
+
sage: Graph(1).rooted_product(Graph(1))
|
455
|
+
Rooted product of Graph on 1 vertex and Graph on 1 vertex: Graph on 1 vertex
|
456
|
+
|
457
|
+
TESTS::
|
458
|
+
|
459
|
+
sage: Graph().rooted_product(DiGraph())
|
460
|
+
Traceback (most recent call last):
|
461
|
+
...
|
462
|
+
TypeError: the graphs should be both directed or both undirected
|
463
|
+
|
464
|
+
Check the behaviour of parameter ``immutable``::
|
465
|
+
|
466
|
+
sage: G = graphs.CycleGraph(4)
|
467
|
+
sage: H = graphs.PathGraph(3)
|
468
|
+
sage: G.rooted_product(H).is_immutable()
|
469
|
+
False
|
470
|
+
sage: G.rooted_product(H, immutable=True).is_immutable()
|
471
|
+
True
|
472
|
+
sage: G = G.copy(immutable=True)
|
473
|
+
sage: G.rooted_product(H).is_immutable()
|
474
|
+
False
|
475
|
+
sage: G.rooted_product(H, immutable=True).is_immutable()
|
476
|
+
True
|
477
|
+
sage: H = H.copy(immutable=True)
|
478
|
+
sage: G.rooted_product(H).is_immutable()
|
479
|
+
True
|
480
|
+
sage: G.rooted_product(H, immutable=False).is_immutable()
|
481
|
+
False
|
482
|
+
"""
|
483
|
+
G._scream_if_not_simple(allow_loops=True)
|
484
|
+
if G._directed is not H._directed:
|
485
|
+
raise TypeError('the graphs should be both directed or both undirected')
|
486
|
+
|
487
|
+
loops = G.has_loops() or H.has_loops()
|
488
|
+
name = f'Rooted product of {G} and {H}'
|
489
|
+
if immutable is None:
|
490
|
+
immutable = G.is_immutable() and H.is_immutable()
|
491
|
+
|
492
|
+
if not G or not H:
|
493
|
+
return G.parent()(loops=loops, name=name, immutable=immutable)
|
494
|
+
if root is None:
|
495
|
+
root = next(H.vertex_iterator())
|
496
|
+
elif root not in H:
|
497
|
+
raise ValueError("the specified root is not a vertex of H")
|
498
|
+
|
499
|
+
vertices = ((u, x) for u in G for x in H)
|
500
|
+
|
501
|
+
def edges():
|
502
|
+
for u, v in G.edge_iterator(labels=False):
|
503
|
+
yield ((u, root), (v, root))
|
504
|
+
for x, y in H.edge_iterator(labels=False):
|
505
|
+
yield from (((u, x), (u, y)) for u in G)
|
506
|
+
|
507
|
+
return G.parent()([vertices, edges()], format='vertices_and_edges',
|
508
|
+
name=name, loops=loops, immutable=immutable)
|
Binary file
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# sage_setup: distribution = sagemath-graphs
|
2
|
+
from libcpp cimport bool
|
3
|
+
from libcpp.list cimport list as cpplist
|
4
|
+
from libcpp.vector cimport vector
|
5
|
+
|
6
|
+
cdef extern from "modular_decomposition.hpp":
|
7
|
+
cdef cppclass SDData:
|
8
|
+
void set_from_data(size_t lex_label_offset, const int* sigma,
|
9
|
+
const size_t *xslice_len,
|
10
|
+
const vector[int] *lex_label)
|
11
|
+
|
12
|
+
cdef cppclass md_tree_node:
|
13
|
+
bool is_leaf() const
|
14
|
+
bool is_prime() const
|
15
|
+
bool is_parallel() const
|
16
|
+
bool is_series() const
|
17
|
+
cpplist[md_tree_node *] children
|
18
|
+
# If is_leaf() is true, the attribute 'vertex' contains the id of the
|
19
|
+
# corresponding vertex. If is_leaf() is false, the attribute 'vertex'
|
20
|
+
# contains the id of a vertex corresponding to any leaf below
|
21
|
+
# the node (i.e., 'vertex' contains the id of a vertex belonging to the
|
22
|
+
# module corresponding to the node).
|
23
|
+
int vertex
|
24
|
+
|
25
|
+
void dealloc_md_tree_nodes_recursively(md_tree_node *)
|
26
|
+
|
27
|
+
cdef md_tree_node * corneil_habib_paul_tedder_inner(const SDData &SD)
|