passagemath-graphs 10.6.1rc1__cp310-cp310-musllinux_1_2_aarch64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (260) hide show
  1. passagemath_graphs-10.6.1rc1.dist-info/METADATA +292 -0
  2. passagemath_graphs-10.6.1rc1.dist-info/RECORD +260 -0
  3. passagemath_graphs-10.6.1rc1.dist-info/WHEEL +5 -0
  4. passagemath_graphs-10.6.1rc1.dist-info/top_level.txt +2 -0
  5. passagemath_graphs.libs/libgcc_s-69c45f16.so.1 +0 -0
  6. passagemath_graphs.libs/libgmp-8e78bd9b.so.10.5.0 +0 -0
  7. passagemath_graphs.libs/libstdc++-1f1a71be.so.6.0.33 +0 -0
  8. sage/all__sagemath_graphs.py +39 -0
  9. sage/combinat/abstract_tree.py +2723 -0
  10. sage/combinat/all__sagemath_graphs.py +34 -0
  11. sage/combinat/binary_tree.py +5306 -0
  12. sage/combinat/cluster_algebra_quiver/all.py +22 -0
  13. sage/combinat/cluster_algebra_quiver/cluster_seed.py +5208 -0
  14. sage/combinat/cluster_algebra_quiver/interact.py +124 -0
  15. sage/combinat/cluster_algebra_quiver/mutation_class.py +625 -0
  16. sage/combinat/cluster_algebra_quiver/mutation_type.py +1555 -0
  17. sage/combinat/cluster_algebra_quiver/quiver.py +2290 -0
  18. sage/combinat/cluster_algebra_quiver/quiver_mutation_type.py +2468 -0
  19. sage/combinat/designs/MOLS_handbook_data.py +570 -0
  20. sage/combinat/designs/all.py +58 -0
  21. sage/combinat/designs/bibd.py +1655 -0
  22. sage/combinat/designs/block_design.py +1071 -0
  23. sage/combinat/designs/covering_array.py +269 -0
  24. sage/combinat/designs/covering_design.py +530 -0
  25. sage/combinat/designs/database.py +5615 -0
  26. sage/combinat/designs/design_catalog.py +122 -0
  27. sage/combinat/designs/designs_pyx.cpython-310-aarch64-linux-gnu.so +0 -0
  28. sage/combinat/designs/designs_pyx.pxd +21 -0
  29. sage/combinat/designs/designs_pyx.pyx +993 -0
  30. sage/combinat/designs/difference_family.py +3951 -0
  31. sage/combinat/designs/difference_matrices.py +279 -0
  32. sage/combinat/designs/evenly_distributed_sets.cpython-310-aarch64-linux-gnu.so +0 -0
  33. sage/combinat/designs/evenly_distributed_sets.pyx +661 -0
  34. sage/combinat/designs/ext_rep.py +1064 -0
  35. sage/combinat/designs/gen_quadrangles_with_spread.cpython-310-aarch64-linux-gnu.so +0 -0
  36. sage/combinat/designs/gen_quadrangles_with_spread.pyx +339 -0
  37. sage/combinat/designs/group_divisible_designs.py +361 -0
  38. sage/combinat/designs/incidence_structures.py +2357 -0
  39. sage/combinat/designs/latin_squares.py +581 -0
  40. sage/combinat/designs/orthogonal_arrays.py +2244 -0
  41. sage/combinat/designs/orthogonal_arrays_build_recursive.py +1780 -0
  42. sage/combinat/designs/orthogonal_arrays_find_recursive.cpython-310-aarch64-linux-gnu.so +0 -0
  43. sage/combinat/designs/orthogonal_arrays_find_recursive.pyx +967 -0
  44. sage/combinat/designs/resolvable_bibd.py +815 -0
  45. sage/combinat/designs/steiner_quadruple_systems.py +1306 -0
  46. sage/combinat/designs/subhypergraph_search.cpython-310-aarch64-linux-gnu.so +0 -0
  47. sage/combinat/designs/subhypergraph_search.pyx +530 -0
  48. sage/combinat/designs/twographs.py +306 -0
  49. sage/combinat/finite_state_machine.py +14874 -0
  50. sage/combinat/finite_state_machine_generators.py +2006 -0
  51. sage/combinat/graph_path.py +448 -0
  52. sage/combinat/interval_posets.py +3908 -0
  53. sage/combinat/nu_tamari_lattice.py +269 -0
  54. sage/combinat/ordered_tree.py +1446 -0
  55. sage/combinat/posets/all.py +46 -0
  56. sage/combinat/posets/bubble_shuffle.py +247 -0
  57. sage/combinat/posets/cartesian_product.py +493 -0
  58. sage/combinat/posets/d_complete.py +182 -0
  59. sage/combinat/posets/elements.py +273 -0
  60. sage/combinat/posets/forest.py +30 -0
  61. sage/combinat/posets/hasse_cython.cpython-310-aarch64-linux-gnu.so +0 -0
  62. sage/combinat/posets/hasse_cython.pyx +174 -0
  63. sage/combinat/posets/hasse_diagram.py +3672 -0
  64. sage/combinat/posets/hochschild_lattice.py +158 -0
  65. sage/combinat/posets/incidence_algebras.py +794 -0
  66. sage/combinat/posets/lattices.py +5117 -0
  67. sage/combinat/posets/linear_extension_iterator.cpython-310-aarch64-linux-gnu.so +0 -0
  68. sage/combinat/posets/linear_extension_iterator.pyx +292 -0
  69. sage/combinat/posets/linear_extensions.py +1037 -0
  70. sage/combinat/posets/mobile.py +275 -0
  71. sage/combinat/posets/moebius_algebra.py +776 -0
  72. sage/combinat/posets/poset_examples.py +2178 -0
  73. sage/combinat/posets/posets.py +9360 -0
  74. sage/combinat/rooted_tree.py +1070 -0
  75. sage/combinat/shard_order.py +239 -0
  76. sage/combinat/tamari_lattices.py +384 -0
  77. sage/combinat/yang_baxter_graph.py +923 -0
  78. sage/databases/all__sagemath_graphs.py +1 -0
  79. sage/databases/knotinfo_db.py +1231 -0
  80. sage/ext_data/all__sagemath_graphs.py +1 -0
  81. sage/ext_data/graphs/graph_plot_js.html +330 -0
  82. sage/ext_data/kenzo/CP2.txt +45 -0
  83. sage/ext_data/kenzo/CP3.txt +349 -0
  84. sage/ext_data/kenzo/CP4.txt +4774 -0
  85. sage/ext_data/kenzo/README.txt +49 -0
  86. sage/ext_data/kenzo/S4.txt +20 -0
  87. sage/graphs/all.py +42 -0
  88. sage/graphs/asteroidal_triples.cpython-310-aarch64-linux-gnu.so +0 -0
  89. sage/graphs/asteroidal_triples.pyx +320 -0
  90. sage/graphs/base/all.py +1 -0
  91. sage/graphs/base/boost_graph.cpython-310-aarch64-linux-gnu.so +0 -0
  92. sage/graphs/base/boost_graph.pxd +106 -0
  93. sage/graphs/base/boost_graph.pyx +3045 -0
  94. sage/graphs/base/c_graph.cpython-310-aarch64-linux-gnu.so +0 -0
  95. sage/graphs/base/c_graph.pxd +106 -0
  96. sage/graphs/base/c_graph.pyx +5096 -0
  97. sage/graphs/base/dense_graph.cpython-310-aarch64-linux-gnu.so +0 -0
  98. sage/graphs/base/dense_graph.pxd +28 -0
  99. sage/graphs/base/dense_graph.pyx +801 -0
  100. sage/graphs/base/graph_backends.cpython-310-aarch64-linux-gnu.so +0 -0
  101. sage/graphs/base/graph_backends.pxd +5 -0
  102. sage/graphs/base/graph_backends.pyx +797 -0
  103. sage/graphs/base/overview.py +85 -0
  104. sage/graphs/base/sparse_graph.cpython-310-aarch64-linux-gnu.so +0 -0
  105. sage/graphs/base/sparse_graph.pxd +90 -0
  106. sage/graphs/base/sparse_graph.pyx +1653 -0
  107. sage/graphs/base/static_dense_graph.cpython-310-aarch64-linux-gnu.so +0 -0
  108. sage/graphs/base/static_dense_graph.pxd +5 -0
  109. sage/graphs/base/static_dense_graph.pyx +1032 -0
  110. sage/graphs/base/static_sparse_backend.cpython-310-aarch64-linux-gnu.so +0 -0
  111. sage/graphs/base/static_sparse_backend.pxd +27 -0
  112. sage/graphs/base/static_sparse_backend.pyx +1583 -0
  113. sage/graphs/base/static_sparse_graph.cpython-310-aarch64-linux-gnu.so +0 -0
  114. sage/graphs/base/static_sparse_graph.pxd +37 -0
  115. sage/graphs/base/static_sparse_graph.pyx +1375 -0
  116. sage/graphs/bipartite_graph.py +2732 -0
  117. sage/graphs/centrality.cpython-310-aarch64-linux-gnu.so +0 -0
  118. sage/graphs/centrality.pyx +1038 -0
  119. sage/graphs/cographs.py +519 -0
  120. sage/graphs/comparability.cpython-310-aarch64-linux-gnu.so +0 -0
  121. sage/graphs/comparability.pyx +851 -0
  122. sage/graphs/connectivity.cpython-310-aarch64-linux-gnu.so +0 -0
  123. sage/graphs/connectivity.pxd +157 -0
  124. sage/graphs/connectivity.pyx +4813 -0
  125. sage/graphs/convexity_properties.cpython-310-aarch64-linux-gnu.so +0 -0
  126. sage/graphs/convexity_properties.pxd +16 -0
  127. sage/graphs/convexity_properties.pyx +870 -0
  128. sage/graphs/digraph.py +4754 -0
  129. sage/graphs/digraph_generators.py +1993 -0
  130. sage/graphs/distances_all_pairs.cpython-310-aarch64-linux-gnu.so +0 -0
  131. sage/graphs/distances_all_pairs.pxd +12 -0
  132. sage/graphs/distances_all_pairs.pyx +2938 -0
  133. sage/graphs/domination.py +1363 -0
  134. sage/graphs/dot2tex_utils.py +100 -0
  135. sage/graphs/edge_connectivity.cpython-310-aarch64-linux-gnu.so +0 -0
  136. sage/graphs/edge_connectivity.pyx +1215 -0
  137. sage/graphs/generators/all.py +1 -0
  138. sage/graphs/generators/basic.py +1769 -0
  139. sage/graphs/generators/chessboard.py +538 -0
  140. sage/graphs/generators/classical_geometries.py +1611 -0
  141. sage/graphs/generators/degree_sequence.py +235 -0
  142. sage/graphs/generators/distance_regular.cpython-310-aarch64-linux-gnu.so +0 -0
  143. sage/graphs/generators/distance_regular.pyx +2846 -0
  144. sage/graphs/generators/families.py +4759 -0
  145. sage/graphs/generators/intersection.py +565 -0
  146. sage/graphs/generators/platonic_solids.py +262 -0
  147. sage/graphs/generators/random.py +2623 -0
  148. sage/graphs/generators/smallgraphs.py +5741 -0
  149. sage/graphs/generators/world_map.py +724 -0
  150. sage/graphs/generic_graph.py +26867 -0
  151. sage/graphs/generic_graph_pyx.cpython-310-aarch64-linux-gnu.so +0 -0
  152. sage/graphs/generic_graph_pyx.pxd +34 -0
  153. sage/graphs/generic_graph_pyx.pyx +1673 -0
  154. sage/graphs/genus.cpython-310-aarch64-linux-gnu.so +0 -0
  155. sage/graphs/genus.pyx +622 -0
  156. sage/graphs/graph.py +9645 -0
  157. sage/graphs/graph_coloring.cpython-310-aarch64-linux-gnu.so +0 -0
  158. sage/graphs/graph_coloring.pyx +2284 -0
  159. sage/graphs/graph_database.py +1177 -0
  160. sage/graphs/graph_decompositions/all.py +1 -0
  161. sage/graphs/graph_decompositions/bandwidth.cpython-310-aarch64-linux-gnu.so +0 -0
  162. sage/graphs/graph_decompositions/bandwidth.pyx +428 -0
  163. sage/graphs/graph_decompositions/clique_separators.cpython-310-aarch64-linux-gnu.so +0 -0
  164. sage/graphs/graph_decompositions/clique_separators.pyx +616 -0
  165. sage/graphs/graph_decompositions/cutwidth.cpython-310-aarch64-linux-gnu.so +0 -0
  166. sage/graphs/graph_decompositions/cutwidth.pyx +753 -0
  167. sage/graphs/graph_decompositions/fast_digraph.cpython-310-aarch64-linux-gnu.so +0 -0
  168. sage/graphs/graph_decompositions/fast_digraph.pxd +13 -0
  169. sage/graphs/graph_decompositions/fast_digraph.pyx +212 -0
  170. sage/graphs/graph_decompositions/graph_products.cpython-310-aarch64-linux-gnu.so +0 -0
  171. sage/graphs/graph_decompositions/graph_products.pyx +508 -0
  172. sage/graphs/graph_decompositions/modular_decomposition.cpython-310-aarch64-linux-gnu.so +0 -0
  173. sage/graphs/graph_decompositions/modular_decomposition.pxd +27 -0
  174. sage/graphs/graph_decompositions/modular_decomposition.pyx +1536 -0
  175. sage/graphs/graph_decompositions/slice_decomposition.cpython-310-aarch64-linux-gnu.so +0 -0
  176. sage/graphs/graph_decompositions/slice_decomposition.pxd +18 -0
  177. sage/graphs/graph_decompositions/slice_decomposition.pyx +1106 -0
  178. sage/graphs/graph_decompositions/tree_decomposition.cpython-310-aarch64-linux-gnu.so +0 -0
  179. sage/graphs/graph_decompositions/tree_decomposition.pxd +17 -0
  180. sage/graphs/graph_decompositions/tree_decomposition.pyx +1996 -0
  181. sage/graphs/graph_decompositions/vertex_separation.cpython-310-aarch64-linux-gnu.so +0 -0
  182. sage/graphs/graph_decompositions/vertex_separation.pxd +5 -0
  183. sage/graphs/graph_decompositions/vertex_separation.pyx +1963 -0
  184. sage/graphs/graph_editor.py +82 -0
  185. sage/graphs/graph_generators.py +3314 -0
  186. sage/graphs/graph_generators_pyx.cpython-310-aarch64-linux-gnu.so +0 -0
  187. sage/graphs/graph_generators_pyx.pyx +95 -0
  188. sage/graphs/graph_input.py +812 -0
  189. sage/graphs/graph_latex.py +2064 -0
  190. sage/graphs/graph_list.py +410 -0
  191. sage/graphs/graph_plot.py +1756 -0
  192. sage/graphs/graph_plot_js.py +338 -0
  193. sage/graphs/hyperbolicity.cpython-310-aarch64-linux-gnu.so +0 -0
  194. sage/graphs/hyperbolicity.pyx +1704 -0
  195. sage/graphs/hypergraph_generators.py +364 -0
  196. sage/graphs/independent_sets.cpython-310-aarch64-linux-gnu.so +0 -0
  197. sage/graphs/independent_sets.pxd +13 -0
  198. sage/graphs/independent_sets.pyx +402 -0
  199. sage/graphs/isgci.py +1033 -0
  200. sage/graphs/isoperimetric_inequalities.cpython-310-aarch64-linux-gnu.so +0 -0
  201. sage/graphs/isoperimetric_inequalities.pyx +489 -0
  202. sage/graphs/line_graph.cpython-310-aarch64-linux-gnu.so +0 -0
  203. sage/graphs/line_graph.pyx +743 -0
  204. sage/graphs/lovasz_theta.py +77 -0
  205. sage/graphs/matching.py +1633 -0
  206. sage/graphs/matching_covered_graph.py +3590 -0
  207. sage/graphs/orientations.py +1489 -0
  208. sage/graphs/partial_cube.py +459 -0
  209. sage/graphs/path_enumeration.cpython-310-aarch64-linux-gnu.so +0 -0
  210. sage/graphs/path_enumeration.pyx +2040 -0
  211. sage/graphs/pq_trees.py +1129 -0
  212. sage/graphs/print_graphs.py +201 -0
  213. sage/graphs/schnyder.py +865 -0
  214. sage/graphs/spanning_tree.cpython-310-aarch64-linux-gnu.so +0 -0
  215. sage/graphs/spanning_tree.pyx +1457 -0
  216. sage/graphs/strongly_regular_db.cpython-310-aarch64-linux-gnu.so +0 -0
  217. sage/graphs/strongly_regular_db.pyx +3340 -0
  218. sage/graphs/traversals.cpython-310-aarch64-linux-gnu.so +0 -0
  219. sage/graphs/traversals.pxd +9 -0
  220. sage/graphs/traversals.pyx +1872 -0
  221. sage/graphs/trees.cpython-310-aarch64-linux-gnu.so +0 -0
  222. sage/graphs/trees.pxd +15 -0
  223. sage/graphs/trees.pyx +310 -0
  224. sage/graphs/tutte_polynomial.py +713 -0
  225. sage/graphs/views.cpython-310-aarch64-linux-gnu.so +0 -0
  226. sage/graphs/views.pyx +794 -0
  227. sage/graphs/weakly_chordal.cpython-310-aarch64-linux-gnu.so +0 -0
  228. sage/graphs/weakly_chordal.pyx +604 -0
  229. sage/groups/all__sagemath_graphs.py +1 -0
  230. sage/groups/perm_gps/all__sagemath_graphs.py +1 -0
  231. sage/groups/perm_gps/partn_ref/all__sagemath_graphs.py +1 -0
  232. sage/groups/perm_gps/partn_ref/refinement_graphs.cpython-310-aarch64-linux-gnu.so +0 -0
  233. sage/groups/perm_gps/partn_ref/refinement_graphs.pxd +38 -0
  234. sage/groups/perm_gps/partn_ref/refinement_graphs.pyx +1666 -0
  235. sage/knots/all.py +6 -0
  236. sage/knots/free_knotinfo_monoid.py +507 -0
  237. sage/knots/gauss_code.py +291 -0
  238. sage/knots/knot.py +682 -0
  239. sage/knots/knot_table.py +284 -0
  240. sage/knots/knotinfo.py +2900 -0
  241. sage/knots/link.py +4715 -0
  242. sage/sandpiles/all.py +13 -0
  243. sage/sandpiles/examples.py +225 -0
  244. sage/sandpiles/sandpile.py +6365 -0
  245. sage/topology/all.py +22 -0
  246. sage/topology/cell_complex.py +1214 -0
  247. sage/topology/cubical_complex.py +1976 -0
  248. sage/topology/delta_complex.py +1806 -0
  249. sage/topology/filtered_simplicial_complex.py +744 -0
  250. sage/topology/moment_angle_complex.py +823 -0
  251. sage/topology/simplicial_complex.py +5160 -0
  252. sage/topology/simplicial_complex_catalog.py +92 -0
  253. sage/topology/simplicial_complex_examples.py +1680 -0
  254. sage/topology/simplicial_complex_homset.py +205 -0
  255. sage/topology/simplicial_complex_morphism.py +836 -0
  256. sage/topology/simplicial_set.py +4102 -0
  257. sage/topology/simplicial_set_catalog.py +55 -0
  258. sage/topology/simplicial_set_constructions.py +2954 -0
  259. sage/topology/simplicial_set_examples.py +865 -0
  260. sage/topology/simplicial_set_morphism.py +1464 -0
