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,627 @@
1
+ # sage_setup: distribution = sagemath-graphs
2
+ # cython: binding=True
3
+ r"""
4
+ Line graphs
5
+
6
+ This module gather everything which is related to line graphs. Right now, this
7
+ amounts to the following functions :
8
+
9
+ .. csv-table::
10
+ :class: contentstable
11
+ :widths: 30, 70
12
+ :delim: |
13
+
14
+ :meth:`line_graph` | Return the line graph of a given graph
15
+ :meth:`is_line_graph` | Check whether a graph is a line graph
16
+ :meth:`root_graph` | Return the root graph corresponding to the given graph
17
+
18
+ Author:
19
+
20
+ - Nathann Cohen (01-2013), :meth:`root_graph` method and module documentation.
21
+ Written while listening to Nina Simone *"I wish I knew how it would feel to be
22
+ free"*. Crazy good song. And *"Prendre ta douleur"*, too.
23
+
24
+ - David Coudert (10-2018), use maximal cliques iterator in :meth:`root_graph`,
25
+ and use :meth:`root_graph` instead of forbidden subgraph search in
26
+ :meth:`is_line_graph` (:issue:`26444`).
27
+
28
+ Definition
29
+ -----------
30
+
31
+ Given a graph `G`, the *line graph* `L(G)` of `G` is the graph such that
32
+
33
+ .. MATH::
34
+
35
+ V(L(G)) =& E(G)\\
36
+ E(L(G)) =& \{(e,e'):\text{ and }e,e'\text{ have a common endpoint in }G\}\\
37
+
38
+ The definition is extended to directed graphs. In this situation, there is an
39
+ arc `(e,e')` in `L(G)` if the destination of `e` is the origin of `e'`.
40
+
41
+ For more information, see the :wikipedia:`Line_graph`.
42
+
43
+ Root graph
44
+ ----------
45
+
46
+ A graph whose line graph is `LG` is called the *root graph* of `LG`. The root
47
+ graph of a (connected) graph is unique ([Whi1932]_, [Har1969]_), except when
48
+ `LG=K_3`, as both `L(K_3)` and `L(K_{1,3})` are equal to `K_3`.
49
+
50
+ Here is how we can *"see"* `G` by staring (very intently) at `LG` :
51
+
52
+ A graph `LG` is the line graph of `G` if there exists a collection
53
+ `(S_v)_{v\in G}` of subsets of `V(LG)` such that :
54
+
55
+ * Every `S_v` is a complete subgraph of `LG`.
56
+
57
+ * Every `v\in LG` belongs to exactly two sets of the family `(S_v)_{v\in G}`.
58
+
59
+ * Any two sets of `(S_v)_{v\in G}` have at most one common elements
60
+
61
+ * For any edge `(u,v)\in LG` there exists a set of `(S_v)_{v\in G}` containing
62
+ both `u` and `v`.
63
+
64
+ In this family, each set `S_v` represent a vertex of `G`, and contains "the
65
+ set of edges incident to `v` in `G`". Two elements `S_v,S_{v'}` have a
66
+ nonempty intersection whenever `vv'` is an edge of `G`.
67
+
68
+ Hence, finding the root graph of `LG` is the job of finding this collection of
69
+ sets.
70
+
71
+ In particular, what we know for sure is that a maximal clique `S` of size `2` or
72
+ `\geq 4` in `LG` corresponds to a vertex of degree `|S|` in `G`, whose incident
73
+ edges are the elements of `S` itself.
74
+
75
+ The main problem lies with maximal cliques of size 3, i.e. triangles. Those we
76
+ have to split into two categories, *even* and *odd* triangles :
77
+
78
+ A triangle `\{e_1,e_2,e_3\}\subseteq V(LG)` is said to be an *odd* triangle if
79
+ there exists a vertex `e\in V(G)` incident to exactly *one* or *all* of
80
+ `\{e_1,e_2,e_3\}`, and it is said to be *even* otherwise.
81
+
82
+ The very good point of this definition is that an inclusionwise maximal clique
83
+ which is an odd triangle will always correspond to a vertex of degree 3 in `G`,
84
+ while an even triangle could result from either a vertex of degree 3 in `G` or a
85
+ triangle in `G`. And in order to build the root graph we obviously have to
86
+ decide *which*.
87
+
88
+ Beineke proves in [Bei1970]_ that the collection of sets we are looking for
89
+ can be easily found. Indeed it turns out that it is the union of :
90
+
91
+ #. The family of all maximal cliques of `LG` of size 2 or `\geq 4`, as well as
92
+ all odd triangles.
93
+
94
+ #. The family of all pairs of adjacent vertices which appear in exactly *one*
95
+ maximal clique which is an even triangle.
96
+
97
+ There are actually four special cases to which the decomposition above does not
98
+ apply, i.e. graphs containing an edge which belongs to exactly two even
99
+ triangles. We deal with those independently.
100
+
101
+ * The :meth:`Complete graph
102
+ <sage.graphs.graph_generators.GraphGenerators.CompleteGraph>` `K_3`.
103
+
104
+ * The :meth:`Diamond graph
105
+ <sage.graphs.graph_generators.GraphGenerators.DiamondGraph>` -- the line graph
106
+ of `K_{1,3}` plus an edge.
107
+
108
+ * The :meth:`Wheel graph
109
+ <sage.graphs.graph_generators.GraphGenerators.WheelGraph>` on `4+1` vertices
110
+ -- the line graph of the :meth:`Diamond graph
111
+ <sage.graphs.graph_generators.GraphGenerators.DiamondGraph>`
112
+
113
+ * The :meth:`Octahedron
114
+ <sage.graphs.graph_generators.GraphGenerators.OctahedralGraph>` -- the line
115
+ graph of `K_4`.
116
+
117
+ This decomposition turns out to be very easy to implement :-)
118
+
119
+ .. WARNING::
120
+
121
+ Even though the root graph is *NOT UNIQUE* for the triangle, this method
122
+ returns `K_{1,3}` (and not `K_3`) in this case. Pay *very close* attention
123
+ to that, for this answer is not theoretically correct : there is no unique
124
+ answer in this case, and we deal with it by returning one of the two
125
+ possible answers.
126
+
127
+ Functions
128
+ ---------
129
+ """
130
+
131
+
132
+ def is_line_graph(g, certificate=False):
133
+ r"""
134
+ Check whether the graph `g` is a line graph.
135
+
136
+ INPUT:
137
+
138
+ - ``certificate`` -- boolean; whether to return a certificate along with
139
+ the boolean result. Here is what happens when ``certificate = True``:
140
+
141
+ - If the graph is not a line graph, the method returns a pair ``(b,
142
+ subgraph)`` where ``b`` is ``False`` and ``subgraph`` is a subgraph
143
+ isomorphic to one of the 9 forbidden induced subgraphs of a line graph.
144
+
145
+ - If the graph is a line graph, the method returns a triple ``(b,R,isom)``
146
+ where ``b`` is ``True``, ``R`` is a graph whose line graph is the graph
147
+ given as input, and ``isom`` is a map associating an edge of ``R`` to
148
+ each vertex of the graph.
149
+
150
+ .. NOTE::
151
+
152
+ This method wastes a bit of time when the input graph is not connected.
153
+ If you have performance in mind, it is probably better to only feed it
154
+ with connected graphs only.
155
+
156
+ .. SEEALSO::
157
+
158
+ - The :mod:`line_graph <sage.graphs.line_graph>` module.
159
+
160
+ - :meth:`~sage.graphs.graph_generators.GraphGenerators.line_graph_forbidden_subgraphs`
161
+ -- the forbidden subgraphs of a line graph.
162
+
163
+ - :meth:`~sage.graphs.generic_graph.GenericGraph.line_graph`
164
+
165
+ EXAMPLES:
166
+
167
+ A complete graph is always the line graph of a star::
168
+
169
+ sage: graphs.CompleteGraph(5).is_line_graph()
170
+ True
171
+
172
+ The Petersen Graph not being claw-free, it is not a line
173
+ graph::
174
+
175
+ sage: graphs.PetersenGraph().is_line_graph()
176
+ False
177
+
178
+ This is indeed the subgraph returned::
179
+
180
+ sage: C = graphs.PetersenGraph().is_line_graph(certificate=True)[1] # needs sage.modules
181
+ sage: C.is_isomorphic(graphs.ClawGraph()) # needs sage.modules
182
+ True
183
+
184
+ The house graph is a line graph::
185
+
186
+ sage: g = graphs.HouseGraph()
187
+ sage: g.is_line_graph()
188
+ True
189
+
190
+ But what is the graph whose line graph is the house ?::
191
+
192
+ sage: # needs sage.modules
193
+ sage: is_line, R, isom = g.is_line_graph(certificate=True)
194
+ sage: R.sparse6_string()
195
+ ':DaHI~'
196
+ sage: R.show() # needs sage.plot
197
+ sage: isom
198
+ {0: (0, 1), 1: (0, 2), 2: (1, 3), 3: (2, 3), 4: (3, 4)}
199
+
200
+ TESTS:
201
+
202
+ Disconnected graphs::
203
+
204
+ sage: g = 2 * graphs.CycleGraph(3)
205
+ sage: gl = g.line_graph().relabel(inplace=False)
206
+ sage: new_g = gl.is_line_graph(certificate=True)[1] # needs sage.modules
207
+ sage: g.line_graph().is_isomorphic(gl) # needs sage.modules
208
+ True
209
+
210
+ Verify that :issue:`29740` is fixed::
211
+
212
+ sage: g = Graph('O{e[{}^~z`MDZBZBkXzE^')
213
+ sage: g.is_line_graph()
214
+ False
215
+ """
216
+ g._scream_if_not_simple()
217
+
218
+ def get_certificate(gg):
219
+ """
220
+ Assuming that gg is not a line graph, return a forbidden induced
221
+ subgraph.
222
+ """
223
+ from sage.graphs.graph_generators import graphs
224
+ for fg in graphs.line_graph_forbidden_subgraphs():
225
+ h = gg.subgraph_search(fg, induced=True)
226
+ if h is not None:
227
+ return h
228
+
229
+ if g.is_connected():
230
+ try:
231
+ # To check whether g is a line graph, we try to construct its root
232
+ # graph
233
+ R, isom = root_graph(g)
234
+ if certificate:
235
+ return True, R, isom
236
+ return True
237
+ except ValueError as VE:
238
+ if str(VE) == "this graph is not a line graph !":
239
+ # g is not a line graph
240
+ if certificate:
241
+ return False, get_certificate(g)
242
+ return False
243
+ raise VE
244
+
245
+ # g is not connected, so we apply the above procedure to each connected
246
+ # component
247
+ from sage.graphs.graph import Graph
248
+ R = Graph()
249
+ for gg in g.connected_components_subgraphs():
250
+ try:
251
+ RR, isom = root_graph(gg)
252
+ R += RR
253
+ except ValueError as VE:
254
+ if str(VE) == "this graph is not a line graph !":
255
+ # gg is not a line graph
256
+ if certificate:
257
+ return False, get_certificate(gg)
258
+ return False
259
+ raise VE
260
+
261
+ if certificate:
262
+ _, isom = g.is_isomorphic(R.line_graph(labels=False), certificate=True)
263
+ return True, R, isom
264
+ return True
265
+
266
+
267
+ def line_graph(g, labels=True):
268
+ """
269
+ Return the line graph of the (di)graph ``g``.
270
+
271
+ INPUT:
272
+
273
+ - ``labels`` -- boolean (default: ``True``); whether edge labels should be
274
+ taken in consideration. If ``labels=True``, the vertices of the line graph
275
+ will be triples ``(u,v,label)``, and pairs of vertices otherwise.
276
+
277
+ The line graph of an undirected graph G is an undirected graph H such that
278
+ the vertices of H are the edges of G and two vertices e and f of H are
279
+ adjacent if e and f share a common vertex in G. In other words, an edge in H
280
+ represents a path of length 2 in G.
281
+
282
+ The line graph of a directed graph G is a directed graph H such that the
283
+ vertices of H are the edges of G and two vertices e and f of H are adjacent
284
+ if e and f share a common vertex in G and the terminal vertex of e is the
285
+ initial vertex of f. In other words, an edge in H represents a (directed)
286
+ path of length 2 in G.
287
+
288
+ .. NOTE::
289
+
290
+ As a :class:`Graph` object only accepts hashable objects as vertices
291
+ (and as the vertices of the line graph are the edges of the graph), this
292
+ code will fail if edge labels are not hashable. You can also set the
293
+ argument ``labels=False`` to ignore labels.
294
+
295
+ .. SEEALSO::
296
+
297
+ - The :mod:`line_graph <sage.graphs.line_graph>` module
298
+
299
+ - :meth:`~sage.graphs.graph_generators.GraphGenerators.line_graph_forbidden_subgraphs`
300
+ -- the forbidden subgraphs of a line graph
301
+
302
+ - :meth:`~Graph.is_line_graph` -- tests whether a graph is a line graph
303
+
304
+ EXAMPLES::
305
+
306
+ sage: g = graphs.CompleteGraph(4)
307
+ sage: h = g.line_graph()
308
+ sage: h.vertices(sort=True)
309
+ [(0, 1, None),
310
+ (0, 2, None),
311
+ (0, 3, None),
312
+ (1, 2, None),
313
+ (1, 3, None),
314
+ (2, 3, None)]
315
+ sage: h.am() # needs sage.modules
316
+ [0 1 1 1 1 0]
317
+ [1 0 1 1 0 1]
318
+ [1 1 0 0 1 1]
319
+ [1 1 0 0 1 1]
320
+ [1 0 1 1 0 1]
321
+ [0 1 1 1 1 0]
322
+ sage: h2 = g.line_graph(labels=False)
323
+ sage: h2.vertices(sort=True)
324
+ [(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)]
325
+ sage: h2.am() == h.am() # needs sage.modules
326
+ True
327
+ sage: g = DiGraph([[1..4], lambda i,j: i < j])
328
+ sage: h = g.line_graph()
329
+ sage: h.vertices(sort=True)
330
+ [(1, 2, None),
331
+ (1, 3, None),
332
+ (1, 4, None),
333
+ (2, 3, None),
334
+ (2, 4, None),
335
+ (3, 4, None)]
336
+ sage: h.edges(sort=True)
337
+ [((1, 2, None), (2, 3, None), None),
338
+ ((1, 2, None), (2, 4, None), None),
339
+ ((1, 3, None), (3, 4, None), None),
340
+ ((2, 3, None), (3, 4, None), None)]
341
+
342
+ TESTS:
343
+
344
+ :issue:`13787`::
345
+
346
+ sage: g = graphs.KneserGraph(7,1)
347
+ sage: C = graphs.CompleteGraph(7)
348
+ sage: C.is_isomorphic(g)
349
+ True
350
+ sage: C.line_graph().is_isomorphic(g.line_graph())
351
+ True
352
+ """
353
+ cdef dict conflicts = {}
354
+ cdef list elist = []
355
+
356
+ g._scream_if_not_simple()
357
+ if g._directed:
358
+ from sage.graphs.digraph import DiGraph
359
+ G = DiGraph()
360
+ G.add_vertices(g.edge_iterator(labels=labels))
361
+ for v in g:
362
+ # Connect appropriate incident edges of the vertex v
363
+ G.add_edges((e, f) for e in g.incoming_edge_iterator(v, labels=labels)
364
+ for f in g.outgoing_edge_iterator(v, labels=labels))
365
+ return G
366
+
367
+ from sage.graphs.graph import Graph
368
+ G = Graph()
369
+
370
+ # We must sort the edges' endpoints so that (1,2,None) is seen as the
371
+ # same edge as (2,1,None).
372
+ #
373
+ # We do so by comparing hashes, just in case all the natural order (<)
374
+ # on vertices would not be a total order (for instance when vertices are
375
+ # sets). If two adjacent vertices have the same hash, then we store the
376
+ # pair in the dictionary of conflicts
377
+
378
+ # 1) List of vertices in the line graph
379
+ for e in g.edge_iterator(labels=labels):
380
+ if hash(e[0]) < hash(e[1]):
381
+ elist.append(e)
382
+ elif hash(e[0]) > hash(e[1]):
383
+ elist.append((e[1], e[0]) + e[2:])
384
+ else:
385
+ # Settle the conflict arbitrarily
386
+ conflicts[e] = e
387
+ conflicts[(e[1], e[0]) + e[2:]] = e
388
+ elist.append(e)
389
+
390
+ G.add_vertices(elist)
391
+
392
+ # 2) adjacencies in the line graph
393
+ for v in g:
394
+ elist = []
395
+
396
+ # Add the edge to the list, according to hashes, as previously
397
+ for e in g.edge_iterator(v, labels=labels):
398
+ if hash(e[0]) < hash(e[1]):
399
+ elist.append(e)
400
+ elif hash(e[0]) > hash(e[1]):
401
+ elist.append((e[1], e[0]) + e[2:])
402
+ else:
403
+ elist.append(conflicts[e])
404
+
405
+ # All pairs of elements in elist are edges of the line graph
406
+ while elist:
407
+ x = elist.pop()
408
+ for y in elist:
409
+ G.add_edge(x, y)
410
+
411
+ return G
412
+
413
+
414
+ def root_graph(g, verbose=False):
415
+ r"""
416
+ Return the root graph corresponding to the given graph ``g``.
417
+
418
+ See the documentation of :mod:`sage.graphs.line_graph` to know how it works.
419
+
420
+ INPUT:
421
+
422
+ - ``g`` -- a graph
423
+
424
+ - ``verbose`` -- boolean (default: ``False``); display some information
425
+ about what is happening inside of the algorithm
426
+
427
+ .. WARNING::
428
+
429
+ This code assumes that `g` is a line graph, and is a connected,
430
+ undirected graph without multiple edges.
431
+
432
+ TESTS:
433
+
434
+ All connected graphs on 6 vertices::
435
+
436
+ sage: from sage.graphs.line_graph import root_graph
437
+ sage: def test(g):
438
+ ....: gl = g.line_graph(labels=False)
439
+ ....: d = root_graph(gl)
440
+ sage: for i,g in enumerate(graphs(6)): # long time
441
+ ....: if not g.is_connected():
442
+ ....: continue
443
+ ....: test(g)
444
+
445
+ Non line-graphs::
446
+
447
+ sage: root_graph(graphs.PetersenGraph())
448
+ Traceback (most recent call last):
449
+ ...
450
+ ValueError: this graph is not a line graph !
451
+
452
+ sage: root_graph(Graph('O{e[{}^~z`MDZBZBkXzE^'))
453
+ Traceback (most recent call last):
454
+ ...
455
+ ValueError: this graph is not a line graph !
456
+
457
+ Small corner-cases::
458
+
459
+ sage: from sage.graphs.line_graph import root_graph
460
+ sage: root_graph(graphs.CompleteGraph(3))
461
+ (Complete bipartite graph of order 1+3: Graph on 4 vertices,
462
+ {0: (0, 1), 1: (0, 2), 2: (0, 3)})
463
+ sage: G, D = root_graph(graphs.OctahedralGraph()); G
464
+ Complete graph: Graph on 4 vertices
465
+ sage: G, D = root_graph(graphs.DiamondGraph()); G
466
+ Graph on 4 vertices
467
+ sage: G, D = root_graph(graphs.WheelGraph(5)); G
468
+ Diamond Graph: Graph on 4 vertices
469
+ """
470
+ from sage.graphs.digraph import DiGraph
471
+
472
+ if isinstance(g, DiGraph):
473
+ raise ValueError("g cannot be a DiGraph !")
474
+ if g.has_multiple_edges():
475
+ raise ValueError("g cannot have multiple edges !")
476
+ if not g.is_connected():
477
+ raise ValueError("g is not connected !")
478
+ # is_line_graph expects a particular error message when g is not a line graph
479
+ not_line_graph = "this graph is not a line graph !"
480
+
481
+ # Complete Graph ?
482
+ if g.is_clique():
483
+ from sage.graphs.generators.basic import CompleteBipartiteGraph
484
+ return (CompleteBipartiteGraph(1, g.order()),
485
+ {v: (0, 1 + i) for i, v in enumerate(g)})
486
+
487
+ # Diamond Graph ?
488
+ elif g.order() == 4 and g.size() == 5:
489
+ from sage.graphs.graph import Graph
490
+ root = Graph([(0, 1), (1, 2), (2, 0), (0, 3)])
491
+ return (root,
492
+ g.is_isomorphic(root.line_graph(labels=False), certificate=True)[1])
493
+
494
+ # Wheel on 5 vertices ?
495
+ elif g.order() == 5 and g.size() == 8 and min(g.degree()) == 3:
496
+ from sage.graphs.generators.basic import DiamondGraph
497
+ root = DiamondGraph()
498
+ return (root,
499
+ g.is_isomorphic(root.line_graph(labels=False), certificate=True)[1])
500
+
501
+ # Octahedron ?
502
+ elif g.order() == 6 and g.size() == 12 and g.is_regular(k=4):
503
+ from sage.graphs.generators.platonic_solids import OctahedralGraph
504
+ if g.is_isomorphic(OctahedralGraph()):
505
+ from sage.graphs.generators.basic import CompleteGraph
506
+ root = CompleteGraph(4)
507
+ return (root,
508
+ g.is_isomorphic(root.line_graph(labels=False), certificate=True)[1])
509
+
510
+ # From now on we can assume (thanks to Beineke) that no edge belongs to two
511
+ # even triangles at once.
512
+
513
+ # Better to work on integers... Everything takes more time otherwise.
514
+ G = g.relabel(inplace=False)
515
+
516
+ # Dictionary of (pairs of) cliques, i.e. the two cliques associated with
517
+ # each vertex.
518
+ cdef dict v_cliques = {v: [] for v in G}
519
+ # All the even triangles we meet
520
+ cdef list even_triangles = []
521
+
522
+ # We iterate over all maximal cliques of the graph.
523
+
524
+ # As method G.cliques_maximal() returns the list of all maximal cliques
525
+ # (which takes an exponential time on general graphs, while it is obviously
526
+ # polynomial on line graphs), we instead use IndependentSet to iterate over
527
+ # all the maximal cliques. This way, we can say early that the graph is not
528
+ # a line graph.
529
+
530
+ from sage.graphs.independent_sets import IndependentSets
531
+ for S in IndependentSets(G, maximal=True, complement=True):
532
+
533
+ # Triangles... even or odd ?
534
+ if len(S) == 3:
535
+
536
+ # If a vertex of G has an odd number of neighbors among the vertices
537
+ # of S, then the triangle is odd. We compute the list of such
538
+ # vertices by taking the symmetric difference of the neighborhood of
539
+ # our three vertices.
540
+ #
541
+ # Note that the elements of S do not appear in this set as they are
542
+ # all seen exactly twice.
543
+
544
+ odd_neighbors = set(G.neighbor_iterator(S[0]))
545
+ odd_neighbors.symmetric_difference_update(G.neighbor_iterator(S[1]))
546
+ odd_neighbors.symmetric_difference_update(G.neighbor_iterator(S[2]))
547
+
548
+ # Even triangles
549
+ if not odd_neighbors:
550
+ even_triangles.append(tuple(S))
551
+ continue
552
+
553
+ # We manage odd triangles the same way we manage other cliques ...
554
+
555
+ # We now associate the clique to all the vertices it contains.
556
+ for v in S:
557
+ if len(v_cliques[v]) == 2:
558
+ raise ValueError(not_line_graph)
559
+ v_cliques[v].append(tuple(S))
560
+
561
+ if verbose:
562
+ print("Added clique", S)
563
+
564
+ # Deal with even triangles
565
+ for u, v, w in even_triangles:
566
+
567
+ # According to Beineke, we must go through all even triangles, and for
568
+ # each triangle uvw consider its three pairs of adjacent vertices uv,
569
+ # vw, wu. For all pairs xy among those such that xy do not appear
570
+ # together in any clique we have found so far, we add xy to the list of
571
+ # cliques describing our covering.
572
+
573
+ for x, y in [(u, v), (v, w), (w, u)]:
574
+
575
+ # If edge xy does not appear in any of the cliques associated with y
576
+ if all(x not in C for C in v_cliques[y]):
577
+ if len(v_cliques[y]) >= 2 or len(v_cliques[x]) >= 2:
578
+ raise ValueError("this graph is not a line graph !")
579
+
580
+ v_cliques[x].append((x, y))
581
+ v_cliques[y].append((x, y))
582
+
583
+ if verbose:
584
+ print("Adding pair", (x, y),
585
+ "appearing in the even triangle", (u, v, w))
586
+
587
+ # Deal with vertices contained in only one clique. All edges must be defined
588
+ # by TWO endpoints, so we add a fake clique.
589
+ for x, clique_list in v_cliques.items():
590
+ if len(clique_list) == 1:
591
+ clique_list.append((x,))
592
+
593
+ # We now have all our cliques. Let's build the root graph to check that it
594
+ # all fits !
595
+ from sage.graphs.graph import Graph
596
+ R = Graph()
597
+
598
+ # Associates an integer to each clique
599
+ cdef dict relabel = {}
600
+
601
+ # Associates to each vertex of G its pair of coordinates in R
602
+ cdef dict vertex_to_map = {}
603
+
604
+ for v, L in v_cliques.items():
605
+
606
+ # Add cliques to relabel dictionary
607
+ for S in L:
608
+ if S not in relabel:
609
+ relabel[S] = len(relabel)
610
+
611
+ # The coordinates of edge v
612
+ vertex_to_map[v] = relabel[L[0]], relabel[L[1]]
613
+
614
+ if verbose:
615
+ print("Final associations :")
616
+ for v, L in v_cliques.items():
617
+ print(v, L)
618
+
619
+ # We now build R
620
+ R.add_edges(vertex_to_map.values())
621
+
622
+ # If g is a line graph, then it is isomorphic to the line graph of the graph
623
+ # R that we have constructed, so we return R (and the isomorphism).
624
+ is_isom, isom = g.is_isomorphic(R.line_graph(labels=False), certificate=True)
625
+ if is_isom:
626
+ return R, isom
627
+ raise ValueError(not_line_graph)
@@ -0,0 +1,77 @@
1
+ # sage_setup: distribution = sagemath-graphs
2
+ r"""
3
+ Lovász theta-function of graphs
4
+
5
+ AUTHORS:
6
+
7
+ - Dima Pasechnik (2015-06-30): Initial version
8
+
9
+ REFERENCE:
10
+
11
+ [Lov1979]_
12
+
13
+ Functions
14
+ ---------
15
+ """
16
+
17
+
18
+ def lovasz_theta(graph):
19
+ r"""
20
+ Return the value of Lovász theta-function of graph.
21
+
22
+ For a graph `G` this function is denoted by `\theta(G)`, and it can be
23
+ computed in polynomial time. Mathematically, its most important property is
24
+ the following:
25
+
26
+ .. MATH::
27
+
28
+ \alpha(G)\leq\theta(G)\leq\chi(\overline{G})
29
+
30
+ with `\alpha(G)` and `\chi(\overline{G})` being, respectively, the maximum
31
+ size of an :meth:`independent set <sage.graphs.graph.Graph.independent_set>`
32
+ set of `G` and the :meth:`chromatic number
33
+ <sage.graphs.graph.Graph.chromatic_number>` of the :meth:`complement
34
+ <sage.graphs.generic_graph.GenericGraph.complement>` `\overline{G}` of `G`.
35
+
36
+ For more information, see the :wikipedia:`Lovász_number`.
37
+
38
+ .. NOTE::
39
+
40
+ - Implemented for undirected graphs only. Use ``to_undirected``
41
+ to convert a digraph to an undirected graph.
42
+
43
+ - This function requires the optional package ``csdp``, which you can
44
+ install with ``sage -i csdp``.
45
+
46
+ EXAMPLES::
47
+
48
+ sage: C = graphs.PetersenGraph()
49
+ sage: C.lovasz_theta() # optional - csdp
50
+ 4.0
51
+ sage: graphs.CycleGraph(5).lovasz_theta() # optional - csdp
52
+ 2.236068
53
+
54
+ TESTS::
55
+
56
+ sage: g = Graph()
57
+ sage: g.lovasz_theta() # indirect doctest
58
+ 0
59
+ """
60
+ n = graph.order()
61
+ if not n:
62
+ return 0
63
+
64
+ from networkx import write_edgelist
65
+ from sage.misc.temporary_file import tmp_filename
66
+ import subprocess
67
+
68
+ from sage.features.csdp import CSDP
69
+ CSDP().require()
70
+
71
+ g = graph.relabel(inplace=False, perm=range(1, n + 1)).networkx_graph()
72
+ tf_name = tmp_filename()
73
+ with open(tf_name, 'wb') as tf:
74
+ tf.write("{}\n{}\n".format(n, g.number_of_edges()).encode())
75
+ write_edgelist(g, tf, data=False)
76
+ lines = subprocess.check_output(['theta', tf_name])
77
+ return float(lines.split()[-1])