@@ -0,0 +1,1769 @@
1
+ # sage_setup: distribution = sagemath-graphs
2
+ r"""
3
+ Basic graphs
4
+
5
+ The methods defined here appear in :mod:`sage.graphs.graph_generators`.
6
+ """
7
+ # ****************************************************************************
8
+ # Copyright (C) 2006 Robert L. Miller <rlmillster@gmail.com>
9
+ # and Emily A. Kirkman
10
+ # 2009 Michael C. Yurko <myurko@gmail.com>
11
+ #
12
+ # This program is free software: you can redistribute it and/or modify
13
+ # it under the terms of the GNU General Public License as published by
14
+ # the Free Software Foundation, either version 2 of the License, or
15
+ # (at your option) any later version.
16
+ # https://www.gnu.org/licenses/
17
+ # ****************************************************************************
18
+
19
+ # import from Sage library
20
+ from sage.graphs.graph import Graph
21
+ from math import sin, cos, pi
22
+
23
+
24
+ def BullGraph(immutable=False):
25
+ r"""
26
+ Return a bull graph with 5 nodes.
27
+
28
+ A bull graph is named for its shape. It's a triangle with horns.
29
+ See the :wikipedia:`Bull_graph` for more information.
30
+
31
+ INPUT:
32
+
33
+ - ``immutable`` -- boolean (default: ``False``); whether to return an
34
+ immutable or a mutable graph
35
+
36
+ PLOTTING:
37
+
38
+ Upon construction, the position dictionary is filled to override the
39
+ spring-layout algorithm. By convention, the bull graph is drawn as a
40
+ triangle with the first node (0) on the bottom. The second and third nodes
41
+ (1 and 2) complete the triangle. Node 3 is the horn connected to 1 and node
42
+ 4 is the horn connected to node 2.
43
+
44
+ EXAMPLES:
45
+
46
+ Construct and show a bull graph::
47
+
48
+ sage: g = graphs.BullGraph(); g
49
+ Bull graph: Graph on 5 vertices
50
+ sage: g.show() # long time # needs sage.plot
51
+
52
+ The bull graph has 5 vertices and 5 edges. Its radius is 2, its
53
+ diameter 3, and its girth 3. The bull graph is planar with chromatic
54
+ number 3 and chromatic index also 3::
55
+
56
+ sage: g.order(); g.size()
57
+ 5
58
+ 5
59
+ sage: g.radius(); g.diameter(); g.girth()
60
+ 2
61
+ 3
62
+ 3
63
+ sage: g.chromatic_number() # needs cliquer
64
+ 3
65
+
66
+ The bull graph has chromatic polynomial `x(x - 2)(x - 1)^3` and
67
+ Tutte polynomial `x^4 + x^3 + x^2 y`. Its characteristic polynomial
68
+ is `x(x^2 - x - 3)(x^2 + x - 1)`, which follows from the definition of
69
+ characteristic polynomials for graphs, i.e. `\det(xI - A)`, where
70
+ `x` is a variable, `A` the adjacency matrix of the graph, and `I`
71
+ the identity matrix of the same dimensions as `A`::
72
+
73
+ sage: # needs sage.libs.flint
74
+ sage: chrompoly = g.chromatic_polynomial()
75
+ sage: x = chrompoly.parent()('x')
76
+ sage: x * (x - 2) * (x - 1)^3 == chrompoly
77
+ True
78
+
79
+ sage: # needs sage.libs.flint sage.modules
80
+ sage: charpoly = g.characteristic_polynomial()
81
+ sage: M = g.adjacency_matrix(); M
82
+ [0 1 1 0 0]
83
+ [1 0 1 1 0]
84
+ [1 1 0 0 1]
85
+ [0 1 0 0 0]
86
+ [0 0 1 0 0]
87
+ sage: Id = identity_matrix(ZZ, M.nrows())
88
+ sage: D = x*Id - M
89
+ sage: D.determinant() == charpoly # needs sage.symbolic
90
+ True
91
+ sage: x * (x^2 - x - 3) * (x^2 + x - 1) == charpoly
92
+ True
93
+
94
+ TESTS:
95
+
96
+ Check the behavior of parameter ``immutable``::
97
+
98
+ sage: graphs.BullGraph(immutable=True).is_immutable()
99
+ True
100
+ """
101
+ edge_list = [(0, 1), (0, 2), (1, 2), (1, 3), (2, 4)]
102
+ pos_dict = {0: (0, 0), 1: (-1, 1), 2: (1, 1), 3: (-2, 2), 4: (2, 2)}
103
+ return Graph([range(5), edge_list], format='vertices_and_edges',
104
+ immutable=immutable, pos=pos_dict, name="Bull graph")
105
+
106
+
107
+ def ButterflyGraph(immutable=False):
108
+ r"""
109
+ Return the butterfly graph.
110
+
111
+ Let `C_3` be the cycle graph on 3 vertices. The butterfly or bowtie
112
+ graph is obtained by joining two copies of `C_3` at a common vertex,
113
+ resulting in a graph that is isomorphic to the friendship graph `F_2`.
114
+ See the :wikipedia:`Butterfly_graph` for more information.
115
+
116
+ .. SEEALSO::
117
+
118
+ - :meth:`~sage.graphs.graph_generators.GraphGenerators.FriendshipGraph`
119
+
120
+ INPUT:
121
+
122
+ - ``immutable`` -- boolean (default: ``False``); whether to return an
123
+ immutable or a mutable graph
124
+
125
+ EXAMPLES:
126
+
127
+ The butterfly graph is a planar graph on 5 vertices and having 6 edges::
128
+
129
+ sage: G = graphs.ButterflyGraph(); G
130
+ Butterfly graph: Graph on 5 vertices
131
+ sage: G.show() # long time # needs sage.plot
132
+ sage: G.is_planar() # needs planarity
133
+ True
134
+ sage: G.order()
135
+ 5
136
+ sage: G.size()
137
+ 6
138
+
139
+ It has diameter 2, girth 3, and radius 1::
140
+
141
+ sage: G.diameter()
142
+ 2
143
+ sage: G.girth()
144
+ 3
145
+ sage: G.radius()
146
+ 1
147
+
148
+ The butterfly graph is Eulerian, with chromatic number 3::
149
+
150
+ sage: G.is_eulerian()
151
+ True
152
+ sage: G.chromatic_number() # needs cliquer
153
+ 3
154
+
155
+ TESTS:
156
+
157
+ Check the behavior of parameter ``immutable``::
158
+
159
+ sage: graphs.ButterflyGraph(immutable=True).is_immutable()
160
+ True
161
+ """
162
+ edge_dict = {
163
+ 0: [3, 4],
164
+ 1: [2, 4],
165
+ 2: [4],
166
+ 3: [4]}
167
+ pos_dict = {
168
+ 0: [-1, 1],
169
+ 1: [1, 1],
170
+ 2: [1, -1],
171
+ 3: [-1, -1],
172
+ 4: [0, 0]}
173
+ return Graph(edge_dict, format='dict_of_lists',
174
+ immutable=immutable, pos=pos_dict, name="Butterfly graph")
175
+
176
+
177
+ def CircularLadderGraph(n, immutable=False):
178
+ r"""
179
+ Return a circular ladder graph with `2 * n` nodes.
180
+
181
+ A Circular ladder graph is a ladder graph that is connected at the ends,
182
+ i.e.: a ladder bent around so that top meets bottom. Thus it can be
183
+ described as two parallel cycle graphs connected at each corresponding node
184
+ pair.
185
+
186
+ PLOTTING: Upon construction, the position dictionary is filled to override
187
+ the spring-layout algorithm. By convention, the circular ladder graph is
188
+ displayed as an inner and outer cycle pair, with the first `n` nodes drawn
189
+ on the inner circle. The first (0) node is drawn at the top of the
190
+ inner-circle, moving clockwise after that. The outer circle is drawn with
191
+ the `(n+1)`-th node at the top, then counterclockwise as well.
192
+ When `n == 2`, we rotate the outer circle by an angle of `\pi/8` to ensure
193
+ that all edges are visible (otherwise the 4 vertices of the graph would be
194
+ placed on a single line).
195
+
196
+ INPUT:
197
+
198
+ - ``n`` -- nonnegative integer
199
+
200
+ - ``immutable`` -- boolean (default: ``False``); whether to return an
201
+ immutable or a mutable graph
202
+
203
+ EXAMPLES:
204
+
205
+ Construct and show a circular ladder graph with 26 nodes::
206
+
207
+ sage: g = graphs.CircularLadderGraph(13)
208
+ sage: g.show() # long time # needs sage.plot
209
+
210
+ Create several circular ladder graphs in a Sage graphics array::
211
+
212
+ sage: g = []
213
+ sage: j = []
214
+ sage: for i in range(9):
215
+ ....: k = graphs.CircularLadderGraph(i+3)
216
+ ....: g.append(k)
217
+ sage: for i in range(3): # needs sage.plot
218
+ ....: n = []
219
+ ....: for m in range(3):
220
+ ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
221
+ ....: j.append(n)
222
+ sage: G = graphics_array(j) # needs sage.plot
223
+ sage: G.show() # long time # needs sage.plot
224
+
225
+ TESTS::
226
+
227
+ sage: G = graphs.CircularLadderGraph(4, immutable=True)
228
+ sage: G.is_immutable()
229
+ True
230
+ """
231
+ from itertools import chain
232
+ edges_1 = zip(range(n), chain(range(1, n), (0,)))
233
+ edges_2 = zip(range(n, 2 * n), chain(range(n + 1, 2 * n), (n,)))
234
+ edges_3 = ((i, i + n) for i in range(n))
235
+ G = Graph([range(2 * n), chain(edges_1, edges_2, edges_3)],
236
+ format='vertices_and_edges', immutable=immutable,
237
+ name="Circular Ladder graph")
238
+ G._circle_embedding(list(range(n)), radius=1, angle=pi/2)
239
+ if n == 2:
240
+ G._circle_embedding(list(range(4)), radius=1, angle=pi/2 + pi/8)
241
+ else:
242
+ G._circle_embedding(list(range(n, 2*n)), radius=2, angle=pi/2)
243
+ return G
244
+
245
+
246
+ def ClawGraph(immutable=False):
247
+ """
248
+ Return a claw graph.
249
+
250
+ A claw graph is named for its shape. It is actually a complete
251
+ bipartite graph with ``(n1, n2) = (1, 3)``.
252
+
253
+ PLOTTING: See :meth:`CompleteBipartiteGraph`.
254
+
255
+ INPUT:
256
+
257
+ - ``immutable`` -- boolean (default: ``False``); whether to return an
258
+ immutable or a mutable graph
259
+
260
+ EXAMPLES:
261
+
262
+ Show a Claw graph::
263
+
264
+ sage: (graphs.ClawGraph()).show() # long time # needs sage.plot
265
+
266
+ Inspect a Claw graph::
267
+
268
+ sage: G = graphs.ClawGraph()
269
+ sage: G
270
+ Claw graph: Graph on 4 vertices
271
+
272
+ TESTS:
273
+
274
+ Check the behavior of parameter ``immutable``::
275
+
276
+ sage: graphs.ClawGraph(immutable=True).is_immutable()
277
+ True
278
+ """
279
+ edge_list = [(0, 1), (0, 2), (0, 3)]
280
+ pos_dict = {0: (0, 1), 1: (-1, 0), 2: (0, 0), 3: (1, 0)}
281
+ return Graph([range(4), edge_list], format='vertices_and_edges',
282
+ immutable=immutable, pos=pos_dict, name="Claw graph")
283
+
284
+
285
+ def CycleGraph(n, immutable=False):
286
+ r"""
287
+ Return a cycle graph with `n` nodes.
288
+
289
+ A cycle graph is a basic structure which is also typically called an
290
+ `n`-gon.
291
+
292
+ INPUT:
293
+
294
+ - ``n`` -- nonnegative integer; the number of vertices of the cycle graph
295
+
296
+ - ``immutable`` -- boolean (default: ``False``); whether to return an
297
+ immutable or a mutable graph
298
+
299
+ PLOTTING: Upon construction, the position dictionary is filled to override
300
+ the spring-layout algorithm. By convention, each cycle graph will be
301
+ displayed with the first (0) node at the top, with the rest following in a
302
+ counterclockwise manner.
303
+
304
+ The cycle graph is a good opportunity to compare efficiency of filling a
305
+ position dictionary vs. using the spring-layout algorithm for
306
+ plotting. Because the cycle graph is very symmetric, the resulting plots
307
+ should be similar (in cases of small `n`).
308
+
309
+ Filling the position dictionary in advance adds `O(n)` to the constructor.
310
+
311
+ EXAMPLES:
312
+
313
+ Compare plotting using the predefined layout and networkx::
314
+
315
+ sage: # needs networkx sage.plot
316
+ sage: import networkx
317
+ sage: n = networkx.cycle_graph(23)
318
+ sage: spring23 = Graph(n)
319
+ sage: posdict23 = graphs.CycleGraph(23)
320
+ sage: spring23.show() # long time
321
+ sage: posdict23.show() # long time
322
+
323
+ We next view many cycle graphs as a Sage graphics array. First we use the
324
+ ``CycleGraph`` constructor, which fills in the position dictionary::
325
+
326
+ sage: # needs networkx sage.plot
327
+ sage: g = []
328
+ sage: j = []
329
+ sage: for i in range(9):
330
+ ....: k = graphs.CycleGraph(i+3)
331
+ ....: g.append(k)
332
+ sage: for i in range(3):
333
+ ....: n = []
334
+ ....: for m in range(3):
335
+ ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
336
+ ....: j.append(n)
337
+ sage: G = graphics_array(j)
338
+ sage: G.show() # long time
339
+
340
+ Compare to plotting with the spring-layout algorithm::
341
+
342
+ sage: # needs networkx sage.plot
343
+ sage: g = []
344
+ sage: j = []
345
+ sage: for i in range(9):
346
+ ....: spr = networkx.cycle_graph(i+3)
347
+ ....: k = Graph(spr)
348
+ ....: g.append(k)
349
+ sage: for i in range(3):
350
+ ....: n = []
351
+ ....: for m in range(3):
352
+ ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
353
+ ....: j.append(n)
354
+ sage: G = graphics_array(j)
355
+ sage: G.show() # long time
356
+
357
+ TESTS:
358
+
359
+ The input parameter must be a positive integer::
360
+
361
+ sage: G = graphs.CycleGraph(-1)
362
+ Traceback (most recent call last):
363
+ ...
364
+ ValueError: parameter n must be a positive integer
365
+
366
+ Check the behavior of parameter ``immutable``::
367
+
368
+ sage: graphs.CycleGraph(4, immutable=True).is_immutable()
369
+ True
370
+ """
371
+ if n < 0:
372
+ raise ValueError("parameter n must be a positive integer")
373
+
374
+ from itertools import chain
375
+ edges = zip(range(n), chain(range(1, n), (0,))) if n > 1 else []
376
+ G = Graph([range(n), edges], format='vertices_and_edges',
377
+ immutable=immutable, name="Cycle graph")
378
+ if n == 1:
379
+ G.set_pos({0: (0, 0)})
380
+ else:
381
+ G._circle_embedding(list(range(n)), angle=pi/2)
382
+ return G
383
+
384
+
385
+ def CompleteGraph(n, immutable=False):
386
+ r"""
387
+ Return a complete graph on `n` nodes.
388
+
389
+ A Complete Graph is a graph in which all nodes are connected to all
390
+ other nodes.
391
+
392
+ INPUT:
393
+
394
+ - ``n`` -- nonnegative integer; the number of vertices of the complete graph
395
+
396
+ - ``immutable`` -- boolean (default: ``False``); whether to return an
397
+ immutable or a mutable graph
398
+
399
+ PLOTTING: Upon construction, the position dictionary is filled to
400
+ override the spring-layout algorithm. By convention, each complete
401
+ graph will be displayed with the first (0) node at the top, with
402
+ the rest following in a counterclockwise manner.
403
+
404
+ In the complete graph, there is a big difference visually in using
405
+ the spring-layout algorithm vs. the position dictionary used in
406
+ this constructor. The position dictionary flattens the graph,
407
+ making it clear which nodes an edge is connected to. But the
408
+ complete graph offers a good example of how the spring-layout
409
+ works. The edges push outward (everything is connected), causing
410
+ the graph to appear as a 3-dimensional pointy ball. (See examples
411
+ below).
412
+
413
+ EXAMPLES:
414
+
415
+ We view many Complete graphs with a Sage Graphics Array, first with this
416
+ constructor (i.e., the position dictionary filled)::
417
+
418
+ sage: # needs sage.plot
419
+ sage: g = []
420
+ sage: j = []
421
+ sage: for i in range(9):
422
+ ....: k = graphs.CompleteGraph(i+3)
423
+ ....: g.append(k)
424
+ sage: for i in range(3):
425
+ ....: n = []
426
+ ....: for m in range(3):
427
+ ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
428
+ ....: j.append(n)
429
+ sage: G = graphics_array(j)
430
+ sage: G.show() # long time
431
+
432
+ We compare to plotting with the spring-layout algorithm::
433
+
434
+ sage: # needs networkx sage.plot
435
+ sage: import networkx
436
+ sage: g = []
437
+ sage: j = []
438
+ sage: for i in range(9):
439
+ ....: spr = networkx.complete_graph(i+3)
440
+ ....: k = Graph(spr)
441
+ ....: g.append(k)
442
+ sage: for i in range(3):
443
+ ....: n = []
444
+ ....: for m in range(3):
445
+ ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
446
+ ....: j.append(n)
447
+ sage: G = graphics_array(j)
448
+ sage: G.show() # long time
449
+
450
+ Compare the constructors (results will vary)::
451
+
452
+ sage: # needs networkx
453
+ sage: import networkx
454
+ sage: t = cputime()
455
+ sage: n = networkx.complete_graph(389); spring389 = Graph(n)
456
+ sage: cputime(t) # random
457
+ 0.59203700000000126
458
+ sage: t = cputime()
459
+ sage: posdict389 = graphs.CompleteGraph(389)
460
+ sage: cputime(t) # random
461
+ 0.6680419999999998
462
+
463
+ We compare plotting::
464
+
465
+ sage: # needs networkx
466
+ sage: import networkx
467
+ sage: n = networkx.complete_graph(23)
468
+ sage: spring23 = Graph(n)
469
+ sage: posdict23 = graphs.CompleteGraph(23)
470
+ sage: spring23.show() # long time # needs sage.plot
471
+ sage: posdict23.show() # long time # needs sage.plot
472
+
473
+ TESTS:
474
+
475
+ Check the behavior of parameter ``immutable``::
476
+
477
+ sage: graphs.CompleteGraph(4, immutable=True).is_immutable()
478
+ True
479
+ """
480
+ from itertools import combinations
481
+ G = Graph([range(n), combinations(range(n), 2)],
482
+ format='vertices_and_edges', immutable=immutable,
483
+ name="Complete graph")
484
+ if n == 1:
485
+ G.set_pos({0: (0, 0)})
486
+ else:
487
+ G._circle_embedding(list(range(n)), angle=pi/2)
488
+ return G
489
+
490
+
491
+ def CorrelationGraph(seqs, alpha, include_anticorrelation, immutable=False):
492
+ r"""
493
+ Return a correlation graph with a node per sequence in ``seqs``.
494
+
495
+ Edges are added between nodes where the corresponding sequences have a
496
+ correlation coefficient greater than alpha.
497
+
498
+ If ``include_anticorrelation`` is ``True``, then edges are also added
499
+ between nodes with correlation coefficient less than ``-alpha``.
500
+
501
+ INPUT:
502
+
503
+ - ``seqs`` -- list of sequences, that is a list of lists
504
+
505
+ - ``alpha`` -- float; threshold on the correlation coefficient between two
506
+ sequences for adding an edge
507
+
508
+ - ``include_anticorrelation`` -- boolean; whether to add edges between nodes
509
+ with correlation coefficient less than ``-alpha`` or not
510
+
511
+ - ``immutable`` -- boolean (default: ``False``); whether to return an
512
+ immutable or a mutable graph
513
+
514
+ EXAMPLES::
515
+
516
+ sage: # needs numpy
517
+ sage: from sage.graphs.generators.basic import CorrelationGraph
518
+ sage: data = [[1,2,3], [4,5,6], [7,8,9999]]
519
+ sage: CG1 = CorrelationGraph(data, 0.9, False)
520
+ sage: CG2 = CorrelationGraph(data, 0.9, True)
521
+ sage: CG3 = CorrelationGraph(data, 0.1, True)
522
+ sage: CG1.edges(sort=False)
523
+ [(0, 0, None), (0, 1, None), (1, 1, None), (2, 2, None)]
524
+ sage: CG2.edges(sort=False)
525
+ [(0, 0, None), (0, 1, None), (1, 1, None), (2, 2, None)]
526
+ sage: CG3.edges(sort=False)
527
+ [(0, 0, None), (0, 1, None), (0, 2, None), (1, 1, None), (1, 2, None), (2, 2, None)]
528
+
529
+ TESTS:
530
+
531
+ Check the behavior of parameter ``immutable``::
532
+
533
+ sage: # needs numpy
534
+ sage: from sage.graphs.generators.basic import CorrelationGraph
535
+ sage: CorrelationGraph(data, 0.9, False, immutable=True).is_immutable()
536
+ True
537
+ sage: CorrelationGraph(data, 0.9, True, immutable=True).is_immutable()
538
+ True
539
+ """
540
+ from numpy import corrcoef
541
+ from sage.matrix.constructor import Matrix
542
+
543
+ # compute pairwise correlation coefficients
544
+ corrs = corrcoef(seqs)
545
+
546
+ # compare against alpha to get adjacency matrix
547
+ if include_anticorrelation:
548
+ boolean_adjacency_matrix = abs(corrs) >= alpha
549
+ else:
550
+ boolean_adjacency_matrix = corrs >= alpha
551
+
552
+ adjacency_matrix = Matrix(boolean_adjacency_matrix.astype(int))
553
+
554
+ # call graph constructor
555
+ return Graph(adjacency_matrix, format='adjacency_matrix',
556
+ immutable=immutable, name="Correlation Graph")
557
+
558
+
559
+ def CompleteBipartiteGraph(p, q, set_position=True, immutable=False, name=None):
560
+ r"""
561
+ Return a Complete Bipartite Graph on `p + q` vertices.
562
+
563
+ A Complete Bipartite Graph is a graph with its vertices partitioned into two
564
+ groups, `V_1 = \{0,...,p-1\}` and `V_2 = \{p,...,p+q-1\}`. Each `u \in
565
+ V_1` is connected to every `v \in V_2`.
566
+
567
+ INPUT:
568
+
569
+ - ``p``, ``q`` -- number of vertices in each side
570
+
571
+ - ``set_position`` -- boolean (default: ``True``); if set to ``True``, we
572
+ assign positions to the vertices so that the set of cardinality `p` is
573
+ on the line `y=1` and the set of cardinality `q` is on the line `y=0`.
574
+
575
+ - ``immutable`` -- boolean (default: ``False``); whether to return an
576
+ immutable or a mutable graph
577
+
578
+ - ``name`` -- string (default: ``None``); used as the name of the returned
579
+ graph when set
580
+
581
+ PLOTTING: Upon construction, the position dictionary is filled to override
582
+ the spring-layout algorithm. By convention, each complete bipartite graph
583
+ will be displayed with the first `p` nodes on the top row (at `y=1`) from
584
+ left to right. The remaining `q` nodes appear at `y=0`, also from left to
585
+ right. The shorter row (partition with fewer nodes) is stretched to the same
586
+ length as the longer row, unless the shorter row has 1 node; in which case
587
+ it is centered. The `x` values in the plot are in domain `[0, \max(p, q)]`.
588
+
589
+ In the Complete Bipartite graph, there is a visual difference in using the
590
+ spring-layout algorithm vs. the position dictionary used in this
591
+ constructor. The position dictionary flattens the graph and separates the
592
+ partitioned nodes, making it clear which nodes an edge is connected to. The
593
+ Complete Bipartite graph plotted with the spring-layout algorithm tends to
594
+ center the nodes in `p` (see ``spring_med`` in examples below), thus
595
+ overlapping its nodes and edges, making it typically hard to decipher.
596
+
597
+ Filling the position dictionary in advance adds `O(n)` to the constructor.
598
+ Feel free to race the constructors below in the examples section. The much
599
+ larger difference is the time added by the spring-layout algorithm when
600
+ plotting. (Also shown in the example below). The spring model is typically
601
+ described as `O(n^3)`, as appears to be the case in the NetworkX source
602
+ code.
603
+
604
+ EXAMPLES:
605
+
606
+ Two ways of constructing the complete bipartite graph, using different
607
+ layout algorithms::
608
+
609
+ sage: # needs networkx
610
+ sage: import networkx
611
+ sage: n = networkx.complete_bipartite_graph(389, 157) # long time
612
+ sage: spring_big = Graph(n) # long time
613
+ sage: posdict_big = graphs.CompleteBipartiteGraph(389, 157) # long time
614
+
615
+ Compare the plotting::
616
+
617
+ sage: n = networkx.complete_bipartite_graph(11, 17) # needs networkx
618
+ sage: spring_med = Graph(n) # needs networkx
619
+ sage: posdict_med = graphs.CompleteBipartiteGraph(11, 17)
620
+
621
+ Notice here how the spring-layout tends to center the nodes of `n1`::
622
+
623
+ sage: spring_med.show() # long time # needs networkx
624
+ sage: posdict_med.show() # long time # needs sage.plot
625
+
626
+ View many complete bipartite graphs with a Sage Graphics Array, with this
627
+ constructor (i.e., the position dictionary filled)::
628
+
629
+ sage: g = []
630
+ sage: j = []
631
+ sage: for i in range(9):
632
+ ....: k = graphs.CompleteBipartiteGraph(i+1,4)
633
+ ....: g.append(k)
634
+ sage: for i in range(3): # needs sage.plot
635
+ ....: n = []
636
+ ....: for m in range(3):
637
+ ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
638
+ ....: j.append(n)
639
+ sage: G = graphics_array(j) # needs sage.plot
640
+ sage: G.show() # long time # needs sage.plot
641
+
642
+ We compare to plotting with the spring-layout algorithm::
643
+
644
+ sage: # needs networkx sage.plot
645
+ sage: g = []
646
+ sage: j = []
647
+ sage: for i in range(9):
648
+ ....: spr = networkx.complete_bipartite_graph(i+1,4)
649
+ ....: k = Graph(spr)
650
+ ....: g.append(k)
651
+ sage: for i in range(3):
652
+ ....: n = []
653
+ ....: for m in range(3):
654
+ ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
655
+ ....: j.append(n)
656
+ sage: G = graphics_array(j)
657
+ sage: G.show() # long time
658
+
659
+ :issue:`12155`::
660
+
661
+ sage: graphs.CompleteBipartiteGraph(5,6).complement()
662
+ complement(Complete bipartite graph of order 5+6): Graph on 11 vertices
663
+
664
+ TESTS:
665
+
666
+ Prevent negative dimensions (:issue:`18530`)::
667
+
668
+ sage: graphs.CompleteBipartiteGraph(-1,1)
669
+ Traceback (most recent call last):
670
+ ...
671
+ ValueError: the arguments p(=-1) and q(=1) must be positive integers
672
+ sage: graphs.CompleteBipartiteGraph(1,-1)
673
+ Traceback (most recent call last):
674
+ ...
675
+ ValueError: the arguments p(=1) and q(=-1) must be positive integers
676
+
677
+ Check the behavior of parameter ``immutable``::
678
+
679
+ sage: graphs.CompleteBipartiteGraph(1, 2, immutable=True).is_immutable()
680
+ True
681
+
682
+ Check the behavior of parameter ``name``::
683
+
684
+ sage: graphs.CompleteBipartiteGraph(1, 2, name='foo')
685
+ foo: Graph on 3 vertices
686
+ """
687
+ if p < 0 or q < 0:
688
+ raise ValueError('the arguments p(={}) and q(={}) must be positive integers'.format(p, q))
689
+
690
+ name = f"Complete bipartite graph of order {p}+{q}" if name is None else name
691
+ edges = ((i, j) for i in range(p) for j in range(p, p + q))
692
+ G = Graph([range(p + q), edges], format='vertices_and_edges',
693
+ immutable=immutable, name=name)
694
+
695
+ # We now assign positions to vertices:
696
+ # - vertices 0,..,p-1 are placed on the line (0, 1) to (max(p, q), 1)
697
+ # - vertices p,..,p+q-1 are placed on the line (0, 0) to (max(p, q), 0)
698
+ # If p (or q) is 1, the vertex is centered in the line.
699
+ if set_position:
700
+ nmax = max(p, q)
701
+ G._line_embedding(list(range(p)), first=(0, 1), last=(nmax, 1))
702
+ G._line_embedding(list(range(p, p + q)), first=(0, 0), last=(nmax, 0))
703
+
704
+ return G
705
+
706
+
707
+ def CompleteMultipartiteGraph(L, immutable=False):
708
+ r"""
709
+ Return a complete multipartite graph.
710
+
711
+ INPUT:
712
+
713
+ - ``L`` -- list of integers; the respective sizes of the components
714
+
715
+ - ``immutable`` -- boolean (default: ``False``); whether to return an
716
+ immutable or a mutable graph
717
+
718
+ PLOTTING: Produce a layout of the vertices so that vertices in the same
719
+ vertex set are adjacent and clearly separated from vertices in other vertex
720
+ sets.
721
+
722
+ This is done by calculating the vertices of an `r`-gon then calculating the
723
+ slope between adjacent vertices. We then 'walk' around the `r`-gon placing
724
+ graph vertices in regular intervals between adjacent vertices of the
725
+ `r`-gon.
726
+
727
+ Makes a nicely organized graph like in this picture:
728
+ https://commons.wikimedia.org/wiki/File:Turan_13-4.svg
729
+
730
+ EXAMPLES:
731
+
732
+ A complete tripartite graph with sets of sizes `5, 6, 8`::
733
+
734
+ sage: g = graphs.CompleteMultipartiteGraph([5, 6, 8]); g
735
+ Multipartite Graph with set sizes [5, 6, 8]: Graph on 19 vertices
736
+
737
+ It clearly has a chromatic number of 3::
738
+
739
+ sage: g.chromatic_number() # needs cliquer
740
+ 3
741
+
742
+ TESTS:
743
+
744
+ Prevent negative dimensions::
745
+
746
+ sage: graphs.CompleteMultipartiteGraph([1, -1, 2])
747
+ Traceback (most recent call last):
748
+ ...
749
+ ValueError: the sizes of the components must be positive integers
750
+
751
+ Check the behaviour of parameter ``immutable``::
752
+
753
+ sage: graphs.CompleteMultipartiteGraph([1], immutable=True).is_immutable()
754
+ True
755
+ sage: graphs.CompleteMultipartiteGraph([1, 2], immutable=True).is_immutable()
756
+ True
757
+ sage: graphs.CompleteMultipartiteGraph([1, 2, 3], immutable=True).is_immutable()
758
+ True
759
+ """
760
+ if any(p < 0 for p in L):
761
+ raise ValueError("the sizes of the components must be positive integers")
762
+
763
+ r = len(L) # getting the number of partitions
764
+ name = "Multipartite Graph with set sizes {}".format(L)
765
+
766
+ if not r:
767
+ return Graph(name=name, immutable=immutable)
768
+ if r == 1:
769
+ g = Graph(L[0], immutable=immutable, name=name)
770
+ g._line_embedding(range(L[0]), first=(0, 0), last=(L[0], 0))
771
+ return g
772
+ if r == 2:
773
+ return CompleteBipartiteGraph(L[0], L[1], immutable=immutable, name=name)
774
+
775
+ # This position code gives bad results on bipartite or isolated graphs
776
+ points = [(cos(2 * pi * i / r), sin(2 * pi * i / r)) for i in range(r)]
777
+ slopes = [(points[(i + 1) % r][0] - points[i % r][0],
778
+ points[(i + 1) % r][1] - points[i % r][1]) for i in range(r)]
779
+
780
+ counter = 0
781
+ parts = []
782
+ positions = {}
783
+ for i, size in enumerate(L):
784
+ parts.append(list(range(counter, counter + size)))
785
+ vertex_set_size = size + 1
786
+ for j in range(1, vertex_set_size):
787
+ x = points[i][0] + slopes[i][0] * j / vertex_set_size
788
+ y = points[i][1] + slopes[i][1] * j / vertex_set_size
789
+ positions[counter] = (x, y)
790
+ counter += 1
791
+
792
+ from itertools import combinations
793
+ edges = ((a, b) for A, B in combinations(parts, 2) for a in A for b in B)
794
+ return Graph([range(counter), edges], format='vertices_and_edges',
795
+ immutable=immutable, pos=positions, name=name)
796
+
797
+
798
+ def DiamondGraph(immutable=False):
799
+ """
800
+ Return a diamond graph with 4 nodes.
801
+
802
+ A diamond graph is a square with one pair of diagonal nodes connected.
803
+
804
+ INPUT:
805
+
806
+ - ``immutable`` -- boolean (default: ``False``); whether to return an
807
+ immutable or a mutable graph
808
+
809
+ PLOTTING: Upon construction, the position dictionary is filled to override
810
+ the spring-layout algorithm. By convention, the diamond graph is drawn as a
811
+ diamond, with the first node on top, second on the left, third on the right,
812
+ and fourth on the bottom; with the second and third node connected.
813
+
814
+ EXAMPLES:
815
+
816
+ Construct and show a diamond graph::
817
+
818
+ sage: g = graphs.DiamondGraph()
819
+ sage: g.show() # long time # needs sage.plot
820
+
821
+ TESTS:
822
+
823
+ Check the behavior of parameter ``immutable``::
824
+
825
+ sage: graphs.DiamondGraph(immutable=True).is_immutable()
826
+ True
827
+ """
828
+ pos_dict = {0: (0, 1), 1: (-1, 0), 2: (1, 0), 3: (0, -1)}
829
+ edges = [(0, 1), (0, 2), (1, 2), (1, 3), (2, 3)]
830
+ return Graph([range(4), edges], format='vertices_and_edges',
831
+ immutable=immutable, pos=pos_dict, name="Diamond Graph")
832
+
833
+
834
+ def GemGraph(immutable=False):
835
+ """
836
+ Return a gem graph with 5 nodes.
837
+
838
+ A gem graph is a fan graph (4,1).
839
+
840
+ INPUT:
841
+
842
+ - ``immutable`` -- boolean (default: ``False``); whether to return an
843
+ immutable or a mutable graph
844
+
845
+ PLOTTING: Upon construction, the position dictionary is filled to override
846
+ the spring-layout algorithm. By convention, the gem graph is drawn as a gem,
847
+ with the sharp part on the bottom.
848
+
849
+ EXAMPLES:
850
+
851
+ Construct and show a gem graph::
852
+
853
+ sage: g = graphs.GemGraph()
854
+ sage: g.show() # long time # needs sage.plot
855
+
856
+ TESTS:
857
+
858
+ Check the behavior of parameter ``immutable``::
859
+
860
+ sage: graphs.GemGraph(immutable=True).is_immutable()
861
+ True
862
+ """
863
+ pos_dict = {0: (0.5, 0), 1: (0, 0.75), 2: (0.25, 1), 3: (0.75, 1), 4: (1, 0.75)}
864
+ edges = [(0, 1), (0, 2), (0, 3), (0, 4), (1, 2), (2, 3), (3, 4)]
865
+ return Graph([range(5), edges], format='vertices_and_edges',
866
+ immutable=immutable, pos=pos_dict, name="Gem Graph")
867
+
868
+
869
+ def ForkGraph(immutable=False):
870
+ """
871
+ Return a fork graph with 5 nodes.
872
+
873
+ A fork graph, sometimes also called chair graph, is 5 vertex tree.
874
+
875
+ INPUT:
876
+
877
+ - ``immutable`` -- boolean (default: ``False``); whether to return an
878
+ immutable or a mutable graph
879
+
880
+ PLOTTING: Upon construction, the position dictionary is filled to override
881
+ the spring-layout algorithm. By convention, the fork graph is drawn as a
882
+ fork, with the sharp part on the bottom.
883
+
884
+ EXAMPLES:
885
+
886
+ Construct and show a fork graph::
887
+
888
+ sage: g = graphs.ForkGraph()
889
+ sage: g.show() # long time # needs sage.plot
890
+
891
+ TESTS:
892
+
893
+ Check the behavior of parameter ``immutable``::
894
+
895
+ sage: graphs.ForkGraph(immutable=True).is_immutable()
896
+ True
897
+ """
898
+ pos_dict = {0: (0, 0), 1: (1, 0), 2: (0, 1), 3: (1, 1), 4: (0, 2)}
899
+ edges = [(0, 2), (2, 3), (3, 1), (2, 4)]
900
+ return Graph([range(5), edges], format='vertices_and_edges',
901
+ immutable=immutable, pos=pos_dict, name="Fork Graph")
902
+
903
+
904
+ def DartGraph(immutable=False):
905
+ """
906
+ Return a dart graph with 5 nodes.
907
+
908
+ INPUT:
909
+
910
+ - ``immutable`` -- boolean (default: ``False``); whether to return an
911
+ immutable or a mutable graph
912
+
913
+ PLOTTING: Upon construction, the position dictionary is filled to override
914
+ the spring-layout algorithm. By convention, the dart graph is drawn as a
915
+ dart, with the sharp part on the bottom.
916
+
917
+ EXAMPLES:
918
+
919
+ Construct and show a dart graph::
920
+
921
+ sage: g = graphs.DartGraph()
922
+ sage: g.show() # long time # needs sage.plot
923
+
924
+ TESTS:
925
+
926
+ Check the behavior of parameter ``immutable``::
927
+
928
+ sage: graphs.DartGraph(immutable=True).is_immutable()
929
+ True
930
+ """
931
+ pos_dict = {0: (0, 1), 1: (-1, 0), 2: (1, 0), 3: (0, -1), 4: (0, 0)}
932
+ edges = [(0, 1), (0, 2), (1, 4), (2, 4), (0, 4), (3, 4)]
933
+ return Graph([range(5), edges], format='vertices_and_edges',
934
+ immutable=immutable, pos=pos_dict, name="Dart Graph")
935
+
936
+
937
+ def EmptyGraph(immutable=False):
938
+ """
939
+ Return an empty graph (0 nodes and 0 edges).
940
+
941
+ This is useful for constructing graphs by adding edges and vertices
942
+ individually or in a loop.
943
+
944
+ INPUT:
945
+
946
+ - ``immutable`` -- boolean (default: ``False``); whether to return an
947
+ immutable or a mutable graph
948
+
949
+ PLOTTING: When plotting, this graph will use the default
950
+ spring-layout algorithm, unless a position dictionary is
951
+ specified.
952
+
953
+ EXAMPLES:
954
+
955
+ Add one vertex to an empty graph and then show::
956
+
957
+ sage: empty1 = graphs.EmptyGraph()
958
+ sage: empty1.add_vertex()
959
+ 0
960
+ sage: empty1.show() # long time # needs sage.plot
961
+
962
+ Use for loops to build a graph from an empty graph::
963
+
964
+ sage: empty2 = graphs.EmptyGraph()
965
+ sage: for i in range(5):
966
+ ....: empty2.add_vertex() # add 5 nodes, labeled 0-4
967
+ 0
968
+ 1
969
+ 2
970
+ 3
971
+ 4
972
+ sage: for i in range(3):
973
+ ....: empty2.add_edge(i,i+1) # add edges {[0:1],[1:2],[2:3]}
974
+ sage: for i in range(1, 4):
975
+ ....: empty2.add_edge(4,i) # add edges {[1:4],[2:4],[3:4]}
976
+ sage: empty2.show() # long time # needs sage.plot
977
+
978
+ TESTS:
979
+
980
+ Check the behavior of parameter ``immutable``::
981
+
982
+ sage: graphs.EmptyGraph(immutable=True).is_immutable()
983
+ True
984
+ """
985
+ return Graph(sparse=True, immutable=immutable)
986
+
987
+
988
+ def ToroidalGrid2dGraph(p, q, immutable=False):
989
+ r"""
990
+ Return a toroidal 2-dimensional grid graph with `p \times q` nodes (`p` rows
991
+ and `q` columns).
992
+
993
+ The toroidal 2-dimensional grid with parameters `p,q` is the 2-dimensional
994
+ grid graph with identical parameters to which are added the edges
995
+ `((i, 0), (i, q - 1))` and `((0, i), (p - 1, i))`.
996
+
997
+ INPUT:
998
+
999
+ - ``p, q`` -- nonnegative integers; the sides of the toroidal grid
1000
+
1001
+ - ``immutable`` -- boolean (default: ``False``); whether to return an
1002
+ immutable or a mutable graph
1003
+
1004
+ EXAMPLES:
1005
+
1006
+ The toroidal 2-dimensional grid is a regular graph, while the usual
1007
+ 2-dimensional grid is not ::
1008
+
1009
+ sage: tgrid = graphs.ToroidalGrid2dGraph(8,9)
1010
+ sage: print(tgrid)
1011
+ Toroidal 2D Grid Graph with parameters 8,9
1012
+ sage: grid = graphs.Grid2dGraph(8,9)
1013
+ sage: grid.is_regular()
1014
+ False
1015
+ sage: tgrid.is_regular()
1016
+ True
1017
+
1018
+ TESTS:
1019
+
1020
+ Check the behavior of parameter ``immutable``::
1021
+
1022
+ sage: graphs.ToroidalGrid2dGraph(2, 3, immutable=True).is_immutable()
1023
+ True
1024
+ """
1025
+ name = f"Toroidal 2D Grid Graph with parameters {p},{q}"
1026
+ g = Grid2dGraph(p, q, set_positions=True, immutable=False)
1027
+ g.name(name)
1028
+
1029
+ g.add_edges([((i, 0), (i, q - 1)) for i in range(p)])
1030
+ g.add_edges([((0, i), (p - 1, i)) for i in range(q)])
1031
+
1032
+ pos = g._pos
1033
+ p += 0.
1034
+ q += 0.
1035
+ uf = (p / 2) * (p / 2)
1036
+ vf = (q / 2) * (q / 2)
1037
+ for u, v in g:
1038
+ x, y = pos[u, v]
1039
+ x += 0.25 * (1.0 + u * (u - p + 1) / uf)
1040
+ y += 0.25 * (1.0 + v * (v - q + 1) / vf)
1041
+ pos[u, v] = (x, y)
1042
+
1043
+ if immutable:
1044
+ return Graph(g, immutable=True, pos=g.get_pos(), name=name)
1045
+ return g
1046
+
1047
+
1048
+ def Toroidal6RegularGrid2dGraph(p, q, immutable=False):
1049
+ r"""
1050
+ Return a toroidal 6-regular grid.
1051
+
1052
+ The toroidal 6-regular grid is a 6-regular graph on `p \times q` vertices
1053
+ and its elements have coordinates `(i, j)` for `i \in \{0...p-1\}` and
1054
+ `j \in \{0...q-1\}`.
1055
+
1056
+ Its edges are those of the :meth:`ToroidalGrid2dGraph`, to which are added
1057
+ the edges between `(i, j)` and `((i + 1) \% p, (j + 1) \% q)`.
1058
+
1059
+ INPUT:
1060
+
1061
+ - ``p``, ``q`` -- integers
1062
+
1063
+ - ``immutable`` -- boolean (default: ``False``); whether to return an
1064
+ immutable or a mutable graph
1065
+
1066
+ EXAMPLES:
1067
+
1068
+ The toroidal 6-regular grid on `25` elements::
1069
+
1070
+ sage: g = graphs.Toroidal6RegularGrid2dGraph(5,5)
1071
+ sage: g.is_regular(k=6)
1072
+ True
1073
+ sage: g.is_vertex_transitive() # needs sage.groups
1074
+ True
1075
+ sage: g.line_graph().is_vertex_transitive() # needs sage.groups
1076
+ True
1077
+ sage: g.automorphism_group().cardinality() # needs sage.groups
1078
+ 300
1079
+ sage: g.is_hamiltonian() # needs sage.numerical.mip
1080
+ True
1081
+
1082
+ TESTS:
1083
+
1084
+ Senseless input::
1085
+
1086
+ sage: graphs.Toroidal6RegularGrid2dGraph(5,2)
1087
+ Traceback (most recent call last):
1088
+ ...
1089
+ ValueError: parameters p and q must be integers larger than 3
1090
+ sage: graphs.Toroidal6RegularGrid2dGraph(2,0)
1091
+ Traceback (most recent call last):
1092
+ ...
1093
+ ValueError: parameters p and q must be integers larger than 3
1094
+
1095
+ Check the behavior of parameter ``immutable``::
1096
+
1097
+ sage: graphs.Toroidal6RegularGrid2dGraph(4, 4, immutable=True).is_immutable()
1098
+ True
1099
+ """
1100
+ if p <= 3 or q <= 3:
1101
+ raise ValueError("parameters p and q must be integers larger than 3")
1102
+
1103
+ g = ToroidalGrid2dGraph(p, q, immutable=False)
1104
+ for u, v in g:
1105
+ g.add_edge((u, v), ((u + 1) % p, (v + 1) % q))
1106
+
1107
+ name = f"Toroidal Hexagonal Grid graph on {p}x{q} elements"
1108
+ if immutable:
1109
+ return Graph(g, immutable=True, pos=g.get_pos(), name=name)
1110
+ g.name(name)
1111
+ return g
1112
+
1113
+
1114
+ def Grid2dGraph(p, q, set_positions=True, immutable=False, name=None):
1115
+ r"""
1116
+ Return a `2`-dimensional grid graph with `p \times q` nodes (`p` rows and
1117
+ `q` columns).
1118
+
1119
+ A 2d grid graph resembles a `2` dimensional grid. All inner nodes are
1120
+ connected to their `4` neighbors. Outer (non-corner) nodes are connected to
1121
+ their `3` neighbors. Corner nodes are connected to their 2 neighbors.
1122
+
1123
+ INPUT:
1124
+
1125
+ - ``p``, ``q`` -- two positive integers
1126
+
1127
+ - ``set_positions`` -- boolean (default: ``True``); whether to set the
1128
+ position of the nodes
1129
+
1130
+ - ``immutable`` -- boolean (default: ``False``); whether to return an
1131
+ immutable or a mutable graph
1132
+
1133
+ - ``name`` -- string (default: ``None``); used as the name of the returned
1134
+ graph when set
1135
+
1136
+ PLOTTING: Upon construction, the position dictionary is filled to override
1137
+ the spring-layout algorithm. By convention, nodes are labelled in (row,
1138
+ column) pairs with `(0, 0)` in the top left corner. Edges will always be
1139
+ horizontal and vertical - another advantage of filling the position
1140
+ dictionary.
1141
+
1142
+ EXAMPLES:
1143
+
1144
+ Construct and show a grid 2d graph Rows = `5`, Columns = `7`::
1145
+
1146
+ sage: g = graphs.Grid2dGraph(5,7)
1147
+ sage: g.show() # long time # needs sage.plot
1148
+
1149
+ TESTS:
1150
+
1151
+ Senseless input::
1152
+
1153
+ sage: graphs.Grid2dGraph(5,0)
1154
+ Traceback (most recent call last):
1155
+ ...
1156
+ ValueError: parameters p and q must be positive integers
1157
+ sage: graphs.Grid2dGraph(-1,0)
1158
+ Traceback (most recent call last):
1159
+ ...
1160
+ ValueError: parameters p and q must be positive integers
1161
+
1162
+ The graph name contains the dimension::
1163
+
1164
+ sage: g = graphs.Grid2dGraph(5,7)
1165
+ sage: g.name()
1166
+ '2D Grid Graph for [5, 7]'
1167
+
1168
+ Check the behavior of parameter ``ìmmutable``::
1169
+
1170
+ sage: graphs.Grid2dGraph(2, 3, immutable=True).is_immutable()
1171
+ True
1172
+
1173
+ Check the behavior of parameter ``name``::
1174
+
1175
+ sage: graphs.Grid2dGraph(2, 3, name='foo')
1176
+ foo: Graph on 6 vertices
1177
+ """
1178
+ if p <= 0 or q <= 0:
1179
+ raise ValueError("parameters p and q must be positive integers")
1180
+
1181
+ vertices = ((i, j) for i in range(p) for j in range(q))
1182
+ from itertools import chain
1183
+ edges = chain((((i, j), (i + 1, j)) for i in range(p - 1) for j in range(q)),
1184
+ (((i, j), (i, j + 1)) for i in range(p) for j in range(q - 1)))
1185
+ pos_dict = None
1186
+ if set_positions:
1187
+ pos_dict = {(i, j): (j, -i) for i in range(p) for j in range(q)}
1188
+ return Graph([vertices, edges], format='vertices_and_edges',
1189
+ immutable=immutable, pos=pos_dict,
1190
+ name=f"2D Grid Graph for [{p}, {q}]" if name is None else name)
1191
+
1192
+
1193
+ def GridGraph(dim_list, immutable=False):
1194
+ r"""
1195
+ Return an `n`-dimensional grid graph.
1196
+
1197
+ INPUT:
1198
+
1199
+ - ``dim_list`` -- list of integers representing the number of nodes to
1200
+ extend in each dimension
1201
+
1202
+ - ``immutable`` -- boolean (default: ``False``); whether to return an
1203
+ immutable or a mutable graph
1204
+
1205
+ PLOTTING: When plotting, this graph will use the default spring-layout
1206
+ algorithm, unless a position dictionary is specified.
1207
+
1208
+ EXAMPLES::
1209
+
1210
+ sage: G = graphs.GridGraph([2,3,4])
1211
+ sage: G.show() # long time # needs sage.plot
1212
+
1213
+ ::
1214
+
1215
+ sage: C = graphs.CubeGraph(4)
1216
+ sage: G = graphs.GridGraph([2,2,2,2])
1217
+ sage: C.show() # long time # needs sage.plot
1218
+ sage: G.show() # long time # needs sage.plot
1219
+
1220
+ TESTS:
1221
+
1222
+ The graph name contains the dimension::
1223
+
1224
+ sage: g = graphs.GridGraph([5, 7])
1225
+ sage: g.name()
1226
+ 'Grid Graph for [5, 7]'
1227
+ sage: g = graphs.GridGraph([2, 3, 4])
1228
+ sage: g.name()
1229
+ 'Grid Graph for [2, 3, 4]'
1230
+ sage: g = graphs.GridGraph([2, 4, 3])
1231
+ sage: g.name()
1232
+ 'Grid Graph for [2, 4, 3]'
1233
+
1234
+ One dimensional grids (i.e., path) have simple vertex labels::
1235
+
1236
+ sage: g = graphs.GridGraph([5])
1237
+ sage: g.vertices(sort=True)
1238
+ [0, 1, 2, 3, 4]
1239
+
1240
+ The graph is correct::
1241
+
1242
+ sage: dim = [randint(1,4) for i in range(4)]
1243
+ sage: g = graphs.GridGraph(dim)
1244
+ sage: import networkx # needs networkx
1245
+ sage: h = Graph(networkx.grid_graph(list(dim))) # needs networkx
1246
+ sage: g.is_isomorphic(h) # needs networkx
1247
+ True
1248
+
1249
+ Trivial cases::
1250
+
1251
+ sage: g = graphs.GridGraph([]); g; g.vertices(sort=False)
1252
+ Grid Graph for []: Graph on 0 vertices
1253
+ []
1254
+ sage: g = graphs.GridGraph([1]); g; g.vertices(sort=False)
1255
+ Grid Graph for [1]: Graph on 1 vertex
1256
+ [0]
1257
+ sage: g = graphs.GridGraph([2]); g; g.vertices(sort=True)
1258
+ Grid Graph for [2]: Graph on 2 vertices
1259
+ [0, 1]
1260
+ sage: g = graphs.GridGraph([1,1]); g; g.vertices(sort=False)
1261
+ Grid Graph for [1, 1]: Graph on 1 vertex
1262
+ [(0, 0)]
1263
+ sage: g = graphs.GridGraph([1, 1, 1]); g; g.vertices(sort=False)
1264
+ Grid Graph for [1, 1, 1]: Graph on 1 vertex
1265
+ [(0, 0, 0)]
1266
+ sage: g = graphs.GridGraph([1,1,2]); g; g.vertices(sort=True)
1267
+ Grid Graph for [1, 1, 2]: Graph on 2 vertices
1268
+ [(0, 0, 0), (0, 0, 1)]
1269
+
1270
+ All dimensions must be positive integers::
1271
+
1272
+ sage: g = graphs.GridGraph([2,-1,3])
1273
+ Traceback (most recent call last):
1274
+ ...
1275
+ ValueError: all dimensions must be positive integers
1276
+
1277
+ Check the behavior of parameter ``ìmmutable``::
1278
+
1279
+ sage: graphs.GridGraph([], immutable=True).is_immutable()
1280
+ True
1281
+ sage: graphs.GridGraph([2], immutable=True).is_immutable()
1282
+ True
1283
+ sage: graphs.GridGraph([2, 2], immutable=True).is_immutable()
1284
+ True
1285
+ sage: graphs.GridGraph([2, 2, 2], immutable=True).is_immutable()
1286
+ True
1287
+ """
1288
+ dim = [int(a) for a in dim_list]
1289
+ if any(a <= 0 for a in dim):
1290
+ raise ValueError("all dimensions must be positive integers")
1291
+
1292
+ name = "Grid Graph for {}".format(dim)
1293
+ n_dim = len(dim)
1294
+ if not n_dim:
1295
+ return Graph(name=name, immutable=immutable)
1296
+ if n_dim == 1:
1297
+ # Vertices are labeled from 0 to dim[0]-1
1298
+ return PathGraph(dim[0], immutable=immutable, name=name)
1299
+ if n_dim == 2:
1300
+ # We use the Grid2dGraph generator to also get the positions
1301
+ return Grid2dGraph(*dim, immutable=immutable, name=name)
1302
+
1303
+ # Now, n_dim > 2 and we don't set positions
1304
+ # Vertices are tuples of dimension n_dim, and the graph contains at
1305
+ # least vertex (0, 0, ..., 0)
1306
+ V = [tuple([0] * n_dim)]
1307
+
1308
+ def edges():
1309
+ from itertools import product
1310
+ for u in product(*[range(d) for d in dim]):
1311
+ for i in range(n_dim):
1312
+ if u[i] + 1 < dim[i]:
1313
+ v = list(u)
1314
+ v[i] = u[i] + 1
1315
+ yield (u, tuple(v))
1316
+
1317
+ return Graph([V, edges()], format='vertices_and_edges',
1318
+ immutable=immutable, name=name)
1319
+
1320
+
1321
+ def HouseGraph(immutable=False):
1322
+ """
1323
+ Return a house graph with 5 nodes.
1324
+
1325
+ A house graph is named for its shape. It is a triangle (roof) over a
1326
+ square (walls).
1327
+
1328
+ PLOTTING: Upon construction, the position dictionary is filled to override
1329
+ the spring-layout algorithm. By convention, the house graph is drawn with
1330
+ the first node in the lower-left corner of the house, the second in the
1331
+ lower-right corner of the house. The third node is in the upper-left corner
1332
+ connecting the roof to the wall, and the fourth is in the upper-right corner
1333
+ connecting the roof to the wall. The fifth node is the top of the roof,
1334
+ connected only to the third and fourth.
1335
+
1336
+ INPUT:
1337
+
1338
+ - ``immutable`` -- boolean (default: ``False``); whether to return an
1339
+ immutable or a mutable graph
1340
+
1341
+ EXAMPLES:
1342
+
1343
+ Construct and show a house graph::
1344
+
1345
+ sage: g = graphs.HouseGraph()
1346
+ sage: g.show() # long time # needs sage.plot
1347
+
1348
+ TESTS:
1349
+
1350
+ Check the behavior of parameter ``immutable``::
1351
+
1352
+ sage: graphs.HouseGraph(immutable=True).is_immutable()
1353
+ True
1354
+ """
1355
+ pos_dict = {0: (-1, 0), 1: (1, 0), 2: (-1, 1), 3: (1, 1), 4: (0, 2)}
1356
+ edges = [(0, 1), (0, 2), (1, 3), (2, 3), (2, 4), (3, 4)]
1357
+ return Graph([range(5), edges], format='vertices_and_edges',
1358
+ immutable=immutable, pos=pos_dict, name="House Graph")
1359
+
1360
+
1361
+ def HouseXGraph(immutable=False):
1362
+ """
1363
+ Return a house X graph with 5 nodes.
1364
+
1365
+ A house X graph is a house graph with two additional edges. The upper-right
1366
+ corner is connected to the lower-left. And the upper-left corner is
1367
+ connected to the lower-right.
1368
+
1369
+ PLOTTING: Upon construction, the position dictionary is filled to override
1370
+ the spring-layout algorithm. By convention, the house X graph is drawn with
1371
+ the first node in the lower-left corner of the house, the second in the
1372
+ lower-right corner of the house. The third node is in the upper-left corner
1373
+ connecting the roof to the wall, and the fourth is in the upper-right corner
1374
+ connecting the roof to the wall. The fifth node is the top of the roof,
1375
+ connected only to the third and fourth.
1376
+
1377
+ INPUT:
1378
+
1379
+ - ``immutable`` -- boolean (default: ``False``); whether to return an
1380
+ immutable or a mutable graph
1381
+
1382
+ EXAMPLES:
1383
+
1384
+ Construct and show a house X graph::
1385
+
1386
+ sage: g = graphs.HouseXGraph()
1387
+ sage: g.show() # long time # needs sage.plot
1388
+
1389
+ TESTS:
1390
+
1391
+ Check the behavior of parameter ``immutable``::
1392
+
1393
+ sage: graphs.HouseXGraph(immutable=True).is_immutable()
1394
+ True
1395
+ """
1396
+ pos_dict = {0: (-1, 0), 1: (1, 0), 2: (-1, 1), 3: (1, 1), 4: (0, 2)}
1397
+ edges = [(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3), (2, 4), (3, 4)]
1398
+ return Graph([range(5), edges], format='vertices_and_edges',
1399
+ immutable=immutable, pos=pos_dict, name="House Graph")
1400
+
1401
+
1402
+ def LadderGraph(n, immutable=False):
1403
+ r"""
1404
+ Return a ladder graph with `2 * n` nodes.
1405
+
1406
+ A ladder graph is a basic structure that is typically displayed as a ladder,
1407
+ i.e.: two parallel path graphs connected at each corresponding node pair.
1408
+
1409
+ PLOTTING: Upon construction, the position dictionary is filled to override
1410
+ the spring-layout algorithm. By convention, each ladder graph will be
1411
+ displayed horizontally, with the first n nodes displayed left to right on
1412
+ the top horizontal line.
1413
+
1414
+ INPUT:
1415
+
1416
+ - ``n`` -- a nonnegative integer; number of nodes is `2n`
1417
+
1418
+ - ``immutable`` -- boolean (default: ``False``); whether to return an
1419
+ immutable or a mutable graph
1420
+
1421
+ EXAMPLES:
1422
+
1423
+ Construct and show a ladder graph with 14 nodes::
1424
+
1425
+ sage: g = graphs.LadderGraph(7)
1426
+ sage: g.show() # long time # needs sage.plot
1427
+
1428
+ Create several ladder graphs in a Sage graphics array::
1429
+
1430
+ sage: # needs sage.plot
1431
+ sage: g = []
1432
+ sage: j = []
1433
+ sage: for i in range(9):
1434
+ ....: k = graphs.LadderGraph(i+2)
1435
+ ....: g.append(k)
1436
+ sage: for i in range(3):
1437
+ ....: n = []
1438
+ ....: for m in range(3):
1439
+ ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
1440
+ ....: j.append(n)
1441
+ sage: G = graphics_array(j)
1442
+ sage: G.show() # long time
1443
+
1444
+ TESTS:
1445
+
1446
+ Check the behavior of parameter ``immutable``::
1447
+
1448
+ sage: graphs.LadderGraph(4, immutable=True).is_immutable()
1449
+ True
1450
+ """
1451
+ pos_dict = {i: (i, 1) for i in range(n)}
1452
+ for i in range(n, 2 * n):
1453
+ x = i - n
1454
+ pos_dict[i] = (x, 0)
1455
+ from itertools import chain
1456
+ edges_1 = zip(range(n), range(1, n))
1457
+ edges_2 = zip(range(n, 2 * n), range(n + 1, 2 * n))
1458
+ edges_3 = ((i, i + n) for i in range(n))
1459
+ return Graph([range(2 * n), chain(edges_1, edges_2, edges_3)],
1460
+ format='vertices_and_edges', immutable=immutable,
1461
+ pos=pos_dict, name="Ladder graph")
1462
+
1463
+
1464
+ def MoebiusLadderGraph(n, immutable=False):
1465
+ r"""
1466
+ Return a Möbius ladder graph with `2n` nodes
1467
+
1468
+ A Möbius ladder graph of order `2n` is a ladder graph of the same order
1469
+ that is connected at the ends with a single twist, i.e., a ladder graph
1470
+ bent around so that top meets bottom with a single twist. Alternatively,
1471
+ it can be described as a single cycle graph (of order `2n`) with the
1472
+ addition of edges (called `rungs`) joining the antipodal pairs of nodes.
1473
+ Also, note that the Möbius ladder graph ``graphs.MoebiusLadderGraph(n)`` is
1474
+ precisely the same graph as the circulant graph
1475
+ ``graphs.CirculantGraph(2 * n, [1, n])``.
1476
+
1477
+ PLOTTING:
1478
+
1479
+ Upon construction, the position dictionary is filled to override the
1480
+ spring-layout algorithm. By convention, each Möbius ladder graph will be
1481
+ displayed with the first (0) node at the top, with the rest following in a
1482
+ counterclockwise manner.
1483
+
1484
+ INPUT:
1485
+
1486
+ - ``n`` -- a nonnegative integer; number of nodes is `2n`
1487
+
1488
+ - ``immutable`` -- boolean (default: ``False``); whether to return an
1489
+ immutable or a mutable graph
1490
+
1491
+ OUTPUT:
1492
+
1493
+ - ``G`` -- a Möbius ladder graph of order `2n`; note that a
1494
+ :exc:`ValueError` is returned if `n < 0`
1495
+
1496
+ EXAMPLES:
1497
+
1498
+ Construct and show a Möbius ladder graph with 26 nodes::
1499
+
1500
+ sage: g = graphs.MoebiusLadderGraph(13)
1501
+ sage: g.show() # long time # needs sage.plot
1502
+
1503
+ Create several Möbius ladder graphs in a Sage graphics array::
1504
+
1505
+ sage: # needs sage.plots
1506
+ sage: g = []
1507
+ sage: j = []
1508
+ sage: for i in range(9):
1509
+ ....: k = graphs.MoebiusLadderGraph(i+3)
1510
+ ....: g.append(k)
1511
+ sage: for i in range(3):
1512
+ ....: n = []
1513
+ ....: for m in range(3):
1514
+ ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
1515
+ ....: j.append(n)
1516
+ sage: G = graphics_array(j)
1517
+ sage: G.show() # long time
1518
+
1519
+ TESTS:
1520
+
1521
+ The input parameter must be a nonnegative integer::
1522
+
1523
+ sage: G = graphs.MoebiusLadderGraph(-1)
1524
+ Traceback (most recent call last):
1525
+ ...
1526
+ ValueError: parameter n must be a nonnegative integer
1527
+
1528
+ Check the behavior of parameter ``immutable``::
1529
+
1530
+ sage: graphs.MoebiusLadderGraph(4, immutable=True).is_immutable()
1531
+ True
1532
+
1533
+ REFERENCES:
1534
+
1535
+ - :wikipedia:`Möbius_ladder`
1536
+
1537
+ .. SEEALSO::
1538
+ :meth:`~sage.graphs.graph_generators.GraphGenerators.LadderGraph`,
1539
+ :meth:`~sage.graphs.graph_generators.GraphGenerators.CircularLadderGraph`,
1540
+ :meth:`~sage.graphs.graph_generators.GraphGenerators.CirculantGraph`
1541
+
1542
+ AUTHORS:
1543
+
1544
+ - Janmenjaya Panda (2024-05-26)
1545
+ """
1546
+ if n < 0:
1547
+ raise ValueError("parameter n must be a nonnegative integer")
1548
+
1549
+ from itertools import chain
1550
+ edges_1 = zip(range(2 * n), chain(range(1, 2 * n), (0,)))
1551
+ edges_2 = ((i, i + n) for i in range(n))
1552
+ G = Graph([range(2 * n), chain(edges_1, edges_2)],
1553
+ format='vertices_and_edges', immutable=immutable,
1554
+ name="Moebius ladder graph")
1555
+ G._circle_embedding(list(range(2 * n)), angle=pi/2)
1556
+ return G
1557
+
1558
+
1559
+ def PathGraph(n, pos=None, immutable=False, name=None):
1560
+ r"""
1561
+ Return a path graph with `n` nodes.
1562
+
1563
+ A path graph is a graph where all inner nodes are connected to their two
1564
+ neighbors and the two end-nodes are connected to their one inner neighbors
1565
+ (i.e.: a cycle graph without the first and last node connected).
1566
+
1567
+ INPUT:
1568
+
1569
+ - ``n`` -- nonnegative integer; number of nodes of the path graph
1570
+
1571
+ - ``pos`` -- string (default: ``None``); indicates the embedding to use
1572
+ between 'circle', 'line' or the default algorithm. See the plotting
1573
+ section below for more detail.
1574
+
1575
+ - ``immutable`` -- boolean (default: ``False``); whether to return an
1576
+ immutable or a mutable graph
1577
+
1578
+ - ``name`` -- string (default: ``None``); used as the name of the returned
1579
+ graph when set
1580
+
1581
+ PLOTTING: Upon construction, the position dictionary is filled to override
1582
+ the spring-layout algorithm. By convention, the graph may be drawn in one of
1583
+ two ways: The 'line' argument will draw the graph in a horizontal line (left
1584
+ to right) if there are less than 11 nodes. Otherwise the 'line' argument
1585
+ will append horizontal lines of length 10 nodes below, alternating left to
1586
+ right and right to left. The 'circle' argument will cause the graph to be
1587
+ drawn in a cycle-shape, with the first node at the top and then about the
1588
+ circle in a clockwise manner. By default (without an appropriate string
1589
+ argument) the graph will be drawn as a 'circle' if `10 < n < 41` and as a
1590
+ 'line' for all other `n`.
1591
+
1592
+ EXAMPLES:
1593
+
1594
+ Show default drawing by size: 'line': `n \leq 10`::
1595
+
1596
+ sage: p = graphs.PathGraph(10)
1597
+ sage: p.show() # long time # needs sage.plot
1598
+
1599
+ 'circle': `10 < n < 41`::
1600
+
1601
+ sage: q = graphs.PathGraph(25)
1602
+ sage: q.show() # long time # needs sage.plot
1603
+
1604
+ 'line': `n \geq 41`::
1605
+
1606
+ sage: r = graphs.PathGraph(55)
1607
+ sage: r.show() # long time # needs sage.plot
1608
+
1609
+ Override the default drawing::
1610
+
1611
+ sage: s = graphs.PathGraph(5,'circle')
1612
+ sage: s.show() # long time # needs sage.plot
1613
+
1614
+ TESTS:
1615
+
1616
+ Check the behavior of parameter ``immutable``::
1617
+
1618
+ sage: graphs.PathGraph(4, immutable=True).is_immutable()
1619
+ True
1620
+
1621
+ Check the behavior of parameter ``name``::
1622
+
1623
+ sage: graphs.PathGraph(4, name='foo')
1624
+ foo: Graph on 4 vertices
1625
+ """
1626
+ edges = ((i, i + 1) for i in range(n - 1))
1627
+ G = Graph([range(n), edges], format='vertices_and_edges',
1628
+ immutable=immutable, name="Path graph" if name is None else name)
1629
+
1630
+ pos_dict = {}
1631
+
1632
+ # Choose appropriate drawing pattern
1633
+ circle = False
1634
+ if pos == "circle":
1635
+ circle = True
1636
+ elif pos == "line":
1637
+ circle = False
1638
+ # Otherwise use default by size of n
1639
+ elif 10 < n < 41:
1640
+ circle = True
1641
+
1642
+ # Draw 'circle'
1643
+ if circle:
1644
+ if n == 1:
1645
+ G.set_pos({0: (0, 0)})
1646
+ else:
1647
+ G._circle_embedding(list(range(n)), angle=pi/2)
1648
+ # Draw 'line'
1649
+ else:
1650
+ counter = 0 # node index
1651
+ rem = n % 10 # remainder to appear on last row
1652
+ rows = n // 10 # number of rows (not counting last row)
1653
+ lr = True # left to right
1654
+
1655
+ for i in range(rows): # note that rows doesn't include last row
1656
+ y = -i
1657
+ for j in range(10):
1658
+ if lr:
1659
+ x = j
1660
+ else:
1661
+ x = 9 - j
1662
+ pos_dict[counter] = (x, y)
1663
+ counter += 1
1664
+ if lr:
1665
+ lr = False
1666
+ else:
1667
+ lr = True
1668
+ y = -rows
1669
+ for j in range(rem): # last row
1670
+ if lr:
1671
+ x = j
1672
+ else:
1673
+ x = 9 - j
1674
+ pos_dict[counter] = (x, y)
1675
+ counter += 1
1676
+ G.set_pos(pos_dict)
1677
+
1678
+ return G
1679
+
1680
+
1681
+ def StarGraph(n, immutable=False):
1682
+ r"""
1683
+ Return a star graph with `n + 1` nodes.
1684
+
1685
+ A Star graph is a basic structure where one node is connected to all other
1686
+ nodes.
1687
+
1688
+ INPUT:
1689
+
1690
+ - ``n`` -- a nonnegative integer; number of nodes is `n + 1`
1691
+
1692
+ - ``immutable`` -- boolean (default: ``False``); whether to return an
1693
+ immutable or a mutable graph
1694
+
1695
+ PLOTTING: Upon construction, the position dictionary is filled to override
1696
+ the spring-layout algorithm. By convention, each star graph will be
1697
+ displayed with the first (0) node in the center, the second node (1) at the
1698
+ top, with the rest following in a counterclockwise manner. (0) is the node
1699
+ connected to all other nodes.
1700
+
1701
+ The star graph is a good opportunity to compare efficiency of filling a
1702
+ position dictionary vs. using the spring-layout algorithm for plotting. As
1703
+ far as display, the spring-layout should push all other nodes away from the
1704
+ (0) node, and thus look very similar to this constructor's positioning.
1705
+
1706
+ EXAMPLES::
1707
+
1708
+ sage: import networkx # needs networkx
1709
+
1710
+ Compare the plots::
1711
+
1712
+ sage: # needs networkx sage.plot
1713
+ sage: n = networkx.star_graph(23)
1714
+ sage: spring23 = Graph(n)
1715
+ sage: posdict23 = graphs.StarGraph(23)
1716
+ sage: spring23.show() # long time
1717
+ sage: posdict23.show() # long time
1718
+
1719
+ View many star graphs as a Sage Graphics Array
1720
+
1721
+ With this constructor (i.e., the position dictionary filled)
1722
+
1723
+ ::
1724
+
1725
+ sage: # needs sage.plot
1726
+ sage: g = []
1727
+ sage: j = []
1728
+ sage: for i in range(9):
1729
+ ....: k = graphs.StarGraph(i+3)
1730
+ ....: g.append(k)
1731
+ sage: for i in range(3):
1732
+ ....: n = []
1733
+ ....: for m in range(3):
1734
+ ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
1735
+ ....: j.append(n)
1736
+ sage: G = graphics_array(j)
1737
+ sage: G.show() # long time
1738
+
1739
+ Compared to plotting with the spring-layout algorithm
1740
+
1741
+ ::
1742
+
1743
+ sage: # needs networkx sage.plot
1744
+ sage: g = []
1745
+ sage: j = []
1746
+ sage: for i in range(9):
1747
+ ....: spr = networkx.star_graph(i+3)
1748
+ ....: k = Graph(spr)
1749
+ ....: g.append(k)
1750
+ sage: for i in range(3):
1751
+ ....: n = []
1752
+ ....: for m in range(3):
1753
+ ....: n.append(g[3*i + m].plot(vertex_size=50, vertex_labels=False))
1754
+ ....: j.append(n)
1755
+ sage: G = graphics_array(j)
1756
+ sage: G.show() # long time
1757
+
1758
+ TESTS:
1759
+
1760
+ Check the behavior of parameter ``immutable``::
1761
+
1762
+ sage: graphs.StarGraph(4, immutable=True).is_immutable()
1763
+ True
1764
+ """
1765
+ G = Graph({0: list(range(1, n + 1))}, format='dict_of_lists',
1766
+ immutable=immutable, name="Star graph")
1767
+ G.set_pos({0: (0, 0)})
1768
+ G._circle_embedding(list(range(1, n + 1)), angle=pi/2)
1769
+ return G