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,3301 @@
1
+ # sage_setup: distribution = sagemath-graphs
2
+ r"""
3
+ Common graphs
4
+
5
+ All graphs in Sage can be built through the ``graphs`` object. In order to
6
+ build a complete graph on 15 elements, one can do::
7
+
8
+ sage: g = graphs.CompleteGraph(15)
9
+
10
+ To get a path with 4 vertices, and the house graph::
11
+
12
+ sage: p = graphs.PathGraph(4)
13
+ sage: h = graphs.HouseGraph()
14
+
15
+ More interestingly, one can get the list of all graphs that Sage knows how to
16
+ build by typing ``graphs.`` in Sage and then hitting :kbd:`Tab`.
17
+ """
18
+
19
+ import subprocess
20
+
21
+
22
+ # This method appends a list of methods to the doc as a 3xN table.
23
+
24
+ # Here's the point :
25
+ #
26
+ # we just have to insert the method's name in this file to add it to
27
+ # the tab, and in exchange the doc contains a table of width 3 with
28
+ # all methods listed, so that the reading order is Column1, then
29
+ # Column2, then Column3. Doing this by hand is hell with Sphinx when
30
+ # you need to insert a new method inside of the list !
31
+
32
+ def __append_to_doc(methods):
33
+ global __doc__
34
+ __doc__ += ("\n.. csv-table::\n"
35
+ " :class: contentstable\n"
36
+ " :widths: 33, 33, 33\n"
37
+ " :delim: |\n\n")
38
+
39
+ h = (len(methods)+2)//3
40
+ # Reorders the list of methods for horizontal reading, the only one Sphinx understands
41
+ reordered_methods = [0]*3*h
42
+ for i, m in enumerate(methods):
43
+ reordered_methods[3*(i % h) + (i//h)] = m
44
+ methods = reordered_methods
45
+
46
+ # Adding the list to the __doc__ string
47
+ def wrap_name(x):
48
+ if x:
49
+ return ":meth:`" + str(x) + " <GraphGenerators." + str(x) + ">`"
50
+ return ""
51
+
52
+ while methods:
53
+ a = methods.pop(0)
54
+ b = methods.pop(0)
55
+ c = methods.pop(0)
56
+ __doc__ += " " + wrap_name(a) + " | " + wrap_name(b) + " | " + wrap_name(c) + "\n"
57
+
58
+
59
+ __doc__ += """
60
+ **Basic structures**
61
+ """
62
+
63
+ __append_to_doc(
64
+ ["BullGraph",
65
+ "ButterflyGraph",
66
+ "CircularLadderGraph",
67
+ "ClawGraph",
68
+ "CycleGraph",
69
+ "CompleteBipartiteGraph",
70
+ "CompleteGraph",
71
+ "CompleteMultipartiteGraph",
72
+ "CorrelationGraph",
73
+ "DiamondGraph",
74
+ "GemGraph",
75
+ "DartGraph",
76
+ "ForkGraph",
77
+ "DipoleGraph",
78
+ "EmptyGraph",
79
+ "Grid2dGraph",
80
+ "GridGraph",
81
+ "HouseGraph",
82
+ "HouseXGraph",
83
+ "LadderGraph",
84
+ "LollipopGraph",
85
+ "MoebiusLadderGraph",
86
+ "PathGraph",
87
+ "StarGraph",
88
+ "TadpoleGraph",
89
+ "ToroidalGrid2dGraph",
90
+ "Toroidal6RegularGrid2dGraph"]
91
+ )
92
+
93
+ __doc__ += """
94
+ **Small Graphs**
95
+
96
+ A small graph is just a single graph and has no parameter influencing
97
+ the number of edges or vertices.
98
+ """
99
+
100
+ __append_to_doc(
101
+ ["Balaban10Cage",
102
+ "Balaban11Cage",
103
+ "BidiakisCube",
104
+ "BiggsSmithGraph",
105
+ "BlanusaFirstSnarkGraph",
106
+ "BlanusaSecondSnarkGraph",
107
+ "BrinkmannGraph",
108
+ "BrouwerHaemersGraph",
109
+ "BuckyBall",
110
+ "CameronGraph",
111
+ "Cell600",
112
+ "Cell120",
113
+ "ChvatalGraph",
114
+ "ClebschGraph",
115
+ "cocliques_HoffmannSingleton",
116
+ "ConwaySmith_for_3S7",
117
+ "CoxeterGraph",
118
+ "CubeplexGraph",
119
+ "DesarguesGraph",
120
+ "DejterGraph",
121
+ "distance_3_doubly_truncated_Golay_code_graph",
122
+ "DoubleStarSnark",
123
+ "DoublyTruncatedWittGraph",
124
+ "DurerGraph",
125
+ "DyckGraph",
126
+ "EllinghamHorton54Graph",
127
+ "EllinghamHorton78Graph",
128
+ "ErreraGraph",
129
+ "F26AGraph",
130
+ "FlowerSnark",
131
+ "FolkmanGraph",
132
+ "FosterGraph",
133
+ "FosterGraph3S6",
134
+ "FranklinGraph",
135
+ "FruchtGraph",
136
+ "GoldnerHararyGraph",
137
+ "GolombGraph",
138
+ "GossetGraph",
139
+ "graph_3O73",
140
+ "GrayGraph",
141
+ "GritsenkoGraph",
142
+ "GrotzschGraph",
143
+ "HallJankoGraph",
144
+ "HarborthGraph",
145
+ "HarriesGraph",
146
+ "HarriesWongGraph",
147
+ "HeawoodGraph",
148
+ "HerschelGraph",
149
+ "HigmanSimsGraph",
150
+ "HoffmanGraph",
151
+ "HoffmanSingletonGraph",
152
+ "HoltGraph",
153
+ "HortonGraph",
154
+ "IoninKharaghani765Graph",
155
+ "IvanovIvanovFaradjevGraph",
156
+ "J2Graph",
157
+ "JankoKharaghaniGraph",
158
+ "JankoKharaghaniTonchevGraph",
159
+ "KittellGraph",
160
+ "KrackhardtKiteGraph",
161
+ "Klein3RegularGraph",
162
+ "Klein7RegularGraph",
163
+ "LargeWittGraph",
164
+ "LeonardGraph",
165
+ "LjubljanaGraph",
166
+ "vanLintSchrijverGraph",
167
+ "LivingstoneGraph",
168
+ "locally_GQ42_distance_transitive_graph",
169
+ "LocalMcLaughlinGraph",
170
+ "M22Graph",
171
+ "MarkstroemGraph",
172
+ "MathonStronglyRegularGraph",
173
+ "McGeeGraph",
174
+ "McLaughlinGraph",
175
+ "MeredithGraph",
176
+ "MoebiusKantorGraph",
177
+ "MoserSpindle",
178
+ "MurtyGraph",
179
+ "NauruGraph",
180
+ "PappusGraph",
181
+ "PoussinGraph",
182
+ "PerkelGraph",
183
+ "PetersenGraph",
184
+ "RobertsonGraph",
185
+ "SchlaefliGraph",
186
+ "shortened_00_11_binary_Golay_code_graph",
187
+ "shortened_000_111_extended_binary_Golay_code_graph",
188
+ "ShrikhandeGraph",
189
+ "SimsGewirtzGraph",
190
+ "SousselierGraph",
191
+ "SylvesterGraph",
192
+ "SzekeresSnarkGraph",
193
+ "ThomsenGraph",
194
+ "TietzeGraph",
195
+ "TricornGraph",
196
+ "TruncatedIcosidodecahedralGraph",
197
+ "TruncatedTetrahedralGraph",
198
+ "TruncatedWittGraph",
199
+ "Tutte12Cage",
200
+ "TutteCoxeterGraph",
201
+ "TutteGraph",
202
+ "TwinplexGraph",
203
+ "U42Graph216",
204
+ "U42Graph540",
205
+ "WagnerGraph",
206
+ "WatkinsSnarkGraph",
207
+ "WellsGraph",
208
+ "WienerArayaGraph",
209
+ "SuzukiGraph"])
210
+
211
+ __doc__ += """
212
+ **Platonic solids** (ordered ascending by number of vertices)
213
+ """
214
+
215
+ __append_to_doc(
216
+ ["TetrahedralGraph",
217
+ "OctahedralGraph",
218
+ "HexahedralGraph",
219
+ "IcosahedralGraph",
220
+ "DodecahedralGraph"])
221
+
222
+ __doc__ += """
223
+ **Families of graphs**
224
+
225
+ A family of graph is an infinite set of graphs which can be indexed by fixed
226
+ number of parameters, e.g. two integer parameters. (A method whose name starts
227
+ with a small letter does not return a single graph object but a graph iterator
228
+ or a list of graphs or ...)
229
+ """
230
+
231
+ __append_to_doc(
232
+ ["AlternatingFormsGraph",
233
+ "AztecDiamondGraph",
234
+ "BalancedTree",
235
+ "BarbellGraph",
236
+ "BilinearFormsGraph",
237
+ "BiwheelGraph",
238
+ "BubbleSortGraph",
239
+ "CaiFurerImmermanGraph",
240
+ "chang_graphs",
241
+ "CirculantGraph",
242
+ "cographs",
243
+ "cospectral_graphs",
244
+ "CubeGraph",
245
+ "CubeConnectedCycle",
246
+ "distance_regular_graph",
247
+ "DorogovtsevGoltsevMendesGraph",
248
+ "DoubleGrassmannGraph",
249
+ "DoubleOddGraph",
250
+ "EgawaGraph",
251
+ "FibonacciTree",
252
+ "FoldedCubeGraph",
253
+ "FriendshipGraph",
254
+ "fullerenes",
255
+ "FurerGadget",
256
+ "fusenes",
257
+ "FuzzyBallGraph",
258
+ "GeneralisedDodecagonGraph",
259
+ "GeneralisedHexagonGraph",
260
+ "GeneralisedOctagonGraph",
261
+ "GeneralizedPetersenGraph",
262
+ "GeneralizedSierpinskiGraph",
263
+ "GoethalsSeidelGraph",
264
+ "GrassmannGraph",
265
+ "HalfCube",
266
+ "HammingGraph",
267
+ "HanoiTowerGraph",
268
+ "HararyGraph",
269
+ "HermitianFormsGraph",
270
+ "HyperStarGraph",
271
+ "JohnsonGraph",
272
+ "KneserGraph",
273
+ "LCFGraph",
274
+ "line_graph_forbidden_subgraphs",
275
+ "MathonPseudocyclicMergingGraph",
276
+ "MathonPseudocyclicStronglyRegularGraph",
277
+ "MuzychukS6Graph",
278
+ "MycielskiGraph",
279
+ "MycielskiStep",
280
+ "nauty_geng",
281
+ "nauty_genbg",
282
+ "NKStarGraph",
283
+ "NStarGraph",
284
+ "OddGraph",
285
+ "PaleyGraph",
286
+ "PasechnikGraph",
287
+ "petersen_family",
288
+ "planar_graphs",
289
+ "plantri_gen",
290
+ "quadrangulations",
291
+ "RingedTree",
292
+ "SierpinskiGasketGraph",
293
+ "SquaredSkewHadamardMatrixGraph",
294
+ "SwitchedSquaredSkewHadamardMatrixGraph",
295
+ "StaircaseGraph",
296
+ "strongly_regular_graph",
297
+ "trees",
298
+ "TruncatedBiwheelGraph",
299
+ "nauty_gentreeg",
300
+ "triangulations",
301
+ "TuranGraph",
302
+ "UstimenkoGraph",
303
+ "WheelGraph",
304
+ "WindmillGraph"])
305
+
306
+
307
+ __doc__ += """
308
+ **Graphs from classical geometries over finite fields**
309
+
310
+ A number of classes of graphs related to geometries over finite fields and
311
+ quadrics and Hermitean varieties there.
312
+ """
313
+
314
+ __append_to_doc(
315
+ ["AffineOrthogonalPolarGraph",
316
+ "AhrensSzekeresGeneralizedQuadrangleGraph",
317
+ "NonisotropicOrthogonalPolarGraph",
318
+ "NonisotropicUnitaryPolarGraph",
319
+ "OrthogonalDualPolarGraph",
320
+ "OrthogonalPolarGraph",
321
+ "SymplecticDualPolarGraph",
322
+ "SymplecticPolarGraph",
323
+ "TaylorTwographDescendantSRG",
324
+ "TaylorTwographSRG",
325
+ "T2starGeneralizedQuadrangleGraph",
326
+ "Nowhere0WordsTwoWeightCodeGraph",
327
+ "HaemersGraph",
328
+ "CossidentePenttilaGraph",
329
+ "UnitaryDualPolarGraph",
330
+ "UnitaryPolarGraph"])
331
+
332
+ __doc__ += """
333
+ **Chessboard Graphs**
334
+ """
335
+
336
+ __append_to_doc(
337
+ ["BishopGraph",
338
+ "KingGraph",
339
+ "KnightGraph",
340
+ "QueenGraph",
341
+ "RookGraph"])
342
+
343
+ __doc__ += """
344
+ **Intersection graphs**
345
+
346
+ These graphs are generated by geometric representations. The objects of
347
+ the representation correspond to the graph vertices and the intersections
348
+ of objects yield the graph edges.
349
+ """
350
+
351
+ __append_to_doc(
352
+ ["IntersectionGraph",
353
+ "IntervalGraph",
354
+ "OrthogonalArrayBlockGraph",
355
+ "PermutationGraph",
356
+ "ToleranceGraph"])
357
+
358
+ __doc__ += """
359
+ **Random graphs**
360
+ """
361
+
362
+ __append_to_doc(
363
+ ["RandomBarabasiAlbert",
364
+ "RandomBicubicPlanar",
365
+ "RandomBipartite",
366
+ "RandomRegularBipartite",
367
+ "RandomBlockGraph",
368
+ "RandomBoundedToleranceGraph",
369
+ "RandomGNM",
370
+ "RandomGNP",
371
+ "RandomHolmeKim",
372
+ "RandomChordalGraph",
373
+ "RandomIntervalGraph",
374
+ "RandomKTree",
375
+ "RandomPartialKTree",
376
+ "RandomLobster",
377
+ "RandomNewmanWattsStrogatz",
378
+ "RandomProperIntervalGraph",
379
+ "RandomRegular",
380
+ "RandomShell",
381
+ "RandomToleranceGraph",
382
+ "RandomTree",
383
+ "RandomTreePowerlaw",
384
+ "RandomTriangulation",
385
+ "RandomUnitDiskGraph"])
386
+
387
+ __doc__ += """
388
+ **Graphs with a given degree sequence**
389
+ """
390
+
391
+ __append_to_doc(
392
+ ["DegreeSequence",
393
+ "DegreeSequenceBipartite",
394
+ "DegreeSequenceConfigurationModel",
395
+ "DegreeSequenceExpected",
396
+ "DegreeSequenceTree"])
397
+
398
+ __doc__ += """
399
+ **Miscellaneous**
400
+ """
401
+
402
+ __append_to_doc(
403
+ ["WorldMap",
404
+ "EuropeMap",
405
+ "AfricaMap",
406
+ "USAMap"]
407
+ )
408
+
409
+ __doc__ += """
410
+
411
+ AUTHORS:
412
+
413
+ - Robert Miller (2006-11-05): initial version, empty, random, petersen
414
+
415
+ - Emily Kirkman (2006-11-12): basic structures, node positioning for
416
+ all constructors
417
+
418
+ - Emily Kirkman (2006-11-19): docstrings, examples
419
+
420
+ - William Stein (2006-12-05): Editing.
421
+
422
+ - Robert Miller (2007-01-16): Cube generation and plotting
423
+
424
+ - Emily Kirkman (2007-01-16): more basic structures, docstrings
425
+
426
+ - Emily Kirkman (2007-02-14): added more named graphs
427
+
428
+ - Robert Miller (2007-06-08-11): Platonic solids, random graphs,
429
+ graphs with a given degree sequence, random directed graphs
430
+
431
+ - Robert Miller (2007-10-24): Isomorph free exhaustive generation
432
+
433
+ - Nathann Cohen (2009-08-12): WorldMap
434
+
435
+ - Michael Yurko (2009-9-01): added hyperstar, (n,k)-star, n-star, and
436
+ bubblesort graphs
437
+
438
+ - Anders Jonsson (2009-10-15): added generalized Petersen graphs
439
+
440
+ - Harald Schilly and Yann Laigle-Chapuy (2010-03-24): added Fibonacci Tree
441
+
442
+ - Jason Grout (2010-06-04): cospectral_graphs
443
+
444
+ - Edward Scheinerman (2010-08-11): RandomTree
445
+
446
+ - Ed Scheinerman (2010-08-21): added Grotzsch graph and Mycielski graphs
447
+
448
+ - Ed Scheinerman (2010-11-15): added RandomTriangulation
449
+
450
+ - Minh Van Nguyen (2010-11-26): added more named graphs
451
+
452
+ - Keshav Kini (2011-02-16): added Shrikhande and Dyck graphs
453
+
454
+ - David Coudert (2012-02-10): new RandomGNP generator
455
+
456
+ - David Coudert (2012-08-02): added chessboard graphs: Queen, King,
457
+ Knight, Bishop, and Rook graphs
458
+
459
+ - Nico Van Cleemput (2013-05-26): added fullerenes
460
+
461
+ - Nico Van Cleemput (2013-07-01): added benzenoids
462
+
463
+ - Birk Eisermann (2013-07-29): new section 'intersection graphs',
464
+ added (random, bounded) tolerance graphs
465
+
466
+ - Marco Cognetta (2016-03-03): added TuranGraph
467
+
468
+ - Janmenjaya Panda (2024-05-26): added MoebiusLadderGraph
469
+
470
+ - Janmenjaya Panda (2024-06-09): added StaircaseGraph, BiwheelGraph and
471
+ TruncatedBiwheelGraph
472
+
473
+
474
+ Functions and methods
475
+ ---------------------
476
+ """
477
+
478
+ # ****************************************************************************
479
+ # Copyright (C) 2006 Robert L. Miller <rlmillster@gmail.com>
480
+ # Emily A. Kirkman
481
+ # 2009 Michael C. Yurko <myurko@gmail.com>
482
+ #
483
+ # This program is free software: you can redistribute it and/or modify
484
+ # it under the terms of the GNU General Public License as published by
485
+ # the Free Software Foundation, either version 2 of the License, or
486
+ # (at your option) any later version.
487
+ # https://www.gnu.org/licenses/
488
+ # ****************************************************************************
489
+
490
+ from . import graph
491
+
492
+
493
+ class GraphGenerators:
494
+ r"""
495
+ A class consisting of constructors for several common graphs, as well as
496
+ orderly generation of isomorphism class representatives. See the
497
+ :mod:`module's help <sage.graphs.graph_generators>` for a list of supported
498
+ constructors.
499
+
500
+ A list of all graphs and graph structures (other than isomorphism class
501
+ representatives) in this database is available via tab completion. Type
502
+ "graphs." and then hit the :kbd:`Tab` key to see which graphs are available.
503
+
504
+ The docstrings include educational information about each named
505
+ graph with the hopes that this class can be used as a reference.
506
+
507
+ For all the constructors in this class (except the octahedral,
508
+ dodecahedral, random and empty graphs), the position dictionary is
509
+ filled to override the spring-layout algorithm.
510
+
511
+
512
+ ORDERLY GENERATION::
513
+
514
+ graphs(vertices, property=lambda x: True, augment='edges', size=None)
515
+
516
+ This syntax accesses the generator of isomorphism class
517
+ representatives. Iterates over distinct, exhaustive
518
+ representatives.
519
+
520
+ Also: see the use of the nauty package for generating graphs
521
+ at the :meth:`nauty_geng` method.
522
+
523
+ INPUT:
524
+
525
+ - ``vertices`` -- a natural number or ``None`` to infinitely generate
526
+ bigger and bigger graphs
527
+
528
+ - ``property`` -- (default: ``lambda x: True``) any property to be
529
+ tested on graphs before generation, but note that in general the
530
+ graphs produced are not the same as those produced by using the
531
+ property function to filter a list of graphs produced by using
532
+ the ``lambda x: True`` default. The generation process assumes
533
+ the property has certain characteristics set by the ``augment``
534
+ argument, and only in the case of inherited properties such that
535
+ all subgraphs of the relevant kind (for ``augment='edges'`` or
536
+ ``augment='vertices'``) of a graph with the property also
537
+ possess the property will there be no missing graphs. (The
538
+ ``property`` argument is ignored if ``degree_sequence`` is
539
+ specified.)
540
+
541
+ - ``augment`` -- (default: ``'edges'``) possible values:
542
+
543
+ - ``'edges'`` -- augments a fixed number of vertices by
544
+ adding one edge. In this case, all graphs on *exactly* ``n=vertices`` are
545
+ generated. If for any graph G satisfying the property, every
546
+ subgraph, obtained from G by deleting one edge but not the vertices
547
+ incident to that edge, satisfies the property, then this will
548
+ generate all graphs with that property. If this does not hold, then
549
+ all the graphs generated will satisfy the property, but there will
550
+ be some missing.
551
+
552
+ - ``'vertices'`` -- augments by adding a vertex and
553
+ edges incident to that vertex. In this case, all graphs *up to*
554
+ ``n=vertices`` are generated. If for any graph G satisfying the
555
+ property, every subgraph, obtained from G by deleting one vertex
556
+ and only edges incident to that vertex, satisfies the property,
557
+ then this will generate all graphs with that property. If this does
558
+ not hold, then all the graphs generated will satisfy the property,
559
+ but there will be some missing.
560
+
561
+ - ``size`` -- (default: ``None``) the size of the graph to be generated
562
+
563
+ - ``degree_sequence`` -- (default: ``None``) a sequence of nonnegative integers,
564
+ or ``None``. If specified, the generated graphs will have these
565
+ integers for degrees. In this case, property and size are both
566
+ ignored.
567
+
568
+ - ``loops`` -- boolean (default: ``False``); whether to allow loops in the graph
569
+ or not
570
+
571
+ - ``sparse`` -- (default: ``True``) whether to use a sparse or dense data
572
+ structure. See the documentation of :class:`~sage.graphs.graph.Graph`.
573
+
574
+ - ``copy`` -- boolean (default: ``True``); whether to return copies. If set
575
+ to ``False`` the method returns the graph it is working on. The second
576
+ alternative is faster, but modifying any of the graph instances returned
577
+ by the method may break the function's behaviour, as it is using these
578
+ graphs to compute the next ones: only use ``copy=False`` when you stick
579
+ to *reading* the graphs returned.
580
+
581
+ This parameter is ignored when ``immutable`` is set to ``True``, in which
582
+ case returned graphs are always copies.
583
+
584
+ - ``immutable`` -- boolean (default: ``False``); whether to return immutable
585
+ or mutable graphs. When set to ``True``, this parameter implies
586
+ ``copy=True``.
587
+
588
+ EXAMPLES:
589
+
590
+ Print graphs on 3 or less vertices::
591
+
592
+ sage: for G in graphs(3, augment='vertices'):
593
+ ....: print(G)
594
+ Graph on 0 vertices
595
+ Graph on 1 vertex
596
+ Graph on 2 vertices
597
+ Graph on 3 vertices
598
+ Graph on 3 vertices
599
+ Graph on 3 vertices
600
+ Graph on 2 vertices
601
+ Graph on 3 vertices
602
+
603
+ Print graphs on 3 vertices.
604
+
605
+ ::
606
+
607
+ sage: # needs nauty
608
+ sage: for G in graphs(3):
609
+ ....: print(G)
610
+ Graph on 3 vertices
611
+ Graph on 3 vertices
612
+ Graph on 3 vertices
613
+ Graph on 3 vertices
614
+
615
+ Generate all graphs with 5 vertices and 4 edges.
616
+
617
+ ::
618
+
619
+ sage: # needs nauty
620
+ sage: L = graphs(5, size=4)
621
+ sage: len(list(L))
622
+ 6
623
+
624
+ Generate all graphs with 5 vertices and up to 4 edges.
625
+
626
+ ::
627
+
628
+ sage: # needs nauty
629
+ sage: L = list(graphs(5, lambda G: G.size() <= 4))
630
+ sage: len(L)
631
+ 14
632
+ sage: graphs_list.show_graphs(L) # long time # needs sage.plot
633
+
634
+ Generate all graphs with up to 5 vertices and up to 4 edges.
635
+
636
+ ::
637
+
638
+ sage: # needs nauty
639
+ sage: L = list(graphs(5, lambda G: G.size() <= 4, augment='vertices'))
640
+ sage: len(L)
641
+ 31
642
+ sage: graphs_list.show_graphs(L) # long time # needs sage.plot
643
+
644
+ Generate all graphs with degree at most 2, up to 6 vertices.
645
+
646
+ ::
647
+
648
+ sage: # needs nauty
649
+ sage: property = lambda G: ( max([G.degree(v) for v in G] + [0]) <= 2 )
650
+ sage: L = list(graphs(6, property, augment='vertices'))
651
+ sage: len(L)
652
+ 45
653
+
654
+ Generate all bipartite graphs on up to 7 vertices: (see
655
+ :oeis:`A033995`)
656
+
657
+ ::
658
+
659
+ sage: # needs nauty
660
+ sage: L = list( graphs(7, lambda G: G.is_bipartite(), augment='vertices') )
661
+ sage: [len([g for g in L if g.order() == i]) for i in [1..7]]
662
+ [1, 2, 3, 7, 13, 35, 88]
663
+
664
+ Generate all bipartite graphs on exactly 7 vertices::
665
+
666
+ sage: # needs nauty
667
+ sage: L = list( graphs(7, lambda G: G.is_bipartite()) )
668
+ sage: len(L)
669
+ 88
670
+
671
+ Generate all bipartite graphs on exactly 8 vertices::
672
+
673
+ sage: # needs nauty
674
+ sage: L = list( graphs(8, lambda G: G.is_bipartite()) ) # long time
675
+ sage: len(L) # long time
676
+ 303
677
+
678
+ Remember that the property argument does not behave as a filter,
679
+ except for appropriately inheritable properties::
680
+
681
+ sage: # needs nauty
682
+ sage: property = lambda G: G.is_vertex_transitive()
683
+ sage: len(list(graphs(4, property))) # needs sage.groups
684
+ 1
685
+ sage: sum(1 for g in graphs(4) if property(g)) # needs sage.groups
686
+ 4
687
+
688
+ sage: # needs nauty
689
+ sage: property = lambda G: G.is_bipartite()
690
+ sage: len(list(graphs(4, property)))
691
+ 7
692
+ sage: sum(1 for g in graphs(4) if property(g))
693
+ 7
694
+
695
+ Generate graphs on the fly: (see :oeis:`A000088`)
696
+
697
+ ::
698
+
699
+ sage: # needs nauty
700
+ sage: for i in range(7):
701
+ ....: print(len(list(graphs(i))))
702
+ 1
703
+ 1
704
+ 2
705
+ 4
706
+ 11
707
+ 34
708
+ 156
709
+
710
+ Generate all simple graphs, allowing loops: (see :oeis:`A000666`)
711
+
712
+ ::
713
+
714
+ sage: L = list(graphs(5,augment='vertices',loops=True)) # long time
715
+ sage: for i in [0..5]: # long time
716
+ ....: print((i, len([g for g in L if g.order() == i])))
717
+ (0, 1)
718
+ (1, 2)
719
+ (2, 6)
720
+ (3, 20)
721
+ (4, 90)
722
+ (5, 544)
723
+
724
+ Generate all graphs with a specified degree sequence (see :oeis:`A002851`)::
725
+
726
+ sage: # needs nauty
727
+ sage: for i in [4,6,8]: # long time (4s on sage.math, 2012)
728
+ ....: print((i, len([g for g in graphs(i, degree_sequence=[3]*i) if g.is_connected()])))
729
+ (4, 1)
730
+ (6, 2)
731
+ (8, 5)
732
+ sage: for i in [4,6,8]: # long time (7s on sage.math, 2012)
733
+ ....: print((i, len([g for g in graphs(i, augment='vertices', degree_sequence=[3]*i) if g.is_connected()])))
734
+ (4, 1)
735
+ (6, 2)
736
+ (8, 5)
737
+
738
+ ::
739
+
740
+ sage: # needs nauty
741
+ sage: print((10, len([g for g in graphs(10,degree_sequence=[3]*10) if g.is_connected()]))) # not tested
742
+ (10, 19)
743
+
744
+ Make sure that the graphs are really independent and the generator
745
+ survives repeated vertex removal (:issue:`8458`)::
746
+
747
+ sage: # needs nauty
748
+ sage: for G in graphs(3):
749
+ ....: G.delete_vertex(0)
750
+ ....: print(G.order())
751
+ 2
752
+ 2
753
+ 2
754
+ 2
755
+
756
+ Returned graphs can be mutable or immutable::
757
+
758
+ sage: # needs nauty
759
+ sage: G = next(graphs(3, immutable=False))
760
+ sage: G.delete_vertex(0)
761
+ sage: G = next(graphs(3, immutable=True))
762
+ sage: G.delete_vertex(0)
763
+ Traceback (most recent call last):
764
+ ...
765
+ ValueError: graph is immutable; please change a copy instead (use function copy())
766
+ sage: G = next(graphs(4, degree_sequence=[3]*4))
767
+ sage: G.delete_vertex(0)
768
+ sage: G = next(graphs(4, degree_sequence=[3]*4, immutable=True))
769
+ sage: G.delete_vertex(0)
770
+ Traceback (most recent call last):
771
+ ...
772
+ ValueError: graph is immutable; please change a copy instead (use function copy())
773
+
774
+ REFERENCE:
775
+
776
+ - Brendan D. McKay, Isomorph-Free Exhaustive generation. *Journal
777
+ of Algorithms*, Volume 26, Issue 2, February 1998, pages 306-324.
778
+ """
779
+
780
+ ###########################################################################
781
+ # Graph Iterators
782
+ ###########################################################################
783
+
784
+ def __call__(self, vertices=None, property=None, augment='edges', size=None,
785
+ degree_sequence=None, loops=False, sparse=True, copy=True,
786
+ immutable=False):
787
+ """
788
+ Access the generator of isomorphism class representatives.
789
+ Iterates over distinct, exhaustive representatives. See the docstring
790
+ of this class for full documentation.
791
+
792
+ EXAMPLES:
793
+
794
+ Print graphs on 3 or less vertices::
795
+
796
+ sage: # needs nauty
797
+ sage: for G in graphs(3, augment='vertices'):
798
+ ....: print(G)
799
+ Graph on 0 vertices
800
+ Graph on 1 vertex
801
+ Graph on 2 vertices
802
+ Graph on 3 vertices
803
+ Graph on 3 vertices
804
+ Graph on 3 vertices
805
+ Graph on 2 vertices
806
+ Graph on 3 vertices
807
+
808
+ ::
809
+
810
+ sage: # needs nauty
811
+ sage: for g in graphs():
812
+ ....: if g.num_verts() > 3: break
813
+ ....: print(g)
814
+ Graph on 0 vertices
815
+ Graph on 1 vertex
816
+ Graph on 2 vertices
817
+ Graph on 2 vertices
818
+ Graph on 3 vertices
819
+ Graph on 3 vertices
820
+ Graph on 3 vertices
821
+ Graph on 3 vertices
822
+
823
+ For more examples, see the class level documentation, or type::
824
+
825
+ sage: graphs? # not tested
826
+
827
+ REFERENCE:
828
+
829
+ - Brendan D. McKay, Isomorph-Free Exhaustive generation.
830
+ Journal of Algorithms Volume 26, Issue 2, February 1998,
831
+ pages 306-324.
832
+ """
833
+ # Use nauty for the basic case, as it is much faster.
834
+ if (vertices and property is None and size is None and
835
+ degree_sequence is None and not loops and augment == 'edges' and
836
+ sparse and (copy or immutable)):
837
+ yield from graphs.nauty_geng(vertices, immutable=immutable)
838
+ return
839
+
840
+ if property is None:
841
+ def property(x):
842
+ return True
843
+
844
+ if degree_sequence is not None:
845
+ if vertices is None:
846
+ raise NotImplementedError
847
+ if (len(degree_sequence) != vertices or sum(degree_sequence) % 2
848
+ or sum(degree_sequence) > vertices*(vertices - 1)):
849
+ raise ValueError("Invalid degree sequence.")
850
+ degree_sequence = sorted(degree_sequence)
851
+ if augment == 'edges':
852
+ def property(x):
853
+ D = sorted(x.degree())
854
+ return all(degree_sequence[i] >= d for i, d in enumerate(D))
855
+
856
+ def extra_property(x):
857
+ return degree_sequence == sorted(x.degree())
858
+ else:
859
+ def property(x):
860
+ D = sorted(x.degree() + [0] * (vertices - x.num_verts()))
861
+ return all(degree_sequence[i] >= d for i, d in enumerate(D))
862
+
863
+ def extra_property(x):
864
+ if x.num_verts() != vertices:
865
+ return False
866
+ return degree_sequence == sorted(x.degree())
867
+ elif size is not None:
868
+ def extra_property(x):
869
+ return x.size() == size
870
+ else:
871
+ def extra_property(x):
872
+ return True
873
+
874
+ if augment == 'vertices':
875
+ if vertices is None:
876
+ raise NotImplementedError
877
+ g = graph.Graph(loops=loops, sparse=sparse)
878
+ for gg in canaug_traverse_vert(g, [], vertices, property, loops=loops, sparse=sparse):
879
+ if extra_property(gg):
880
+ yield gg.copy(immutable=immutable) if copy or immutable else gg
881
+ elif augment == 'edges':
882
+ if vertices is None:
883
+ from sage.rings.integer import Integer
884
+ vertices = Integer(0)
885
+ while True:
886
+ for g in self(vertices, loops=loops, sparse=sparse):
887
+ yield g.copy(immutable=immutable) if copy or immutable else g
888
+ vertices += 1
889
+ g = graph.Graph(vertices, loops=loops, sparse=sparse)
890
+ gens = []
891
+ for i in range(vertices - 1):
892
+ gen = list(range(i))
893
+ gen.append(i + 1)
894
+ gen.append(i)
895
+ gen += list(range(i + 2, vertices))
896
+ gens.append(gen)
897
+ for gg in canaug_traverse_edge(g, gens, property, loops=loops, sparse=sparse):
898
+ if extra_property(gg):
899
+ yield gg.copy(immutable=immutable) if copy or immutable else gg
900
+ else:
901
+ raise NotImplementedError
902
+
903
+ def nauty_geng(self, options='', debug=False, immutable=False):
904
+ r"""
905
+ Return a generator which creates graphs from nauty's geng program.
906
+
907
+ INPUT:
908
+
909
+ - ``options`` -- string (default: ``''``); a string passed to ``geng``
910
+ as if it was run at a system command line. At a minimum, you *must*
911
+ pass the number of vertices you desire. Sage expects the graphs to be
912
+ in nauty's "graph6" format, do not set an option to change this
913
+ default or results will be unpredictable.
914
+
915
+ - ``debug`` -- boolean (default: ``False``); if ``True`` the first line
916
+ of ``geng``'s output to standard error is captured and the first call
917
+ to the generator's ``next()`` function will return this line as a
918
+ string. A line leading with ">A" indicates a successful initiation of
919
+ the program with some information on the arguments, while a line
920
+ beginning with ">E" indicates an error with the input.
921
+
922
+ - ``immutable`` -- boolean (default: ``False``); whether to return
923
+ immutable or mutable graphs
924
+
925
+ The possible options, obtained as output of ``geng --help``::
926
+
927
+ n : the number of vertices
928
+ mine:maxe : <int>:<int> a range for the number of edges
929
+ <int>:0 means '<int> or more' except in the case 0:0
930
+ res/mod : only generate subset res out of subsets 0..mod-1
931
+
932
+ -c : only write connected graphs
933
+ -C : only write biconnected graphs
934
+ -t : only generate triangle-free graphs
935
+ -f : only generate 4-cycle-free graphs
936
+ -b : only generate bipartite graphs
937
+ (-t, -f and -b can be used in any combination)
938
+ -m : save memory at the expense of time (only makes a
939
+ difference in the absence of -b, -t, -f and n <= 28).
940
+ -d<int> : a lower bound for the minimum degree
941
+ -D<int> : a upper bound for the maximum degree
942
+ -v : display counts by number of edges
943
+ -l : canonically label output graphs
944
+
945
+ -q : suppress auxiliary output (except from -v)
946
+
947
+ Options which cause ``geng`` to use an output format different than the
948
+ graph6 format are not listed above (-u, -g, -s, -y, -h) as they will
949
+ confuse the creation of a Sage graph. The res/mod option can be useful
950
+ when using the output in a routine run several times in parallel.
951
+
952
+ OUTPUT:
953
+
954
+ A generator which will produce the graphs as Sage graphs.
955
+ These will be simple graphs: no loops, no multiple edges, no
956
+ directed edges.
957
+
958
+ .. SEEALSO::
959
+
960
+ :meth:`Graph.is_strongly_regular` -- tests whether a graph is
961
+ strongly regular and/or returns its parameters.
962
+
963
+ EXAMPLES:
964
+
965
+ The generator can be used to construct graphs for testing,
966
+ one at a time (usually inside a loop). Or it can be used to
967
+ create an entire list all at once if there is sufficient memory
968
+ to contain it. ::
969
+
970
+ sage: # needs nauty
971
+ sage: gen = graphs.nauty_geng("2")
972
+ sage: next(gen)
973
+ Graph on 2 vertices
974
+ sage: next(gen)
975
+ Graph on 2 vertices
976
+ sage: next(gen)
977
+ Traceback (most recent call last):
978
+ ...
979
+ StopIteration
980
+
981
+ A list of all graphs on 7 vertices. This agrees with
982
+ :oeis:`A000088`. ::
983
+
984
+ sage: # needs nauty
985
+ sage: gen = graphs.nauty_geng("7")
986
+ sage: len(list(gen))
987
+ 1044
988
+
989
+ A list of just the connected graphs on 7 vertices. This agrees with
990
+ :oeis:`A001349`. ::
991
+
992
+ sage: # needs nauty
993
+ sage: gen = graphs.nauty_geng("7 -c")
994
+ sage: len(list(gen))
995
+ 853
996
+
997
+ A list of connected degree exactly 2 graphs on 5 vertices. ::
998
+
999
+ sage: # needs nauty
1000
+ sage: gen = graphs.nauty_geng("5 -c -d2 -D2")
1001
+ sage: len(list(gen))
1002
+ 1
1003
+
1004
+ The ``debug`` switch can be used to examine ``geng``'s reaction to the
1005
+ input in the ``options`` string. We illustrate success. (A failure
1006
+ will be a string beginning with ">E".) Passing the "-q" switch to
1007
+ ``geng`` will suppress the indicator of a successful initiation, and so
1008
+ the first returned value might be an empty string if ``debug`` is
1009
+ ``True``::
1010
+
1011
+ sage: # needs nauty
1012
+ sage: gen = graphs.nauty_geng("4", debug=True)
1013
+ sage: print(next(gen))
1014
+ >A ...geng -d0D3 n=4 e=0-6
1015
+ sage: gen = graphs.nauty_geng("4 -q", debug=True)
1016
+ sage: next(gen)
1017
+ ''
1018
+
1019
+ TESTS:
1020
+
1021
+ Wrong input, ``"-c3"`` instead of ``"-c 3"`` (:issue:`14068`)::
1022
+
1023
+ sage: # needs nauty
1024
+ sage: list(graphs.nauty_geng("-c3", debug=False))
1025
+ Traceback (most recent call last):
1026
+ ...
1027
+ ValueError: wrong format of parameter option
1028
+ sage: list(graphs.nauty_geng("-c3", debug=True))
1029
+ ['>E Usage: ...geng ...\n']
1030
+ sage: list(graphs.nauty_geng("-c 3", debug=True))
1031
+ ['>A ...geng -cd1D2 n=3 e=2-3\n', Graph on 3 vertices, Graph on 3 vertices]
1032
+ """
1033
+ import shlex
1034
+ from sage.features.nauty import NautyExecutable
1035
+ geng_path = NautyExecutable("geng").absolute_filename()
1036
+ sp = subprocess.Popen(shlex.quote(geng_path) + " {0}".format(options), shell=True,
1037
+ stdin=subprocess.PIPE, stdout=subprocess.PIPE,
1038
+ stderr=subprocess.PIPE, close_fds=True,
1039
+ encoding='latin-1')
1040
+ msg = sp.stderr.readline()
1041
+ if debug:
1042
+ yield msg
1043
+ elif msg.startswith('>E'):
1044
+ raise ValueError('wrong format of parameter option')
1045
+ gen = sp.stdout
1046
+ while True:
1047
+ try:
1048
+ s = next(gen)
1049
+ except StopIteration:
1050
+ # Exhausted list of graphs from nauty geng
1051
+ return
1052
+ yield graph.Graph(s[:-1], format='graph6', immutable=immutable)
1053
+
1054
+ def nauty_genbg(self, options='', debug=False, immutable=False):
1055
+ r"""
1056
+ Return a generator which creates bipartite graphs from nauty's ``genbgL``
1057
+ program.
1058
+
1059
+ INPUT:
1060
+
1061
+ - ``options`` -- string (default: ``""``); a string passed to ``genbgL``
1062
+ as if it was run at a system command line. At a minimum, you *must*
1063
+ pass the number of vertices you desire in each side. Sage expects the
1064
+ bipartite graphs to be in nauty's "graph6" format, do not set an
1065
+ option to change this default or results will be unpredictable.
1066
+
1067
+ - ``debug`` -- boolean (default: ``False``); if ``True`` the first line
1068
+ of ``geng``'s output to standard error is captured and the first call
1069
+ to the generator's ``next()`` function will return this line as a
1070
+ string. A line leading with ">A" indicates a successful initiation of
1071
+ the program with some information on the arguments, while a line
1072
+ beginning with ">E" indicates an error with the input.
1073
+
1074
+ - ``immutable`` -- boolean (default: ``False``); whether to return
1075
+ immutable or mutable graphs
1076
+
1077
+ The possible options, obtained as output of ``genbgL --help``::
1078
+
1079
+ n1 : the number of vertices in the first class.
1080
+ We must have n1=1..30.
1081
+ n2 : the number of vertices in the second class.
1082
+ We must have n2=0..64 and n1+n2=1..64.
1083
+ mine:maxe : <int>:<int> a range for the number of edges
1084
+ <int>:0 means '<int> or more' except in the case 0:0
1085
+ res/mod : only generate subset res out of subsets 0..mod-1
1086
+ -c : only write connected graphs
1087
+ -z : all the vertices in the second class must have
1088
+ different neighbourhoods
1089
+ -F : the vertices in the second class must have at least
1090
+ two neighbours of degree at least 2
1091
+ -L : there is no vertex in the first class whose removal
1092
+ leaves the vertices in the second class unreachable
1093
+ from each other
1094
+ -Y<int> : two vertices in the second class must have at least
1095
+ <int> common neighbours
1096
+ -Z<int> : two vertices in the second class must have at most
1097
+ <int> common neighbours
1098
+ -A : no vertex in the second class has a neighbourhood
1099
+ which is a subset of another vertex's neighbourhood
1100
+ in the second class
1101
+ -D<int> : specify an upper bound for the maximum degree
1102
+ Example: -D6. You can also give separate maxima for
1103
+ the two parts, for example: -D5:6
1104
+ -d<int> : specify a lower bound for the minimum degree
1105
+ Again, you can specify it separately for the two parts,
1106
+ for example -d1:2
1107
+ -v : display counts by number of edges to stderr
1108
+ -l : canonically label output graphs
1109
+
1110
+ Options which cause ``genbgL`` to use an output format different than
1111
+ the ``graph6`` format are not listed above (``-s``, ``-a``) as they will
1112
+ confuse the creation of a Sage graph. Option ``-q`` which suppress
1113
+ auxiliary output (except from ``-v``) should never be used as we are
1114
+ unable to recover the partition of the vertices of the bipartite graph
1115
+ without the auxiliary output. Hence the partition of the vertices of
1116
+ returned bipartite graphs might not respect the requirement.
1117
+
1118
+ The res/mod option can be useful when using the output in a routine run
1119
+ several times in parallel.
1120
+
1121
+ OUTPUT:
1122
+
1123
+ A generator which will produce the graphs as
1124
+ :class:`~sage/graphs.bipartite_graph.BipartiteGraph`. These will be
1125
+ simple bipartite graphs: no loops, no multiple edges, no directed edges.
1126
+
1127
+ EXAMPLES:
1128
+
1129
+ The generator can be used to construct biparrtite graphs for testing,
1130
+ one at a time (usually inside a loop). Or it can be used to
1131
+ create an entire list all at once if there is sufficient memory
1132
+ to contain it::
1133
+
1134
+ sage: # needs nauty
1135
+ sage: gen = graphs.nauty_genbg("1 1")
1136
+ sage: next(gen)
1137
+ Bipartite graph on 2 vertices
1138
+ sage: next(gen)
1139
+ Bipartite graph on 2 vertices
1140
+ sage: next(gen)
1141
+ Traceback (most recent call last):
1142
+ ...
1143
+ StopIteration
1144
+
1145
+ Connected bipartite graphs of order 6 with different number of vertices
1146
+ in each side::
1147
+
1148
+ sage: # needs nauty
1149
+ sage: gen = graphs.nauty_genbg("1 5 -c")
1150
+ sage: len(list(gen))
1151
+ 1
1152
+ sage: gen = graphs.nauty_genbg("2 4 -c")
1153
+ sage: len(list(gen))
1154
+ 6
1155
+ sage: gen = graphs.nauty_genbg("3 3 -c")
1156
+ sage: len(list(gen))
1157
+ 13
1158
+
1159
+ Use :meth:`nauty_geng` instead if you want the list of all bipartite
1160
+ graphs of order `n`. For instance, the list of all connected bipartite
1161
+ graphs of order 6, which agrees with :oeis:`A005142`::
1162
+
1163
+ sage: # needs nauty
1164
+ sage: gen = graphs.nauty_geng("-b -c 6")
1165
+ sage: len(list(gen))
1166
+ 17
1167
+
1168
+ The ``debug`` switch can be used to examine ``genbgL``'s reaction to the
1169
+ input in the ``options`` string. A message starting with ">A" indicates
1170
+ success and a message starting with ">E" indicates a failure::
1171
+
1172
+ sage: # needs nauty
1173
+ sage: gen = graphs.nauty_genbg("2 3", debug=True)
1174
+ sage: print(next(gen))
1175
+ >A ...genbg... n=2+3 e=0:6 d=0:0 D=3:2
1176
+ sage: gen = graphs.nauty_genbg("-c2 3", debug=True)
1177
+ sage: next(gen)
1178
+ '>E Usage: ...genbg... [-c -ugs -vq -lzF] [-Z#] [-D#] [-A] [-d#|-d#:#] [-D#|-D#:#] n1 n2...
1179
+
1180
+ Check that the partition of the bipartite graph is consistent::
1181
+
1182
+ sage: # needs nauty
1183
+ sage: gen = graphs.nauty_genbg("3 3")
1184
+ sage: left = set(range(3))
1185
+ sage: for g in gen:
1186
+ ....: if g.left != left:
1187
+ ....: raise ValueError('wrong partition')
1188
+
1189
+ TESTS:
1190
+
1191
+ Wrong input::
1192
+
1193
+ sage: # needs nauty
1194
+ sage: list(graphs.nauty_genbg("-c1 2", debug=False))
1195
+ Traceback (most recent call last):
1196
+ ...
1197
+ ValueError: wrong format of parameter options
1198
+ sage: list(graphs.nauty_genbg("-c1 2", debug=True))
1199
+ ['>E Usage: ...genbg... [-c -ugs -vq -lzF] [-Z#] [-D#] [-A] [-d#|-d#:#] [-D#|-D#:#] n1 n2...
1200
+ sage: list(graphs.nauty_genbg("-c 1 2", debug=True))
1201
+ ['>A ...genbg... n=1+2 e=2:2 d=1:1 D=2:1 c...\n', Bipartite graph on 3 vertices]
1202
+
1203
+ We must have n1=1..30, n2=0..64 and n1+n2=1..64 (:issue:`34179`,
1204
+ :issue:`38618`)::
1205
+
1206
+ sage: # needs nauty
1207
+ sage: next(graphs.nauty_genbg("31 1", debug=False))
1208
+ Traceback (most recent call last):
1209
+ ...
1210
+ ValueError: wrong format of parameter options
1211
+ sage: next(graphs.nauty_genbg("31 1", debug=True))
1212
+ '>E ...genbg...: must have n1=1..30, n1+n2=1..64...
1213
+ sage: next(graphs.nauty_genbg("30 40", debug=True))
1214
+ '>E ...genbg...: must have n1=1..30, n1+n2=1..64...
1215
+ sage: next(graphs.nauty_genbg("1 63", debug=False))
1216
+ Bipartite graph on 64 vertices
1217
+ sage: next(graphs.nauty_genbg("1 64", debug=True))
1218
+ '>E ...genbg...: must have n1=1..30, n1+n2=1..64...
1219
+ sage: next(graphs.nauty_genbg("0 2", debug=True))
1220
+ '>E ...genbg...: must have n1=1..30, n1+n2=1..64...
1221
+ sage: next(graphs.nauty_genbg("2 0", debug=False))
1222
+ Bipartite graph on 2 vertices
1223
+ sage: next(graphs.nauty_genbg("2 -1", debug=True))
1224
+ '>E Usage: ...genbg... [-c -ugs -vq -lzF] [-Z#] [-D#] [-A] [-d#|-d#:#] [-D#|-D#:#] n1 n2...
1225
+ """
1226
+ import shlex
1227
+ from sage.features.nauty import NautyExecutable
1228
+ genbg_path = NautyExecutable("genbgL").absolute_filename()
1229
+ sp = subprocess.Popen(shlex.quote(genbg_path) + " {0}".format(options), shell=True,
1230
+ stdin=subprocess.PIPE, stdout=subprocess.PIPE,
1231
+ stderr=subprocess.PIPE, close_fds=True,
1232
+ encoding='latin-1')
1233
+ msg = sp.stderr.readline()
1234
+ if debug:
1235
+ yield msg
1236
+ elif msg.startswith('>E'):
1237
+ raise ValueError('wrong format of parameter options')
1238
+
1239
+ if msg.startswith('>A'):
1240
+ # We extract the partition of the vertices from the msg string
1241
+ for s in msg.split(' '):
1242
+ if s.startswith('n='):
1243
+ from sage.rings.integer import Integer
1244
+ n1, n2 = (Integer(t) for t in s[2:].split('+') if t.isdigit())
1245
+ partition = [set(range(n1)), set(range(n1, n1 + n2))]
1246
+ break
1247
+ else:
1248
+ # should never happen
1249
+ raise ValueError('unable to recover the partition')
1250
+ else:
1251
+ # Either msg starts with >E or option -q has been given
1252
+ partition = None
1253
+
1254
+ gen = sp.stdout
1255
+ from sage.graphs.bipartite_graph import BipartiteGraph
1256
+ while True:
1257
+ try:
1258
+ s = next(gen)
1259
+ except StopIteration:
1260
+ # Exhausted list of bipartite graphs from nauty genbgL
1261
+ return
1262
+ yield BipartiteGraph(s[:-1], format='graph6', partition=partition,
1263
+ immutable=immutable)
1264
+
1265
+ def nauty_genktreeg(self, options='', debug=False, immutable=False):
1266
+ r"""
1267
+ Return a generator which creates all `k`-trees using nauty..
1268
+
1269
+ A `k`-tree is an undirected graph formed by starting with a complete
1270
+ graph on `k + 1` vertices and then repeatedly add vertices in such a
1271
+ way that each added vertex `v` has exactly `k` neighbors `U` such that,
1272
+ together, the `k + 1` vertices formed by `v` and `U` form a clique.
1273
+ See the :wikipedia:`K-tree` for more details.
1274
+
1275
+ INPUT:
1276
+
1277
+ - ``options`` -- string (default: ``""``); a string passed to
1278
+ ``genktreeg`` as if it was run at a system command line. At a minimum,
1279
+ you *must* pass the number of vertices you desire. Sage expects the
1280
+ graphs to be in nauty's "graph6" format, do not set an option to
1281
+ change this default or results will be unpredictable.
1282
+
1283
+ - ``debug`` -- boolean (default: ``False``); if ``True`` the first line
1284
+ of ``genktreeg``'s output to standard error is captured and the first
1285
+ call to the generator's ``next()`` function will return this line as a
1286
+ string. A line leading with ">A" indicates a successful initiation of
1287
+ the program with some information on the arguments, while a line
1288
+ beginning with ">E" indicates an error with the input.
1289
+
1290
+ - ``immutable`` -- boolean (default: ``False``); whether to return
1291
+ immutable or mutable graphs
1292
+
1293
+ The possible options, obtained as output of ``genktreeg --help``::
1294
+
1295
+ n : the number of vertices
1296
+ -k<int> : the value of `k`(default: 2)
1297
+ res/mod : only generate subset res out of subsets 0..mod-1
1298
+ -l : canonically label output graphs
1299
+
1300
+ Options which cause ``genktreeg`` to use an output format different than
1301
+ the graph6 format are not listed above (-u, -s, -h) as they will confuse
1302
+ the creation of a Sage graph. The res/mod option can be useful when
1303
+ using the output in a routine run several times in parallel.
1304
+
1305
+ OUTPUT:
1306
+
1307
+ A generator which will produce the graphs as Sage graphs.
1308
+ These will be simple graphs: no loops, no multiple edges, no
1309
+ directed edges.
1310
+
1311
+ EXAMPLES:
1312
+
1313
+ A `k`-tree is a maximal graph with treewidth `k`::
1314
+
1315
+ sage: # needs nauty
1316
+ sage: gen = graphs.nauty_genktreeg("10 -k4")
1317
+ sage: G = next(gen); G
1318
+ Graph on 10 vertices
1319
+ sage: G.treewidth() # needs cliquer
1320
+ 4
1321
+
1322
+ A list of all 2-trees with 6, 7 and 8 vertices. This agrees with
1323
+ :oeis:`A054581`::
1324
+
1325
+ sage: # needs nauty
1326
+ sage: gen = graphs.nauty_genktreeg("6")
1327
+ sage: len(list(gen))
1328
+ 5
1329
+ sage: gen = graphs.nauty_genktreeg("7")
1330
+ sage: len(list(gen))
1331
+ 12
1332
+ sage: gen = graphs.nauty_genktreeg("8")
1333
+ sage: len(list(gen))
1334
+ 39
1335
+
1336
+ The ``debug`` switch can be used to examine ``geng``'s reaction to the
1337
+ input in the ``options`` string. We illustrate success. (A failure
1338
+ will be a string beginning with ">E".) Passing the "-q" switch to
1339
+ ``geng`` will suppress the indicator of a successful initiation, and so
1340
+ the first returned value might be an empty string if ``debug`` is
1341
+ ``True``::
1342
+
1343
+ sage: gen = graphs.nauty_genktreeg("7", debug=True) # needs nauty
1344
+ sage: print(next(gen)) # needs nauty
1345
+ >A ...genktreeg k=2 n=7
1346
+
1347
+ TESTS:
1348
+
1349
+ Wrong input::
1350
+
1351
+ sage: # needs nauty
1352
+ sage: list(graphs.nauty_genktreeg("4 -k5", debug=True))
1353
+ ['>E genktreeg: n cannot be less than k\n']
1354
+ sage: list(graphs.nauty_genktreeg("10 -k 4", debug=True))
1355
+ ['>E genktreeg -k: missing argument value\n']
1356
+ sage: list(graphs.nauty_genktreeg("-c3", debug=False))
1357
+ Traceback (most recent call last):
1358
+ ...
1359
+ ValueError: wrong format of parameter option
1360
+ """
1361
+ import shlex
1362
+ from sage.features.nauty import NautyExecutable
1363
+ geng_path = NautyExecutable("genktreeg").absolute_filename()
1364
+ sp = subprocess.Popen(shlex.quote(geng_path) + " {0}".format(options), shell=True,
1365
+ stdin=subprocess.PIPE, stdout=subprocess.PIPE,
1366
+ stderr=subprocess.PIPE, close_fds=True,
1367
+ encoding='latin-1')
1368
+ msg = sp.stderr.readline()
1369
+ if debug:
1370
+ yield msg
1371
+ elif msg.startswith('>E'):
1372
+ raise ValueError('wrong format of parameter option')
1373
+ gen = sp.stdout
1374
+ while True:
1375
+ try:
1376
+ s = next(gen)
1377
+ except StopIteration:
1378
+ # Exhausted list of graphs from nauty geng
1379
+ return
1380
+ yield graph.Graph(s[:-1], format='graph6', immutable=immutable)
1381
+
1382
+ def cospectral_graphs(self, vertices, matrix_function=None, graphs=None,
1383
+ immutable=False):
1384
+ r"""
1385
+ Find all sets of graphs on ``vertices`` vertices (with
1386
+ possible restrictions) which are cospectral with respect to a
1387
+ constructed matrix.
1388
+
1389
+ INPUT:
1390
+
1391
+ - ``vertices`` -- the number of vertices in the graphs to be tested
1392
+
1393
+ - ``matrix_function`` -- a function taking a graph and giving back
1394
+ a matrix. This defaults to the adjacency matrix. The spectra
1395
+ examined are the spectra of these matrices.
1396
+
1397
+ - ``graphs`` -- one of three things:
1398
+
1399
+ - ``None`` -- default; test all graphs having ``vertices``
1400
+ vertices
1401
+
1402
+ - a function taking a graph and returning ``True`` or ``False``
1403
+ - test only the graphs on ``vertices`` vertices for which
1404
+ the function returns ``True``
1405
+
1406
+ - a list of graphs (or other iterable object) -- these graphs
1407
+ are tested for cospectral sets. In this case,
1408
+ ``vertices`` is ignored.
1409
+
1410
+ - ``immutable`` -- boolean (default: ``False``); whether to return
1411
+ immutable or mutable graphs
1412
+
1413
+ OUTPUT:
1414
+
1415
+ A list of lists of graphs. Each sublist will be a list of
1416
+ cospectral graphs (lists of cardinality 1 being omitted).
1417
+
1418
+ .. SEEALSO::
1419
+
1420
+ :meth:`Graph.is_strongly_regular` -- tests whether a graph is
1421
+ strongly regular and/or returns its parameters.
1422
+
1423
+ EXAMPLES::
1424
+
1425
+ sage: g = graphs.cospectral_graphs(5) # needs sage.modules
1426
+ sage: sorted(sorted(g.graph6_string() for g in glist) for glist in g) # needs sage.modules
1427
+ [['Dr?', 'Ds_']]
1428
+ sage: g[0][1].am().charpoly()==g[0][1].am().charpoly() # needs sage.modules
1429
+ True
1430
+
1431
+ There are two sets of cospectral graphs on six vertices with no isolated vertices::
1432
+
1433
+ sage: # needs sage.modules
1434
+ sage: g = graphs.cospectral_graphs(6, graphs=lambda x: min(x.degree())>0)
1435
+ sage: sorted(sorted(g.graph6_string() for g in glist) for glist in g)
1436
+ [['Ep__', 'Er?G'], ['ExGg', 'ExoG']]
1437
+ sage: g[0][1].am().charpoly()==g[0][1].am().charpoly()
1438
+ True
1439
+ sage: g[1][1].am().charpoly()==g[1][1].am().charpoly()
1440
+ True
1441
+
1442
+ There is one pair of cospectral trees on eight vertices::
1443
+
1444
+ sage: g = graphs.cospectral_graphs(6, graphs=graphs.trees(8)) # needs sage.modules
1445
+ sage: sorted(sorted(g.graph6_string() for g in glist) for glist in g) # needs sage.modules
1446
+ [['GiPC?C', 'GiQCC?']]
1447
+ sage: g[0][1].am().charpoly()==g[0][1].am().charpoly() # needs sage.modules
1448
+ True
1449
+
1450
+ There are two sets of cospectral graphs (with respect to the
1451
+ Laplacian matrix) on six vertices::
1452
+
1453
+ sage: # needs sage.modules
1454
+ sage: g = graphs.cospectral_graphs(6, matrix_function=lambda g: g.laplacian_matrix())
1455
+ sage: sorted(sorted(g.graph6_string() for g in glist) for glist in g)
1456
+ [['Edq_', 'ErcG'], ['Exoo', 'EzcG']]
1457
+ sage: g[0][1].laplacian_matrix().charpoly()==g[0][1].laplacian_matrix().charpoly()
1458
+ True
1459
+ sage: g[1][1].laplacian_matrix().charpoly()==g[1][1].laplacian_matrix().charpoly()
1460
+ True
1461
+
1462
+ To find cospectral graphs with respect to the normalized
1463
+ Laplacian, assuming the graphs do not have an isolated vertex, it
1464
+ is enough to check the spectrum of the matrix `D^{-1}A`, where `D`
1465
+ is the diagonal matrix of vertex degrees, and A is the adjacency
1466
+ matrix. We find two such cospectral graphs (for the normalized
1467
+ Laplacian) on five vertices::
1468
+
1469
+ sage: def DinverseA(g):
1470
+ ....: A = g.adjacency_matrix().change_ring(QQ)
1471
+ ....: for i in range(g.order()):
1472
+ ....: A.rescale_row(i, 1 / len(A.nonzero_positions_in_row(i)))
1473
+ ....: return A
1474
+ sage: g = graphs.cospectral_graphs(5, matrix_function=DinverseA, # needs sage.libs.pari sage.modules
1475
+ ....: graphs=lambda g: min(g.degree()) > 0)
1476
+ sage: sorted(sorted(g.graph6_string() for g in glist) for glist in g) # needs sage.modules
1477
+ [['Dlg', 'Ds_']]
1478
+ sage: (g[0][1].laplacian_matrix(normalized=True).charpoly() # needs sage.modules sage.symbolic
1479
+ ....: == g[0][1].laplacian_matrix(normalized=True).charpoly())
1480
+ True
1481
+ """
1482
+ if matrix_function is None:
1483
+ matrix_function = lambda g: g.adjacency_matrix()
1484
+
1485
+ def prop(x):
1486
+ return True
1487
+
1488
+ from sage.graphs.graph_generators import graphs as graph_gen
1489
+ if graphs is None:
1490
+ graph_list = graph_gen(vertices, property=prop, immutable=immutable)
1491
+ elif callable(graphs):
1492
+ graph_list = (g for g in graph_gen(vertices, property=prop,
1493
+ immutable=immutable) if graphs(g))
1494
+ else:
1495
+ graph_list = iter(graphs)
1496
+
1497
+ from collections import defaultdict
1498
+ charpolys = defaultdict(list)
1499
+ for g in graph_list:
1500
+ cp = matrix_function(g).charpoly()
1501
+ charpolys[cp].append(g)
1502
+
1503
+ cospectral_graphs = []
1504
+ for cp, g_list in charpolys.items():
1505
+ if len(g_list) > 1:
1506
+ cospectral_graphs.append(g_list)
1507
+
1508
+ return cospectral_graphs
1509
+
1510
+ def _read_planar_code(self, code_input, immutable=False):
1511
+ r"""
1512
+ Return a generator for the plane graphs in planar code format in
1513
+ the file code_input (see [BM2016]_).
1514
+
1515
+ A file with planar code starts with a header ``>>planar_code<<``.
1516
+ After the header each graph is stored in the following way :
1517
+
1518
+ The first character is the number of vertices, followed by
1519
+ n11,...,n1k,null character,n21,...,n2k',null character, ...
1520
+
1521
+ where the n1* are all neighbors of n1 and all n2* are the
1522
+ neighbors of n2, ...
1523
+ Besides, these neighbors are enumerated in clockwise order.
1524
+
1525
+ INPUT:
1526
+
1527
+ - ``code_input`` -- a file containing valid planar code data
1528
+
1529
+ - ``immutable`` -- boolean (default: ``False``); whether to return
1530
+ immutable or mutable graphs
1531
+
1532
+ OUTPUT:
1533
+
1534
+ A generator which will produce the plane graphs as Sage graphs
1535
+ with an embedding set. These will be simple graphs: no loops, no
1536
+ multiple edges, no directed edges (unless plantri is asked to give
1537
+ the dual graphs instead).
1538
+
1539
+ .. SEEALSO::
1540
+
1541
+ - :meth:`~sage.graphs.generic_graph.GenericGraph.set_embedding`,
1542
+ :meth:`~sage.graphs.generic_graph.GenericGraph.get_embedding` --
1543
+ get/set methods for embeddings.
1544
+
1545
+ EXAMPLES:
1546
+
1547
+ The following example creates a small planar code file in memory and
1548
+ reads it using the ``_read_planar_code`` method::
1549
+
1550
+ sage: from io import StringIO
1551
+ sage: code_input = StringIO('>>planar_code<<')
1552
+ sage: _ = code_input.write('>>planar_code<<')
1553
+ sage: for c in [4,2,3,4,0,1,4,3,0,1,2,4,0,1,3,2,0]:
1554
+ ....: _ = code_input.write('{:c}'.format(c))
1555
+ sage: _ = code_input.seek(0)
1556
+ sage: gen = graphs._read_planar_code(code_input)
1557
+ sage: l = list(gen)
1558
+ sage: l
1559
+ [Graph on 4 vertices]
1560
+ sage: l[0].is_isomorphic(graphs.CompleteGraph(4))
1561
+ True
1562
+ sage: l[0].get_embedding()
1563
+ {1: [2, 3, 4],
1564
+ 2: [1, 4, 3],
1565
+ 3: [1, 2, 4],
1566
+ 4: [1, 3, 2]}
1567
+ """
1568
+ # start of code to read planar code
1569
+ header = code_input.read(15)
1570
+ assert header == '>>planar_code<<', 'Not a valid planar code header'
1571
+
1572
+ # read graph per graph
1573
+ while True:
1574
+ c = code_input.read(1)
1575
+ if not c:
1576
+ return
1577
+
1578
+ # Each graph is stored in the following way :
1579
+ #
1580
+ # The first character is the number of vertices, followed by
1581
+ # n11,...,n1k,null character,n21,...,n2k',null character, ...
1582
+ #
1583
+ # where the n1* are all neighbors of n1 and all n2* are the
1584
+ # neighbors of n2, ...
1585
+ #
1586
+ # Besides, these neighbors are enumerated in clockwise order.
1587
+ order = ord(c)
1588
+
1589
+ zeroCount = 0
1590
+
1591
+ g = [[] for i in range(order)]
1592
+
1593
+ while zeroCount < order:
1594
+ c = code_input.read(1)
1595
+ if ord(c) == 0:
1596
+ zeroCount += 1
1597
+ else:
1598
+ g[zeroCount].append(ord(c))
1599
+
1600
+ # construct graph based on g
1601
+
1602
+ # first taking care that every edge is given twice
1603
+ edges_g = {i + 1: [j for j in di if j < i + 1]
1604
+ for i, di in enumerate(g)}
1605
+
1606
+ # then adding half of the loops (if any)
1607
+ has_loops = False
1608
+ for i, di in enumerate(g):
1609
+ Ni = di.count(i + 1)
1610
+ if Ni > 1:
1611
+ edges_g[i + 1] += [i + 1] * (Ni // 2)
1612
+ has_loops = True
1613
+ G = graph.Graph(edges_g, loops=has_loops, immutable=immutable)
1614
+
1615
+ if not (G.has_multiple_edges() or has_loops):
1616
+ embed_g = {i + 1: di for i, di in enumerate(g)}
1617
+ G.set_embedding(embed_g)
1618
+ yield G
1619
+
1620
+ def fullerenes(self, order, ipr=False, immutable=False):
1621
+ r"""
1622
+ Return a generator which creates fullerene graphs using
1623
+ the buckygen generator (see [BGM2012]_).
1624
+
1625
+ INPUT:
1626
+
1627
+ - ``order`` -- a positive even integer smaller than or equal to 254
1628
+ This specifies the number of vertices in the generated fullerenes
1629
+
1630
+ - ``ipr`` -- boolean (default: ``False``); if ``True`` only fullerenes
1631
+ that satisfy the Isolated Pentagon Rule are generated. This means that
1632
+ no pentagonal faces share an edge.
1633
+
1634
+ - ``immutable`` -- boolean (default: ``False``); whether to return
1635
+ immutable or mutable graphs
1636
+
1637
+ OUTPUT:
1638
+
1639
+ A generator which will produce the fullerene graphs as Sage graphs
1640
+ with an embedding set. These will be simple graphs: no loops, no
1641
+ multiple edges, no directed edges.
1642
+
1643
+ .. SEEALSO::
1644
+
1645
+ - :meth:`~sage.graphs.generic_graph.GenericGraph.set_embedding`,
1646
+ :meth:`~sage.graphs.generic_graph.GenericGraph.get_embedding` --
1647
+ get/set methods for embeddings.
1648
+
1649
+ EXAMPLES:
1650
+
1651
+ There are 1812 isomers of `\textrm{C}_{60}`, i.e., 1812 fullerene graphs
1652
+ on 60 vertices::
1653
+
1654
+ sage: gen = graphs.fullerenes(60) # optional - buckygen
1655
+ sage: len(list(gen)) # optional - buckygen
1656
+ 1812
1657
+
1658
+ However, there is only one IPR fullerene graph on 60 vertices: the famous
1659
+ Buckminster Fullerene::
1660
+
1661
+ sage: gen = graphs.fullerenes(60, ipr=True) # optional - buckygen
1662
+ sage: next(gen) # optional - buckygen
1663
+ Graph on 60 vertices
1664
+ sage: next(gen) # optional - buckygen
1665
+ Traceback (most recent call last):
1666
+ ...
1667
+ StopIteration
1668
+
1669
+ The unique fullerene graph on 20 vertices is isomorphic to the dodecahedron
1670
+ graph. ::
1671
+
1672
+ sage: # optional - buckygen
1673
+ sage: gen = graphs.fullerenes(20)
1674
+ sage: g = next(gen)
1675
+ sage: g.is_isomorphic(graphs.DodecahedralGraph())
1676
+ True
1677
+ sage: g.get_embedding()
1678
+ {1: [2, 3, 4],
1679
+ 2: [1, 5, 6],
1680
+ 3: [1, 7, 8],
1681
+ 4: [1, 9, 10],
1682
+ 5: [2, 10, 11],
1683
+ 6: [2, 12, 7],
1684
+ 7: [3, 6, 13],
1685
+ 8: [3, 14, 9],
1686
+ 9: [4, 8, 15],
1687
+ 10: [4, 16, 5],
1688
+ 11: [5, 17, 12],
1689
+ 12: [6, 11, 18],
1690
+ 13: [7, 18, 14],
1691
+ 14: [8, 13, 19],
1692
+ 15: [9, 19, 16],
1693
+ 16: [10, 15, 17],
1694
+ 17: [11, 16, 20],
1695
+ 18: [12, 20, 13],
1696
+ 19: [14, 20, 15],
1697
+ 20: [17, 19, 18]}
1698
+ sage: g.plot3d(layout='spring') # needs sage.plot
1699
+ Graphics3d Object
1700
+ """
1701
+ # number of vertices should be positive
1702
+ if order < 0:
1703
+ raise ValueError("number of vertices should be nonnegative")
1704
+
1705
+ # buckygen can only output fullerenes on up to 254 vertices
1706
+ if order > 254:
1707
+ raise ValueError("number of vertices should be at most 254")
1708
+
1709
+ # fullerenes only exist for an even number of vertices, larger than 20
1710
+ # and different from 22
1711
+ if order % 2 == 1 or order < 20 or order == 22:
1712
+ return
1713
+
1714
+ from sage.features.graph_generators import Buckygen
1715
+ Buckygen().require()
1716
+
1717
+ import shlex
1718
+ command = shlex.quote(Buckygen().absolute_filename())
1719
+ command += ' -' + ('I' if ipr else '') + 'd {0}d'.format(order)
1720
+
1721
+ sp = subprocess.Popen(command, shell=True,
1722
+ stdin=subprocess.PIPE, stdout=subprocess.PIPE,
1723
+ stderr=subprocess.PIPE, close_fds=True,
1724
+ encoding='latin-1')
1725
+
1726
+ sp.stdout.reconfigure(newline='')
1727
+
1728
+ yield from graphs._read_planar_code(sp.stdout, immutable=immutable)
1729
+
1730
+ def fusenes(self, hexagon_count, benzenoids=False, immutable=False):
1731
+ r"""
1732
+ Return a generator which creates fusenes and benzenoids using
1733
+ the benzene generator (see [BCH2002]_). Fusenes are planar
1734
+ polycyclic hydrocarbons with all bounded faces hexagons. Benzenoids
1735
+ are fusenes that are subgraphs of the hexagonal lattice.
1736
+
1737
+ INPUT:
1738
+
1739
+ - ``hexagon_count`` -- positive integer smaller than or equal to 30;
1740
+ this specifies the number of hexagons in the generated benzenoids
1741
+
1742
+ - ``benzenoids`` -- boolean (default: ``False``); if ``True`` only
1743
+ benzenoids are generated
1744
+
1745
+ - ``immutable`` -- boolean (default: ``False``); whether to return
1746
+ immutable or mutable graphs
1747
+
1748
+ OUTPUT:
1749
+
1750
+ A generator which will produce the fusenes as Sage graphs
1751
+ with an embedding set. These will be simple graphs: no loops, no
1752
+ multiple edges, no directed edges.
1753
+
1754
+ .. SEEALSO::
1755
+
1756
+ - :meth:`~sage.graphs.generic_graph.GenericGraph.set_embedding`,
1757
+ :meth:`~sage.graphs.generic_graph.GenericGraph.get_embedding` --
1758
+ get/set methods for embeddings.
1759
+
1760
+ EXAMPLES:
1761
+
1762
+ There is a unique fusene with 2 hexagons::
1763
+
1764
+ sage: gen = graphs.fusenes(2) # optional - benzene
1765
+ sage: len(list(gen)) # optional - benzene
1766
+ 1
1767
+
1768
+ This fusene is naphthalene (`\textrm{C}_{10}\textrm{H}_{8}`).
1769
+ In the fusene graph the H-atoms are not stored, so this is
1770
+ a graph on just 10 vertices::
1771
+
1772
+ sage: gen = graphs.fusenes(2) # optional - benzene
1773
+ sage: next(gen) # optional - benzene
1774
+ Graph on 10 vertices
1775
+ sage: next(gen) # optional - benzene
1776
+ Traceback (most recent call last):
1777
+ ...
1778
+ StopIteration
1779
+
1780
+ There are 6505 benzenoids with 9 hexagons::
1781
+
1782
+ sage: gen = graphs.fusenes(9, benzenoids=True) # optional - benzene
1783
+ sage: len(list(gen)) # optional - benzene
1784
+ 6505
1785
+ """
1786
+ if hexagon_count < 0:
1787
+ raise ValueError("number of hexagons should be nonnegative")
1788
+
1789
+ # benzene is only built for fusenes with up to 30 hexagons
1790
+ if hexagon_count > 30:
1791
+ raise ValueError("number of hexagons should be at most 30")
1792
+
1793
+ # there are no fusenes with 0 hexagons
1794
+ if hexagon_count == 0:
1795
+ return
1796
+
1797
+ # there is only one unique fusene with 1 hexagon (and benzene doesn't generate it)
1798
+ if hexagon_count == 1:
1799
+ g = {1: [6, 2], 2: [1, 3], 3: [2, 4], 4: [3, 5], 5: [4, 6], 6: [5, 1]}
1800
+ G = graph.Graph(g)
1801
+ G.set_embedding(g)
1802
+ yield G
1803
+ return
1804
+
1805
+ from sage.features.graph_generators import Benzene
1806
+ Benzene().require()
1807
+
1808
+ import shlex
1809
+ command = shlex.quote(Benzene().absolute_filename())
1810
+ command += (' b' if benzenoids else '') + ' {0} p'.format(hexagon_count)
1811
+
1812
+ sp = subprocess.Popen(command, shell=True,
1813
+ stdin=subprocess.PIPE, stdout=subprocess.PIPE,
1814
+ stderr=subprocess.PIPE, close_fds=True,
1815
+ encoding='latin-1')
1816
+
1817
+ sp.stdout.reconfigure(newline='')
1818
+
1819
+ yield from graphs._read_planar_code(sp.stdout, immutable=immutable)
1820
+
1821
+ def plantri_gen(self, options="", immutable=False):
1822
+ r"""
1823
+ Iterator over planar graphs created using the ``plantri`` generator.
1824
+
1825
+ ``plantri`` is a (optional) program that generates certain types of
1826
+ graphs that are embedded on the sphere. It outputs exactly one member of
1827
+ each isomorphism class, using an amount of memory almost independent of
1828
+ the number of graphs produced. Isomorphisms are defined with respect to
1829
+ the embeddings, so in some cases outputs may be isomorphic as abstract
1830
+ graphs.
1831
+
1832
+ This method allows for passing command directly to ``plantry``,
1833
+ similarly to method :meth:`nauty_geng`, provide that the output format
1834
+ is not changed.
1835
+
1836
+ INPUT:
1837
+
1838
+ - ``options`` -- string (default: ``""``); a string passed to
1839
+ ``plantri`` as if it was run at a system command line. At a minimum,
1840
+ you *must* pass the number of vertices you desire. Sage expects the
1841
+ output of plantri to be in "planar code" format, so do not set an
1842
+ option to change this default or results will be unpredictable.
1843
+
1844
+ - ``immutable`` -- boolean (default: ``False``); whether to return
1845
+ immutable or mutable graphs
1846
+
1847
+ The possible options are::
1848
+
1849
+ n : the number of vertices (the only compulsory parameter).
1850
+ This number must be in range `3\cdots 64`.
1851
+ It can also be given as "nd", where the suffix "d" means
1852
+ "dual", in which case it is converted by adding 4 then
1853
+ dividing by 2, i.e., `(28+4)/2 = 16`. In the case of
1854
+ triangulations, this calculation yields the number of
1855
+ faces, which is the number of vertices in the dual cubic
1856
+ graph.
1857
+
1858
+ -d : output the dual instead of the original graph.
1859
+ Note that it is applied only at the output stage. All
1860
+ other switches refer to the original graph before the dual
1861
+ is taken.
1862
+
1863
+ -o : Normally, one member of each isomorphism class is written.
1864
+ If this switch is given, one member of each O-P
1865
+ isomorphism class is written.
1866
+
1867
+ -V : output only graphs with non-trivial group. If -o is
1868
+ given the O-P group is used, the full group otherwise.
1869
+
1870
+ -m<int> : lower bound on the minimum degree. The default is -m3.
1871
+ In the dual graph, this means a lower bound on the minimum
1872
+ face size.
1873
+
1874
+ -c<int> : lower bound on the connectivity. The default is -c3.
1875
+
1876
+ -x : when used in combination with -cN, the connectivity must
1877
+ be exactly N rather than at least N.
1878
+
1879
+ -e : used to specify bounds on the number of edges.
1880
+ There are four possible forms:
1881
+ -e<int> exactly <int> edges
1882
+ -e:<int> at most <int> edges
1883
+ -e<int>: at least <int> edges
1884
+ -e<int>:<int> between <int> and <int> edges
1885
+
1886
+ -f<int> : upper bound on the size of a face, and so on the maximum
1887
+ degree of the dual.
1888
+
1889
+ -b but not -p : select eulerian triangulations, where "eulerian"
1890
+ means that every vertex has even degree.
1891
+ This parameter can be used in combination with
1892
+ parameters -c and -x.
1893
+
1894
+ -p but not -b : select general planar simple graphs.
1895
+ This parameter can be used in combination with
1896
+ parameters -m, -c, -x, -e and -f.
1897
+
1898
+ -bp or -pb : select general planar simple bipartite graphs.
1899
+ This parameter can be used in combination with
1900
+ parameters -m, -c, -x, -e and -f, except -c4, -m4,
1901
+ -m5 and -f3.
1902
+
1903
+ -P<int> : select triangulations of a disk. These are embedded simple
1904
+ graphs with a distinguished "outer" face. The outer face
1905
+ can be of any size (here called the disk size) but the
1906
+ other faces must be triangles. The argument <int> to -P
1907
+ is the disk size. If no argument (or 0) is given, all disk
1908
+ sizes are permitted.
1909
+ This parameter can be used in combination with
1910
+ parameters -m, -c, and -x.
1911
+
1912
+ -q : select simple quadrangulations. These are planar simple
1913
+ graphs for which every face has length 4.
1914
+ This parameter can be used in combination with parameters
1915
+ -c and -m.
1916
+
1917
+ -A : select Appolonian networks. These are simple planar
1918
+ triangulations that can be formed starting with `K_4` then
1919
+ repeatedly dividing a face into three by addition of a new
1920
+ vertex. They all have minimum degree and connectivity
1921
+ equal to 3.
1922
+
1923
+ res/mod : only generate subset res out of subsets 0..mod-1.
1924
+ The set of objects is divided into mod disjoint classes
1925
+ and only the res-th class is generated.
1926
+
1927
+ If -b, -q, -p, -P and -A are absent, the graphs found are triangulations
1928
+ only restricted by connectivity and minimum degree. In this case,
1929
+ there is the possibility of connectivity lower than 3.
1930
+
1931
+ Other options listed in the ``plantri`` guide might cause unpredictable
1932
+ behavior, in particular those changing the output format of ``plantri``
1933
+ as they will confuse the creation of a Sage graph.
1934
+
1935
+ OUTPUT:
1936
+
1937
+ An iterator which yields the graphs generated by ``plantri`` as Sage
1938
+ :class:`~sage.graphs.graph.Graph`.
1939
+
1940
+ .. SEEALSO::
1941
+
1942
+ - :meth:`planar_graphs` -- iterator over connected planar graphs
1943
+ using the ``plantri`` generator
1944
+ - :meth:`triangulations` -- iterator over connected planar
1945
+ triangulations using the ``plantri`` generator
1946
+ - :meth:`quadrangulations` -- iterator over connected planar
1947
+ quadrangulations using the ``plantri`` generator
1948
+
1949
+ EXAMPLES:
1950
+
1951
+ The generator can be used to construct graphs for testing, one at a time
1952
+ (usually inside a loop). Or it can be used to create an entire list all
1953
+ at once if there is sufficient memory to contain it::
1954
+
1955
+ sage: # optional - plantri
1956
+ sage: gen = graphs.plantri_gen("6")
1957
+ sage: next(gen)
1958
+ Graph on 6 vertices
1959
+ sage: next(gen)
1960
+ Graph on 6 vertices
1961
+ sage: next(gen)
1962
+ Traceback (most recent call last):
1963
+ ...
1964
+ StopIteration
1965
+
1966
+ An overview of the number of quadrangulations on up to 12 vertices. This
1967
+ agrees with :oeis:`A113201`::
1968
+
1969
+ sage: for i in range(4, 13): # optional - plantri
1970
+ ....: cmd = '-qm2c2 {}'.format(i)
1971
+ ....: L = len(list(graphs.plantri_gen(cmd)))
1972
+ ....: print("{:2d} {:3d}".format(i, L))
1973
+ 4 1
1974
+ 5 1
1975
+ 6 2
1976
+ 7 3
1977
+ 8 9
1978
+ 9 18
1979
+ 10 62
1980
+ 11 198
1981
+ 12 803
1982
+
1983
+ TESTS:
1984
+
1985
+ Wrong input, ``"-c=3"`` instead of ``"-c3"``::
1986
+
1987
+ sage: list(graphs.plantri_gen("6 -c3")) # optional - plantri
1988
+ [Graph on 6 vertices, Graph on 6 vertices]
1989
+ sage: list(graphs.plantri_gen("6 -c=3")) # optional - plantri
1990
+ Traceback (most recent call last):
1991
+ ...
1992
+ AttributeError: invalid options '6 -c=3'
1993
+ """
1994
+ from sage.features.graph_generators import Plantri
1995
+ Plantri().require()
1996
+
1997
+ import shlex
1998
+ command = '{} {}'.format(shlex.quote(Plantri().absolute_filename()),
1999
+ options)
2000
+ sp = subprocess.Popen(command, shell=True,
2001
+ stdin=subprocess.PIPE, stdout=subprocess.PIPE,
2002
+ stderr=subprocess.PIPE, close_fds=True,
2003
+ encoding='latin-1')
2004
+
2005
+ sp.stdout.reconfigure(newline='')
2006
+
2007
+ try:
2008
+ yield from graphs._read_planar_code(sp.stdout, immutable=immutable)
2009
+ except AssertionError:
2010
+ raise AttributeError("invalid options '{}'".format(options))
2011
+
2012
+ def planar_graphs(self, order, minimum_degree=None,
2013
+ minimum_connectivity=None,
2014
+ exact_connectivity=False,
2015
+ minimum_edges=None,
2016
+ maximum_edges=None,
2017
+ maximum_face_size=None,
2018
+ only_bipartite=False,
2019
+ dual=False,
2020
+ immutable=False):
2021
+ r"""
2022
+ An iterator over connected planar graphs using the plantri generator.
2023
+
2024
+ This uses the plantri generator (see [BM2007]_) which is available
2025
+ through the optional package plantri.
2026
+
2027
+ .. NOTE::
2028
+
2029
+ The non-3-connected graphs will be returned several times, with all
2030
+ its possible embeddings.
2031
+
2032
+ INPUT:
2033
+
2034
+ - ``order`` -- positive integer smaller than or equal to 64;
2035
+ this specifies the number of vertices in the generated graphs
2036
+
2037
+ - ``minimum_degree`` -- (default: ``None``) a value `\geq 1` and `\leq
2038
+ 5`, or ``None``. This specifies the minimum degree of the generated
2039
+ graphs. If this is ``None`` and the order is 1, then this is set to
2040
+ 0. If this is ``None`` and the minimum connectivity is specified, then
2041
+ this is set to the same value as the minimum connectivity. If the
2042
+ minimum connectivity is also equal to ``None``, then this is set to 1.
2043
+
2044
+ - ``minimum_connectivity`` -- (default: ``None``) a value `\geq 1`
2045
+ and `\leq 3`, or ``None``. This specifies the minimum connectivity of the
2046
+ generated graphs. If this is ``None`` and the minimum degree is
2047
+ specified, then this is set to the minimum of the minimum degree
2048
+ and 3. If the minimum degree is also equal to ``None``, then this
2049
+ is set to 1.
2050
+
2051
+ - ``exact_connectivity`` -- (default: ``False``) if ``True`` only
2052
+ graphs with exactly the specified connectivity will be generated.
2053
+ This option cannot be used with ``minimum_connectivity=3``, or if
2054
+ the minimum connectivity is not explicitly set.
2055
+
2056
+ - ``minimum_edges`` -- integer (default: ``None``); lower bound on the
2057
+ number of edges
2058
+
2059
+ - ``maximum_edges`` -- integer (default: ``None``); upper bound on the
2060
+ number of edges
2061
+
2062
+ - ``maximum_face_size`` -- integer (default: ``None``); upper bound on
2063
+ the size of a face and so on the maximum degree of the dual graph
2064
+
2065
+ - ``only_bipartite`` -- (default: ``False``) if ``True`` only bipartite
2066
+ graphs will be generated. This option cannot be used for graphs with
2067
+ a minimum degree larger than 3.
2068
+
2069
+ - ``dual`` -- (default: ``False``) if ``True`` return instead the
2070
+ planar duals of the generated graphs
2071
+
2072
+ - ``immutable`` -- boolean (default: ``False``); whether to return
2073
+ immutable or mutable graphs
2074
+
2075
+ OUTPUT:
2076
+
2077
+ An iterator which will produce all planar graphs with the given
2078
+ number of vertices as Sage graphs with an embedding set. These will be
2079
+ simple graphs (no loops, no multiple edges, no directed edges)
2080
+ unless the option ``dual=True`` is used.
2081
+
2082
+ .. SEEALSO::
2083
+
2084
+ - :meth:`~sage.graphs.generic_graph.GenericGraph.set_embedding`,
2085
+ :meth:`~sage.graphs.generic_graph.GenericGraph.get_embedding` --
2086
+ get/set methods for embeddings.
2087
+
2088
+ EXAMPLES:
2089
+
2090
+ There are 6 planar graphs on 4 vertices::
2091
+
2092
+ sage: gen = graphs.planar_graphs(4) # optional - plantri
2093
+ sage: len(list(gen)) # optional - plantri
2094
+ 6
2095
+
2096
+ Three of these planar graphs are bipartite::
2097
+
2098
+ sage: gen = graphs.planar_graphs(4, only_bipartite=True) # optional - plantri
2099
+ sage: len(list(gen)) # optional - plantri
2100
+ 3
2101
+
2102
+ Setting ``dual=True`` gives the planar dual graphs::
2103
+
2104
+ sage: gen = graphs.planar_graphs(4, dual=True) # optional - plantri
2105
+ sage: [u for u in list(gen)] # optional - plantri
2106
+ [Graph on 4 vertices,
2107
+ Multi-graph on 3 vertices,
2108
+ Multi-graph on 2 vertices,
2109
+ Looped multi-graph on 2 vertices,
2110
+ Looped multi-graph on 1 vertex,
2111
+ Looped multi-graph on 1 vertex]
2112
+
2113
+ The cycle of length 4 is the only 2-connected bipartite planar graph
2114
+ on 4 vertices::
2115
+
2116
+ sage: l = list(graphs.planar_graphs(4, minimum_connectivity=2, only_bipartite=True)) # optional - plantri
2117
+ sage: l[0].get_embedding() # optional - plantri
2118
+ {1: [2, 3],
2119
+ 2: [1, 4],
2120
+ 3: [1, 4],
2121
+ 4: [2, 3]}
2122
+
2123
+ There is one planar graph with one vertex. This graph obviously has
2124
+ minimum degree equal to 0::
2125
+
2126
+ sage: list(graphs.planar_graphs(1)) # optional - plantri
2127
+ [Graph on 1 vertex]
2128
+ sage: list(graphs.planar_graphs(1, minimum_degree=1)) # optional - plantri
2129
+ []
2130
+
2131
+ Specifying lower and upper bounds on the number of edges::
2132
+
2133
+ sage: # optional - plantri
2134
+ sage: len(list(graphs.planar_graphs(4)))
2135
+ 6
2136
+ sage: len(list(graphs.planar_graphs(4, minimum_edges=4)))
2137
+ 4
2138
+ sage: len(list(graphs.planar_graphs(4, maximum_edges=4)))
2139
+ 4
2140
+ sage: len(list(graphs.planar_graphs(4, minimum_edges=4, maximum_edges=4)))
2141
+ 2
2142
+
2143
+ Specifying the maximum size of a face::
2144
+
2145
+ sage: len(list(graphs.planar_graphs(4, maximum_face_size=3))) # optional - plantri
2146
+ 1
2147
+ sage: len(list(graphs.planar_graphs(4, maximum_face_size=4))) # optional - plantri
2148
+ 3
2149
+
2150
+ TESTS:
2151
+
2152
+ The number of edges in a planar graph is equal to the number of edges in
2153
+ its dual::
2154
+
2155
+ sage: # optional - plantri
2156
+ sage: planar = list(graphs.planar_graphs(5,dual=True))
2157
+ sage: dual_planar = list(graphs.planar_graphs(5,dual=False))
2158
+ sage: planar_sizes = [g.size() for g in planar]
2159
+ sage: dual_planar_sizes = [g.size() for g in dual_planar]
2160
+ sage: planar_sizes == dual_planar_sizes
2161
+ True
2162
+ """
2163
+ if order < 0:
2164
+ raise ValueError("number of vertices should be nonnegative")
2165
+
2166
+ # plantri can only output general planar graphs on up to 64 vertices
2167
+ if order > 64:
2168
+ raise ValueError("number of vertices should be at most 64")
2169
+
2170
+ if exact_connectivity and minimum_connectivity is None:
2171
+ raise ValueError("Minimum connectivity must be specified to use the exact_connectivity option.")
2172
+
2173
+ if minimum_connectivity is not None and not (1 <= minimum_connectivity <= 3):
2174
+ raise ValueError("Minimum connectivity should be a number between 1 and 3.")
2175
+
2176
+ # minimum degree should be None or a number between 1 and 5
2177
+ if minimum_degree == 0:
2178
+ if order != 1:
2179
+ raise ValueError("Minimum degree equal to 0 is only possible if the graphs have 1 vertex.")
2180
+ elif minimum_degree is not None and not (1 <= minimum_degree <= 5):
2181
+ raise ValueError("Minimum degree should be a number between 1 and 5 if the order is greater than 1.")
2182
+ elif minimum_degree is None and order == 1:
2183
+ minimum_degree = 0
2184
+
2185
+ # check combination of values of minimum degree and minimum connectivity
2186
+ if minimum_connectivity is None:
2187
+ if minimum_degree is not None:
2188
+ minimum_connectivity = min(3, minimum_degree)
2189
+ elif minimum_degree is None:
2190
+ minimum_degree, minimum_connectivity = 1, 1
2191
+ else:
2192
+ if minimum_degree is None:
2193
+ minimum_degree = minimum_connectivity
2194
+ elif (minimum_degree < minimum_connectivity and
2195
+ minimum_degree > 0):
2196
+ raise ValueError("Minimum connectivity can be at most the minimum degree.")
2197
+
2198
+ # exact connectivity is not implemented for minimum connectivity 3
2199
+ if exact_connectivity and minimum_connectivity == 3:
2200
+ raise NotImplementedError("Generation of planar graphs with connectivity exactly 3 is not implemented.")
2201
+
2202
+ if only_bipartite and minimum_degree > 3:
2203
+ raise NotImplementedError("Generation of bipartite planar graphs with minimum degree 4 or 5 is not implemented.")
2204
+
2205
+ edges = ''
2206
+ if minimum_edges is None:
2207
+ if maximum_edges is not None:
2208
+ if maximum_edges < order - 1:
2209
+ raise ValueError("the number of edges cannot be less than order - 1")
2210
+ edges = '-e:{}'.format(maximum_edges)
2211
+ else:
2212
+ if minimum_edges > 3*order - 6:
2213
+ raise ValueError("the number of edges cannot be more than 3*order - 6")
2214
+ if maximum_edges is None:
2215
+ edges = '-e{}:'.format(minimum_edges)
2216
+ elif minimum_edges > maximum_edges:
2217
+ raise ValueError("the maximum number of edges must be larger "
2218
+ "or equal to the minimum number of edges")
2219
+ elif minimum_edges == maximum_edges:
2220
+ edges = '-e{}'.format(minimum_edges)
2221
+ else:
2222
+ edges = '-e{}:{}'.format(minimum_edges, maximum_edges)
2223
+
2224
+ faces = ''
2225
+ if maximum_face_size is not None:
2226
+ if maximum_face_size < 3:
2227
+ raise ValueError("the upper bound on the size of a face must be at least 3")
2228
+ faces = '-f{}'.format(maximum_face_size)
2229
+
2230
+ if order == 0:
2231
+ return
2232
+
2233
+ minimum_order = {0: 1, 1: 2, 2: 3, 3: 4, 4: 6, 5: 12}[minimum_degree]
2234
+
2235
+ if order < minimum_order:
2236
+ return
2237
+
2238
+ if order == 1:
2239
+ if minimum_degree == 0:
2240
+ G = graph.Graph(1, immutable=immutable)
2241
+ G.set_embedding({0: []})
2242
+ yield G
2243
+ return
2244
+
2245
+ cmd = '-p{}m{}c{}{}{} {} {} {}'
2246
+ command = cmd.format('b' if only_bipartite else '',
2247
+ minimum_degree,
2248
+ minimum_connectivity,
2249
+ 'x' if exact_connectivity else '',
2250
+ 'd' if dual else '',
2251
+ edges, faces,
2252
+ order)
2253
+
2254
+ yield from graphs.plantri_gen(command, immutable=immutable)
2255
+
2256
+ def triangulations(self, order, minimum_degree=None, minimum_connectivity=None,
2257
+ exact_connectivity=False, only_eulerian=False, dual=False,
2258
+ immutable=False):
2259
+ r"""
2260
+ An iterator over connected planar triangulations using the plantri generator.
2261
+
2262
+ This uses the plantri generator (see [BM2007]_) which is available
2263
+ through the optional package plantri.
2264
+
2265
+ INPUT:
2266
+
2267
+ - ``order`` -- positive integer smaller than or equal to 64;
2268
+ this specifies the number of vertices in the generated triangulations
2269
+
2270
+ - ``minimum_degree`` -- (default: ``None``) a value `\geq 3` and `\leq 5`,
2271
+ or ``None``. This specifies the minimum degree of the generated
2272
+ triangulations. If this is ``None`` and the minimum connectivity
2273
+ is specified, then this is set to the same value as the minimum
2274
+ connectivity. If the minimum connectivity is also equal to ``None``,
2275
+ then this is set to 3.
2276
+
2277
+ - ``minimum_connectivity`` -- (default: ``None``) a value `\geq 3` and
2278
+ `\leq 5`, or ``None``. This specifies the minimum connectivity of the
2279
+ generated triangulations. If this is ``None`` and the minimum degree
2280
+ is specified, then this is set to the minimum of the minimum degree
2281
+ and 3. If the minimum degree is also equal to ``None``, then this is
2282
+ set to 3.
2283
+
2284
+ - ``exact_connectivity`` -- (default: ``False``) if ``True`` only
2285
+ triangulations with exactly the specified connectivity will be generated.
2286
+ This option cannot be used with ``minimum_connectivity=3``, or if
2287
+ the minimum connectivity is not explicitly set.
2288
+
2289
+ - ``only_eulerian`` -- (default: ``False``) if ``True`` only Eulerian
2290
+ triangulations will be generated. This option cannot be used if the
2291
+ minimum degree is explicitly set to anything else than 4.
2292
+
2293
+ - ``dual`` -- (default: ``False``) if ``True`` return instead the
2294
+ planar duals of the generated graphs
2295
+
2296
+ - ``immutable`` -- boolean (default: ``False``); whether to return
2297
+ immutable or mutable graphs
2298
+
2299
+ OUTPUT:
2300
+
2301
+ An iterator which will produce all planar triangulations with the given
2302
+ number of vertices as Sage graphs with an embedding set. These will be
2303
+ simple graphs (no loops, no multiple edges, no directed edges).
2304
+
2305
+ .. SEEALSO::
2306
+
2307
+ - :meth:`~sage.graphs.generic_graph.GenericGraph.set_embedding`,
2308
+ :meth:`~sage.graphs.generic_graph.GenericGraph.get_embedding` --
2309
+ get/set methods for embeddings.
2310
+
2311
+ - :meth:`~sage.graphs.graph_generators.GraphGenerators.RandomTriangulation`
2312
+ -- build a random triangulation.
2313
+
2314
+ EXAMPLES:
2315
+
2316
+ The unique planar embedding of the `K_4` is the only planar triangulations
2317
+ on 4 vertices::
2318
+
2319
+ sage: gen = graphs.triangulations(4) # optional - plantri
2320
+ sage: [g.get_embedding() for g in gen] # optional - plantri
2321
+ [{1: [2, 3, 4], 2: [1, 4, 3], 3: [1, 2, 4], 4: [1, 3, 2]}]
2322
+
2323
+ but, of course, this graph is not Eulerian::
2324
+
2325
+ sage: gen = graphs.triangulations(4, only_eulerian=True) # optional - plantri
2326
+ sage: len(list(gen)) # optional - plantri
2327
+ 0
2328
+
2329
+ The unique Eulerian triangulation on 6 vertices is isomorphic to the octahedral
2330
+ graph. ::
2331
+
2332
+ sage: gen = graphs.triangulations(6, only_eulerian=True) # optional - plantri
2333
+ sage: g = next(gen) # optional - plantri
2334
+ sage: g.is_isomorphic(graphs.OctahedralGraph()) # optional - plantri
2335
+ True
2336
+
2337
+ The minimum degree of a triangulation is 3, so the method can not output
2338
+ a triangle::
2339
+
2340
+ sage: list(graphs.triangulations(3)) # optional - plantri
2341
+ []
2342
+
2343
+ An overview of the number of 5-connected triangulations on up to 22 vertices. This
2344
+ agrees with :oeis:`A081621`::
2345
+
2346
+ sage: for i in range(12, 23): # optional - plantri
2347
+ ....: L = len(list(graphs.triangulations(i, minimum_connectivity=5)))
2348
+ ....: print("{} {:3d}".format(i,L))
2349
+ 12 1
2350
+ 13 0
2351
+ 14 1
2352
+ 15 1
2353
+ 16 3
2354
+ 17 4
2355
+ 18 12
2356
+ 19 23
2357
+ 20 71
2358
+ 21 187
2359
+ 22 627
2360
+
2361
+ The minimum connectivity can be at most the minimum degree::
2362
+
2363
+ sage: gen = next(graphs.triangulations(10, minimum_degree=3, # optional - plantri
2364
+ ....: minimum_connectivity=5))
2365
+ Traceback (most recent call last):
2366
+ ...
2367
+ ValueError: Minimum connectivity can be at most the minimum degree.
2368
+
2369
+ There are 5 triangulations with 9 vertices and minimum degree equal to 4
2370
+ that are 3-connected, but only one of them is not 4-connected::
2371
+
2372
+ sage: len([g for g in graphs.triangulations(9, minimum_degree=4, # optional - plantri
2373
+ ....: minimum_connectivity=3)])
2374
+ 5
2375
+ sage: len([g for g in graphs.triangulations(9, minimum_degree=4, # optional - plantri
2376
+ ....: minimum_connectivity=3,
2377
+ ....: exact_connectivity=True)])
2378
+ 1
2379
+
2380
+ Setting ``dual=True`` gives the planar dual graphs::
2381
+
2382
+ sage: [len(g) for g in graphs.triangulations(9, minimum_degree=4, # optional plantri
2383
+ ....: minimum_connectivity=3, dual=True)]
2384
+ [14, 14, 14, 14, 14]
2385
+
2386
+ TESTS::
2387
+
2388
+ sage: [g.size() for g in graphs.triangulations(6, minimum_connectivity=3)] # optional - plantri
2389
+ [12, 12]
2390
+ """
2391
+ if order < 0:
2392
+ raise ValueError("number of vertices should be nonnegative")
2393
+
2394
+ # plantri can only output planar triangulations on up to 64 vertices
2395
+ if order > 64:
2396
+ raise ValueError("number of vertices should be at most 64")
2397
+
2398
+ if exact_connectivity and minimum_connectivity is None:
2399
+ raise ValueError("Minimum connectivity must be specified to use the exact_connectivity option.")
2400
+
2401
+ if minimum_connectivity is not None and not (3 <= minimum_connectivity <= 5):
2402
+ raise ValueError("Minimum connectivity should be None or a number between 3 and 5.")
2403
+
2404
+ if minimum_degree is not None and not (3 <= minimum_degree <= 5):
2405
+ raise ValueError("Minimum degree should be None or a number between 3 and 5.")
2406
+
2407
+ # for Eulerian triangulations the minimum degree is set to 4 (unless it was already specifically set)
2408
+ if only_eulerian and minimum_degree is None:
2409
+ minimum_degree = 4
2410
+
2411
+ # check combination of values of minimum degree and minimum connectivity
2412
+ if minimum_connectivity is None:
2413
+ if minimum_degree is not None:
2414
+ minimum_connectivity = min(3, minimum_degree)
2415
+ else:
2416
+ minimum_degree, minimum_connectivity = 3, 3
2417
+ else:
2418
+ if minimum_degree is None:
2419
+ minimum_degree = minimum_connectivity
2420
+ elif minimum_degree < minimum_connectivity:
2421
+ raise ValueError("Minimum connectivity can be at most the minimum degree.")
2422
+
2423
+ # exact connectivity is not implemented for minimum connectivity equal
2424
+ # to minimum degree
2425
+ if exact_connectivity and minimum_connectivity == minimum_degree:
2426
+ raise NotImplementedError("Generation of triangulations with minimum connectivity equal to minimum degree is not implemented.")
2427
+
2428
+ minimum_order = {3: 4, 4: 6, 5: 12}[minimum_degree]
2429
+
2430
+ if order < minimum_order:
2431
+ return
2432
+
2433
+ if only_eulerian and order < 6:
2434
+ return
2435
+
2436
+ cmd = '-{}m{}c{}{}{} {}'
2437
+ command = cmd.format('b' if only_eulerian else '',
2438
+ minimum_degree,
2439
+ minimum_connectivity,
2440
+ 'x' if exact_connectivity else '',
2441
+ 'd' if dual else '',
2442
+ order)
2443
+
2444
+ yield from graphs.plantri_gen(command, immutable=immutable)
2445
+
2446
+ def quadrangulations(self, order, minimum_degree=None, minimum_connectivity=None,
2447
+ no_nonfacial_quadrangles=False, dual=False,
2448
+ immutable=False):
2449
+ r"""
2450
+ An iterator over planar quadrangulations using the plantri generator.
2451
+
2452
+ This uses the plantri generator (see [BM2007]_) which is available
2453
+ through the optional package plantri.
2454
+
2455
+ INPUT:
2456
+
2457
+ - ``order`` -- positive integer smaller than or equal to 64;
2458
+ this specifies the number of vertices in the generated quadrangulations
2459
+
2460
+ - ``minimum_degree`` -- (default: ``None``) a value `\geq 2` and `\leq
2461
+ 3`, or ``None``. This specifies the minimum degree of the generated
2462
+ quadrangulations. If this is ``None`` and the minimum connectivity is
2463
+ specified, then this is set to the same value as the minimum
2464
+ connectivity. If the minimum connectivity is also equal to ``None``,
2465
+ then this is set to 2.
2466
+
2467
+ - ``minimum_connectivity`` -- (default: ``None``) a value `\geq 2` and
2468
+ `\leq 3`, or ``None``. This specifies the minimum connectivity of the
2469
+ generated quadrangulations. If this is ``None`` and the option
2470
+ ``no_nonfacial_quadrangles`` is set to ``True``, then this is set to
2471
+ 3. Otherwise if this is ``None`` and the minimum degree is specified,
2472
+ then this is set to the minimum degree. If the minimum degree is also
2473
+ equal to ``None``, then this is set to 3.
2474
+
2475
+ - ``no_nonfacial_quadrangles`` -- (default: ``False``) if ``True`` only
2476
+ quadrangulations with no non-facial quadrangles are generated. This
2477
+ option cannot be used if ``minimum_connectivity`` is set to 2.
2478
+
2479
+ - ``dual`` -- (default: ``False``) if ``True`` return instead the
2480
+ planar duals of the generated graphs
2481
+
2482
+ - ``immutable`` -- boolean (default: ``False``); whether to return
2483
+ immutable or mutable graphs
2484
+
2485
+ OUTPUT:
2486
+
2487
+ An iterator which will produce all planar quadrangulations with the given
2488
+ number of vertices as Sage graphs with an embedding set. These will be
2489
+ simple graphs (no loops, no multiple edges, no directed edges).
2490
+
2491
+ .. SEEALSO::
2492
+
2493
+ - :meth:`~sage.graphs.generic_graph.GenericGraph.set_embedding`,
2494
+ :meth:`~sage.graphs.generic_graph.GenericGraph.get_embedding` --
2495
+ get/set methods for embeddings.
2496
+
2497
+ EXAMPLES:
2498
+
2499
+ The cube is the only 3-connected planar quadrangulation on 8 vertices::
2500
+
2501
+ sage: # optional - plantri
2502
+ sage: gen = graphs.quadrangulations(8, minimum_connectivity=3)
2503
+ sage: g = next(gen)
2504
+ sage: g.is_isomorphic(graphs.CubeGraph(3))
2505
+ True
2506
+ sage: next(gen)
2507
+ Traceback (most recent call last):
2508
+ ...
2509
+ StopIteration
2510
+
2511
+ An overview of the number of quadrangulations on up to 12 vertices. This
2512
+ agrees with :oeis:`A113201`::
2513
+
2514
+ sage: for i in range(4,13): # optional - plantri
2515
+ ....: L = len(list(graphs.quadrangulations(i)))
2516
+ ....: print("{:2d} {:3d}".format(i,L))
2517
+ 4 1
2518
+ 5 1
2519
+ 6 2
2520
+ 7 3
2521
+ 8 9
2522
+ 9 18
2523
+ 10 62
2524
+ 11 198
2525
+ 12 803
2526
+
2527
+ There are 2 planar quadrangulation on 12 vertices that do not have a
2528
+ non-facial quadrangle::
2529
+
2530
+ sage: len([g for g in graphs.quadrangulations(12, no_nonfacial_quadrangles=True)]) # optional - plantri
2531
+ 2
2532
+
2533
+ Setting ``dual=True`` gives the planar dual graphs::
2534
+
2535
+ sage: [len(g) for g in graphs.quadrangulations(12, no_nonfacial_quadrangles=True, dual=True)] # optional - plantri
2536
+ [10, 10]
2537
+ """
2538
+ if order < 0:
2539
+ raise ValueError("number of vertices should be nonnegative")
2540
+
2541
+ # plantri can only output planar quadrangulations on up to 64 vertices
2542
+ if order > 64:
2543
+ raise ValueError("number of vertices should be at most 64")
2544
+
2545
+ if minimum_connectivity not in {None, 2, 3}:
2546
+ raise ValueError("Minimum connectivity should be None, 2 or 3.")
2547
+
2548
+ if minimum_degree not in {None, 2, 3}:
2549
+ raise ValueError("Minimum degree should be None, 2 or 3.")
2550
+
2551
+ if (no_nonfacial_quadrangles and
2552
+ minimum_connectivity == 2):
2553
+ raise NotImplementedError("Generation of no non-facial quadrangles "
2554
+ "and minimum connectivity 2 is not implemented")
2555
+
2556
+ # check combination of values of minimum degree and minimum connectivity
2557
+ if minimum_connectivity is None:
2558
+ if minimum_degree is not None:
2559
+ minimum_connectivity = min(2, minimum_degree)
2560
+ else:
2561
+ minimum_degree, minimum_connectivity = 2, 2
2562
+ else:
2563
+ if minimum_degree is None:
2564
+ minimum_degree = minimum_connectivity
2565
+ elif minimum_degree < minimum_connectivity:
2566
+ raise ValueError("Minimum connectivity can be at most the minimum degree.")
2567
+
2568
+ minimum_order = {2: 4, 3: 8}[minimum_degree]
2569
+
2570
+ if order < minimum_order:
2571
+ return
2572
+
2573
+ if no_nonfacial_quadrangles:
2574
+ # for plantri -q the option -c4 means 3-connected with no non-facial quadrangles
2575
+ minimum_connectivity = 4
2576
+
2577
+ cmd = '-qm{}c{}{} {}'
2578
+ command = cmd.format(minimum_degree,
2579
+ minimum_connectivity,
2580
+ 'd' if dual else '',
2581
+ order)
2582
+
2583
+ yield from graphs.plantri_gen(command, immutable=immutable)
2584
+
2585
+ ###########################################################################
2586
+ # Basic Graphs
2587
+ ###########################################################################
2588
+ from .generators import basic
2589
+ BullGraph = staticmethod(basic.BullGraph)
2590
+ ButterflyGraph = staticmethod(basic.ButterflyGraph)
2591
+ CircularLadderGraph = staticmethod(basic.CircularLadderGraph)
2592
+ ClawGraph = staticmethod(basic.ClawGraph)
2593
+ CycleGraph = staticmethod(basic.CycleGraph)
2594
+ CompleteGraph = staticmethod(basic.CompleteGraph)
2595
+ CompleteBipartiteGraph = staticmethod(basic.CompleteBipartiteGraph)
2596
+ CompleteMultipartiteGraph = staticmethod(basic.CompleteMultipartiteGraph)
2597
+ CorrelationGraph = staticmethod(basic.CorrelationGraph)
2598
+ DiamondGraph = staticmethod(basic.DiamondGraph)
2599
+ GemGraph = staticmethod(basic.GemGraph)
2600
+ DartGraph = staticmethod(basic.DartGraph)
2601
+ ForkGraph = staticmethod(basic.ForkGraph)
2602
+ EmptyGraph = staticmethod(basic.EmptyGraph)
2603
+ Grid2dGraph = staticmethod(basic.Grid2dGraph)
2604
+ GridGraph = staticmethod(basic.GridGraph)
2605
+ HouseGraph = staticmethod(basic.HouseGraph)
2606
+ HouseXGraph = staticmethod(basic.HouseXGraph)
2607
+ LadderGraph = staticmethod(basic.LadderGraph)
2608
+ MoebiusLadderGraph = staticmethod(basic.MoebiusLadderGraph)
2609
+ PathGraph = staticmethod(basic.PathGraph)
2610
+ StarGraph = staticmethod(basic.StarGraph)
2611
+ Toroidal6RegularGrid2dGraph = staticmethod(basic.Toroidal6RegularGrid2dGraph)
2612
+ ToroidalGrid2dGraph = staticmethod(basic.ToroidalGrid2dGraph)
2613
+
2614
+ ###########################################################################
2615
+ # Small Graphs
2616
+ ###########################################################################
2617
+ from .generators import smallgraphs, distance_regular
2618
+ Balaban10Cage = staticmethod(smallgraphs.Balaban10Cage)
2619
+ Balaban11Cage = staticmethod(smallgraphs.Balaban11Cage)
2620
+ BidiakisCube = staticmethod(smallgraphs.BidiakisCube)
2621
+ BiggsSmithGraph = staticmethod(smallgraphs.BiggsSmithGraph)
2622
+ BlanusaFirstSnarkGraph = staticmethod(smallgraphs.BlanusaFirstSnarkGraph)
2623
+ BlanusaSecondSnarkGraph = staticmethod(smallgraphs.BlanusaSecondSnarkGraph)
2624
+ BrinkmannGraph = staticmethod(smallgraphs.BrinkmannGraph)
2625
+ BrouwerHaemersGraph = staticmethod(smallgraphs.BrouwerHaemersGraph)
2626
+ BuckyBall = staticmethod(smallgraphs.BuckyBall)
2627
+ CameronGraph = staticmethod(smallgraphs.CameronGraph)
2628
+ Cell600 = staticmethod(smallgraphs.Cell600)
2629
+ Cell120 = staticmethod(smallgraphs.Cell120)
2630
+ ChvatalGraph = staticmethod(smallgraphs.ChvatalGraph)
2631
+ ClebschGraph = staticmethod(smallgraphs.ClebschGraph)
2632
+ cocliques_HoffmannSingleton = staticmethod(distance_regular.cocliques_HoffmannSingleton)
2633
+ ConwaySmith_for_3S7 = staticmethod(distance_regular.ConwaySmith_for_3S7)
2634
+ CoxeterGraph = staticmethod(smallgraphs.CoxeterGraph)
2635
+ CubeplexGraph = staticmethod(smallgraphs.CubeplexGraph)
2636
+ DejterGraph = staticmethod(smallgraphs.DejterGraph)
2637
+ DesarguesGraph = staticmethod(smallgraphs.DesarguesGraph)
2638
+ distance_3_doubly_truncated_Golay_code_graph = staticmethod(distance_regular.distance_3_doubly_truncated_Golay_code_graph)
2639
+ DoubleStarSnark = staticmethod(smallgraphs.DoubleStarSnark)
2640
+ DoublyTruncatedWittGraph = staticmethod(distance_regular.DoublyTruncatedWittGraph)
2641
+ DurerGraph = staticmethod(smallgraphs.DurerGraph)
2642
+ DyckGraph = staticmethod(smallgraphs.DyckGraph)
2643
+ EllinghamHorton54Graph = staticmethod(smallgraphs.EllinghamHorton54Graph)
2644
+ EllinghamHorton78Graph = staticmethod(smallgraphs.EllinghamHorton78Graph)
2645
+ ErreraGraph = staticmethod(smallgraphs.ErreraGraph)
2646
+ F26AGraph = staticmethod(smallgraphs.F26AGraph)
2647
+ FlowerSnark = staticmethod(smallgraphs.FlowerSnark)
2648
+ FolkmanGraph = staticmethod(smallgraphs.FolkmanGraph)
2649
+ FosterGraph = staticmethod(smallgraphs.FosterGraph)
2650
+ FosterGraph3S6 = staticmethod(distance_regular.FosterGraph3S6)
2651
+ FranklinGraph = staticmethod(smallgraphs.FranklinGraph)
2652
+ FruchtGraph = staticmethod(smallgraphs.FruchtGraph)
2653
+ GoldnerHararyGraph = staticmethod(smallgraphs.GoldnerHararyGraph)
2654
+ GolombGraph = staticmethod(smallgraphs.GolombGraph)
2655
+ GossetGraph = staticmethod(smallgraphs.GossetGraph)
2656
+ graph_3O73 = staticmethod(distance_regular.graph_3O73)
2657
+ GrayGraph = staticmethod(smallgraphs.GrayGraph)
2658
+ GritsenkoGraph = staticmethod(smallgraphs.GritsenkoGraph)
2659
+ GrotzschGraph = staticmethod(smallgraphs.GrotzschGraph)
2660
+ HallJankoGraph = staticmethod(smallgraphs.HallJankoGraph)
2661
+ WellsGraph = staticmethod(smallgraphs.WellsGraph)
2662
+ HarborthGraph = staticmethod(smallgraphs.HarborthGraph)
2663
+ HarriesGraph = staticmethod(smallgraphs.HarriesGraph)
2664
+ HarriesWongGraph = staticmethod(smallgraphs.HarriesWongGraph)
2665
+ HeawoodGraph = staticmethod(smallgraphs.HeawoodGraph)
2666
+ HerschelGraph = staticmethod(smallgraphs.HerschelGraph)
2667
+ HigmanSimsGraph = staticmethod(smallgraphs.HigmanSimsGraph)
2668
+ HoffmanGraph = staticmethod(smallgraphs.HoffmanGraph)
2669
+ HoffmanSingletonGraph = staticmethod(smallgraphs.HoffmanSingletonGraph)
2670
+ HoltGraph = staticmethod(smallgraphs.HoltGraph)
2671
+ HortonGraph = staticmethod(smallgraphs.HortonGraph)
2672
+ IoninKharaghani765Graph = staticmethod(smallgraphs.IoninKharaghani765Graph)
2673
+ IvanovIvanovFaradjevGraph = staticmethod(distance_regular.IvanovIvanovFaradjevGraph)
2674
+ J2Graph = staticmethod(distance_regular.J2Graph)
2675
+ JankoKharaghaniGraph = staticmethod(smallgraphs.JankoKharaghaniGraph)
2676
+ JankoKharaghaniTonchevGraph = staticmethod(smallgraphs.JankoKharaghaniTonchevGraph)
2677
+ KittellGraph = staticmethod(smallgraphs.KittellGraph)
2678
+ KrackhardtKiteGraph = staticmethod(smallgraphs.KrackhardtKiteGraph)
2679
+ Klein3RegularGraph = staticmethod(smallgraphs.Klein3RegularGraph)
2680
+ Klein7RegularGraph = staticmethod(smallgraphs.Klein7RegularGraph)
2681
+ LargeWittGraph = staticmethod(distance_regular.LargeWittGraph)
2682
+ LeonardGraph = staticmethod(distance_regular.LeonardGraph)
2683
+ LjubljanaGraph = staticmethod(smallgraphs.LjubljanaGraph)
2684
+ vanLintSchrijverGraph = staticmethod(distance_regular.vanLintSchrijverGraph)
2685
+ LivingstoneGraph = staticmethod(smallgraphs.LivingstoneGraph)
2686
+ locally_GQ42_distance_transitive_graph = staticmethod(distance_regular.locally_GQ42_distance_transitive_graph)
2687
+ LocalMcLaughlinGraph = staticmethod(smallgraphs.LocalMcLaughlinGraph)
2688
+ M22Graph = staticmethod(smallgraphs.M22Graph)
2689
+ MarkstroemGraph = staticmethod(smallgraphs.MarkstroemGraph)
2690
+ MathonStronglyRegularGraph = staticmethod(smallgraphs.MathonStronglyRegularGraph)
2691
+ McGeeGraph = staticmethod(smallgraphs.McGeeGraph)
2692
+ McLaughlinGraph = staticmethod(smallgraphs.McLaughlinGraph)
2693
+ MeredithGraph = staticmethod(smallgraphs.MeredithGraph)
2694
+ MoebiusKantorGraph = staticmethod(smallgraphs.MoebiusKantorGraph)
2695
+ MoserSpindle = staticmethod(smallgraphs.MoserSpindle)
2696
+ MurtyGraph = staticmethod(smallgraphs.MurtyGraph)
2697
+ NauruGraph = staticmethod(smallgraphs.NauruGraph)
2698
+ PappusGraph = staticmethod(smallgraphs.PappusGraph)
2699
+ PoussinGraph = staticmethod(smallgraphs.PoussinGraph)
2700
+ PerkelGraph = staticmethod(smallgraphs.PerkelGraph)
2701
+ PetersenGraph = staticmethod(smallgraphs.PetersenGraph)
2702
+ RobertsonGraph = staticmethod(smallgraphs.RobertsonGraph)
2703
+ SchlaefliGraph = staticmethod(smallgraphs.SchlaefliGraph)
2704
+ shortened_00_11_binary_Golay_code_graph = staticmethod(distance_regular.shortened_00_11_binary_Golay_code_graph)
2705
+ shortened_000_111_extended_binary_Golay_code_graph = staticmethod(distance_regular.shortened_000_111_extended_binary_Golay_code_graph)
2706
+ ShrikhandeGraph = staticmethod(smallgraphs.ShrikhandeGraph)
2707
+ SimsGewirtzGraph = staticmethod(smallgraphs.SimsGewirtzGraph)
2708
+ SousselierGraph = staticmethod(smallgraphs.SousselierGraph)
2709
+ SylvesterGraph = staticmethod(smallgraphs.SylvesterGraph)
2710
+ SzekeresSnarkGraph = staticmethod(smallgraphs.SzekeresSnarkGraph)
2711
+ ThomsenGraph = staticmethod(smallgraphs.ThomsenGraph)
2712
+ TietzeGraph = staticmethod(smallgraphs.TietzeGraph)
2713
+ TricornGraph = staticmethod(smallgraphs.TricornGraph)
2714
+ Tutte12Cage = staticmethod(smallgraphs.Tutte12Cage)
2715
+ TruncatedIcosidodecahedralGraph = staticmethod(smallgraphs.TruncatedIcosidodecahedralGraph)
2716
+ TruncatedTetrahedralGraph = staticmethod(smallgraphs.TruncatedTetrahedralGraph)
2717
+ TruncatedWittGraph = staticmethod(distance_regular.TruncatedWittGraph)
2718
+ TutteCoxeterGraph = staticmethod(smallgraphs.TutteCoxeterGraph)
2719
+ TutteGraph = staticmethod(smallgraphs.TutteGraph)
2720
+ TwinplexGraph = staticmethod(smallgraphs.TwinplexGraph)
2721
+ U42Graph216 = staticmethod(smallgraphs.U42Graph216)
2722
+ U42Graph540 = staticmethod(smallgraphs.U42Graph540)
2723
+ WagnerGraph = staticmethod(smallgraphs.WagnerGraph)
2724
+ WatkinsSnarkGraph = staticmethod(smallgraphs.WatkinsSnarkGraph)
2725
+ WienerArayaGraph = staticmethod(smallgraphs.WienerArayaGraph)
2726
+ SuzukiGraph = staticmethod(smallgraphs.SuzukiGraph)
2727
+
2728
+ ###########################################################################
2729
+ # Platonic Solids
2730
+ ###########################################################################
2731
+ from .generators import platonic_solids
2732
+ DodecahedralGraph = staticmethod(platonic_solids.DodecahedralGraph)
2733
+ HexahedralGraph = staticmethod(platonic_solids.HexahedralGraph)
2734
+ IcosahedralGraph = staticmethod(platonic_solids.IcosahedralGraph)
2735
+ OctahedralGraph = staticmethod(platonic_solids.OctahedralGraph)
2736
+ TetrahedralGraph = staticmethod(platonic_solids.TetrahedralGraph)
2737
+
2738
+ ###########################################################################
2739
+ # Families
2740
+ ###########################################################################
2741
+ from . import cographs as cographs_module
2742
+ from .generators import families
2743
+ from . import strongly_regular_db
2744
+ AlternatingFormsGraph = staticmethod(distance_regular.AlternatingFormsGraph)
2745
+ AztecDiamondGraph = staticmethod(families.AztecDiamondGraph)
2746
+ BalancedTree = staticmethod(families.BalancedTree)
2747
+ BarbellGraph = staticmethod(families.BarbellGraph)
2748
+ BilinearFormsGraph = staticmethod(distance_regular.BilinearFormsGraph)
2749
+ BiwheelGraph = staticmethod(families.BiwheelGraph)
2750
+ BubbleSortGraph = staticmethod(families.BubbleSortGraph)
2751
+ CaiFurerImmermanGraph = staticmethod(families.CaiFurerImmermanGraph)
2752
+ chang_graphs = staticmethod(families.chang_graphs)
2753
+ CirculantGraph = staticmethod(families.CirculantGraph)
2754
+ cographs = staticmethod(cographs_module.cographs)
2755
+ CubeGraph = staticmethod(families.CubeGraph)
2756
+ CubeConnectedCycle = staticmethod(families.CubeConnectedCycle)
2757
+ DipoleGraph = staticmethod(families.DipoleGraph)
2758
+ distance_regular_graph = staticmethod(distance_regular.distance_regular_graph)
2759
+ DorogovtsevGoltsevMendesGraph = staticmethod(families.DorogovtsevGoltsevMendesGraph)
2760
+ DoubleGeneralizedPetersenGraph = staticmethod(families.DoubleGeneralizedPetersenGraph)
2761
+ DoubleGrassmannGraph = staticmethod(distance_regular.DoubleGrassmannGraph)
2762
+ DoubleOddGraph = staticmethod(distance_regular.DoubleOddGraph)
2763
+ EgawaGraph = staticmethod(families.EgawaGraph)
2764
+ FibonacciTree = staticmethod(families.FibonacciTree)
2765
+ FoldedCubeGraph = staticmethod(families.FoldedCubeGraph)
2766
+ FriendshipGraph = staticmethod(families.FriendshipGraph)
2767
+ FurerGadget = staticmethod(families.FurerGadget)
2768
+ FuzzyBallGraph = staticmethod(families.FuzzyBallGraph)
2769
+ GeneralisedDodecagonGraph = staticmethod(distance_regular.GeneralisedDodecagonGraph)
2770
+ GeneralisedHexagonGraph = staticmethod(distance_regular.GeneralisedHexagonGraph)
2771
+ GeneralisedOctagonGraph = staticmethod(distance_regular.GeneralisedOctagonGraph)
2772
+ GeneralizedPetersenGraph = staticmethod(families.GeneralizedPetersenGraph)
2773
+ GeneralizedSierpinskiGraph = staticmethod(families.GeneralizedSierpinskiGraph)
2774
+ GoethalsSeidelGraph = staticmethod(families.GoethalsSeidelGraph)
2775
+ GrassmannGraph = staticmethod(distance_regular.GrassmannGraph)
2776
+ HalfCube = staticmethod(distance_regular.HalfCube)
2777
+ HammingGraph = staticmethod(families.HammingGraph)
2778
+ HanoiTowerGraph = staticmethod(families.HanoiTowerGraph)
2779
+ HararyGraph = staticmethod(families.HararyGraph)
2780
+ HermitianFormsGraph = staticmethod(distance_regular.HermitianFormsGraph)
2781
+ HyperStarGraph = staticmethod(families.HyperStarGraph)
2782
+ IGraph = staticmethod(families.IGraph)
2783
+ JohnsonGraph = staticmethod(families.JohnsonGraph)
2784
+ KneserGraph = staticmethod(families.KneserGraph)
2785
+ LCFGraph = staticmethod(families.LCFGraph)
2786
+ line_graph_forbidden_subgraphs = staticmethod(families.line_graph_forbidden_subgraphs)
2787
+ LollipopGraph = staticmethod(families.LollipopGraph)
2788
+ MathonPseudocyclicMergingGraph = staticmethod(families.MathonPseudocyclicMergingGraph)
2789
+ MathonPseudocyclicStronglyRegularGraph = staticmethod(families.MathonPseudocyclicStronglyRegularGraph)
2790
+ MuzychukS6Graph = staticmethod(families.MuzychukS6Graph)
2791
+ MycielskiGraph = staticmethod(families.MycielskiGraph)
2792
+ MycielskiStep = staticmethod(families.MycielskiStep)
2793
+ NKStarGraph = staticmethod(families.NKStarGraph)
2794
+ NStarGraph = staticmethod(families.NStarGraph)
2795
+ OddGraph = staticmethod(families.OddGraph)
2796
+ PaleyGraph = staticmethod(families.PaleyGraph)
2797
+ PasechnikGraph = staticmethod(families.PasechnikGraph)
2798
+ petersen_family = staticmethod(families.petersen_family)
2799
+ RingedTree = staticmethod(families.RingedTree)
2800
+ RoseWindowGraph = staticmethod(families.RoseWindowGraph)
2801
+ SierpinskiGasketGraph = staticmethod(families.SierpinskiGasketGraph)
2802
+ SquaredSkewHadamardMatrixGraph = staticmethod(families.SquaredSkewHadamardMatrixGraph)
2803
+ SwitchedSquaredSkewHadamardMatrixGraph = staticmethod(families.SwitchedSquaredSkewHadamardMatrixGraph)
2804
+ StaircaseGraph = staticmethod(families.StaircaseGraph)
2805
+ strongly_regular_graph = staticmethod(strongly_regular_db.strongly_regular_graph)
2806
+ TabacjnGraph = staticmethod(families.TabacjnGraph)
2807
+ TadpoleGraph = staticmethod(families.TadpoleGraph)
2808
+ trees = staticmethod(families.trees)
2809
+ TruncatedBiwheelGraph = staticmethod(families.TruncatedBiwheelGraph)
2810
+ nauty_gentreeg = staticmethod(families.nauty_gentreeg)
2811
+ TuranGraph = staticmethod(families.TuranGraph)
2812
+ UstimenkoGraph = staticmethod(distance_regular.UstimenkoGraph)
2813
+ WheelGraph = staticmethod(families.WheelGraph)
2814
+ WindmillGraph = staticmethod(families.WindmillGraph)
2815
+
2816
+ ###########################################################################
2817
+ # Graphs from classical geometries over `F_q`
2818
+ ###########################################################################
2819
+ from .generators import classical_geometries
2820
+ AffineOrthogonalPolarGraph = staticmethod(classical_geometries.AffineOrthogonalPolarGraph)
2821
+ AhrensSzekeresGeneralizedQuadrangleGraph = staticmethod(classical_geometries.AhrensSzekeresGeneralizedQuadrangleGraph)
2822
+ NonisotropicOrthogonalPolarGraph = staticmethod(classical_geometries.NonisotropicOrthogonalPolarGraph)
2823
+ NonisotropicUnitaryPolarGraph = staticmethod(classical_geometries.NonisotropicUnitaryPolarGraph)
2824
+ OrthogonalDualPolarGraph = staticmethod(classical_geometries.OrthogonalDualPolarGraph)
2825
+ OrthogonalPolarGraph = staticmethod(classical_geometries.OrthogonalPolarGraph)
2826
+ SymplecticDualPolarGraph = staticmethod(classical_geometries.SymplecticDualPolarGraph)
2827
+ SymplecticPolarGraph = staticmethod(classical_geometries.SymplecticPolarGraph)
2828
+ TaylorTwographDescendantSRG = staticmethod(classical_geometries.TaylorTwographDescendantSRG)
2829
+ TaylorTwographSRG = staticmethod(classical_geometries.TaylorTwographSRG)
2830
+ T2starGeneralizedQuadrangleGraph = staticmethod(classical_geometries.T2starGeneralizedQuadrangleGraph)
2831
+ Nowhere0WordsTwoWeightCodeGraph = staticmethod(classical_geometries.Nowhere0WordsTwoWeightCodeGraph)
2832
+ HaemersGraph = staticmethod(classical_geometries.HaemersGraph)
2833
+ CossidentePenttilaGraph = staticmethod(classical_geometries.CossidentePenttilaGraph)
2834
+ UnitaryDualPolarGraph = staticmethod(classical_geometries.UnitaryDualPolarGraph)
2835
+ UnitaryPolarGraph = staticmethod(classical_geometries.UnitaryPolarGraph)
2836
+
2837
+ ###########################################################################
2838
+ # Chessboard Graphs
2839
+ ###########################################################################
2840
+ from .generators import chessboard
2841
+ ChessboardGraphGenerator = staticmethod(chessboard.ChessboardGraphGenerator)
2842
+ BishopGraph = staticmethod(chessboard.BishopGraph)
2843
+ KingGraph = staticmethod(chessboard.KingGraph)
2844
+ KnightGraph = staticmethod(chessboard.KnightGraph)
2845
+ QueenGraph = staticmethod(chessboard.QueenGraph)
2846
+ RookGraph = staticmethod(chessboard.RookGraph)
2847
+
2848
+ ###########################################################################
2849
+ # Intersection graphs
2850
+ ###########################################################################
2851
+ from .generators import intersection
2852
+ IntervalGraph = staticmethod(intersection.IntervalGraph)
2853
+ IntersectionGraph = staticmethod(intersection.IntersectionGraph)
2854
+ PermutationGraph = staticmethod(intersection.PermutationGraph)
2855
+ OrthogonalArrayBlockGraph = staticmethod(intersection.OrthogonalArrayBlockGraph)
2856
+ ToleranceGraph = staticmethod(intersection.ToleranceGraph)
2857
+
2858
+ ###########################################################################
2859
+ # Random Graphs
2860
+ ###########################################################################
2861
+ from .generators import random
2862
+ RandomBarabasiAlbert = staticmethod(random.RandomBarabasiAlbert)
2863
+ RandomBipartite = staticmethod(random.RandomBipartite)
2864
+ RandomRegularBipartite = staticmethod(random.RandomRegularBipartite)
2865
+ RandomBicubicPlanar = staticmethod(random.RandomBicubicPlanar)
2866
+ RandomBlockGraph = staticmethod(random.RandomBlockGraph)
2867
+ RandomBoundedToleranceGraph = staticmethod(random.RandomBoundedToleranceGraph)
2868
+ RandomChordalGraph = staticmethod(random.RandomChordalGraph)
2869
+ RandomGNM = staticmethod(random.RandomGNM)
2870
+ RandomGNP = staticmethod(random.RandomGNP)
2871
+ RandomHolmeKim = staticmethod(random.RandomHolmeKim)
2872
+ RandomIntervalGraph = staticmethod(random.RandomIntervalGraph)
2873
+ RandomLobster = staticmethod(random.RandomLobster)
2874
+ RandomNewmanWattsStrogatz = staticmethod(random.RandomNewmanWattsStrogatz)
2875
+ RandomProperIntervalGraph = staticmethod(random.RandomProperIntervalGraph)
2876
+ RandomRegular = staticmethod(random.RandomRegular)
2877
+ RandomShell = staticmethod(random.RandomShell)
2878
+ RandomKTree = staticmethod(random.RandomKTree)
2879
+ RandomPartialKTree = staticmethod(random.RandomPartialKTree)
2880
+ RandomToleranceGraph = staticmethod(random.RandomToleranceGraph)
2881
+ RandomTreePowerlaw = staticmethod(random.RandomTreePowerlaw)
2882
+ RandomTree = staticmethod(random.RandomTree)
2883
+ RandomTriangulation = staticmethod(random.RandomTriangulation)
2884
+ RandomUnitDiskGraph = staticmethod(random.RandomUnitDiskGraph)
2885
+
2886
+ ###########################################################################
2887
+ # Maps
2888
+ ###########################################################################
2889
+ from .generators import world_map
2890
+ WorldMap = staticmethod(world_map.WorldMap)
2891
+ EuropeMap = staticmethod(world_map.EuropeMap)
2892
+ AfricaMap = staticmethod(world_map.AfricaMap)
2893
+ USAMap = staticmethod(world_map.USAMap)
2894
+
2895
+ ###########################################################################
2896
+ # Degree Sequence
2897
+ ###########################################################################
2898
+ from .generators import degree_sequence
2899
+ DegreeSequence = staticmethod(degree_sequence.DegreeSequence)
2900
+ DegreeSequenceBipartite = staticmethod(degree_sequence.DegreeSequenceBipartite)
2901
+ DegreeSequenceConfigurationModel = staticmethod(degree_sequence.DegreeSequenceConfigurationModel)
2902
+ DegreeSequenceTree = staticmethod(degree_sequence.DegreeSequenceTree)
2903
+ DegreeSequenceExpected = staticmethod(degree_sequence.DegreeSequenceExpected)
2904
+
2905
+
2906
+ def canaug_traverse_vert(g, aut_gens, max_verts, property, dig=False, loops=False, sparse=True):
2907
+ """
2908
+ Main function for exhaustive generation. Recursive traversal of a
2909
+ canonically generated tree of isomorph free (di)graphs satisfying a
2910
+ given property.
2911
+
2912
+ INPUT:
2913
+
2914
+ - ``g`` -- current position on the tree
2915
+
2916
+ - ``aut_gens`` -- list of generators of Aut(g), in list notation
2917
+
2918
+ - ``max_verts`` -- when to retreat
2919
+
2920
+ - ``property`` -- check before traversing below g
2921
+
2922
+ - ``degree_sequence`` -- specify a degree sequence to try to obtain
2923
+
2924
+ EXAMPLES::
2925
+
2926
+ sage: from sage.graphs.graph_generators import canaug_traverse_vert
2927
+ sage: list(canaug_traverse_vert(Graph(), [], 3, lambda x: True))
2928
+ [Graph on 0 vertices, ... Graph on 3 vertices]
2929
+
2930
+ The best way to access this function is through the graphs()
2931
+ iterator:
2932
+
2933
+ Print graphs on 3 or less vertices.
2934
+
2935
+ ::
2936
+
2937
+ sage: for G in graphs(3, augment='vertices'):
2938
+ ....: print(G)
2939
+ Graph on 0 vertices
2940
+ Graph on 1 vertex
2941
+ Graph on 2 vertices
2942
+ Graph on 3 vertices
2943
+ Graph on 3 vertices
2944
+ Graph on 3 vertices
2945
+ Graph on 2 vertices
2946
+ Graph on 3 vertices
2947
+
2948
+ Print digraphs on 2 or less vertices.
2949
+
2950
+ ::
2951
+
2952
+ sage: for D in digraphs(2, augment='vertices'):
2953
+ ....: print(D)
2954
+ Digraph on 0 vertices
2955
+ Digraph on 1 vertex
2956
+ Digraph on 2 vertices
2957
+ Digraph on 2 vertices
2958
+ Digraph on 2 vertices
2959
+ """
2960
+ from sage.groups.perm_gps.partn_ref.refinement_graphs import search_tree
2961
+ if not property(g):
2962
+ return
2963
+ yield g
2964
+
2965
+ n = g.order()
2966
+ if n < max_verts:
2967
+
2968
+ # build a list representing C(g) - the vertex to be added
2969
+ # is at the end, so only specify which edges...
2970
+ # in the case of graphs, there are n possibilities,
2971
+ # and in the case of digraphs, there are 2*n.
2972
+ if dig:
2973
+ possibilities = 2*n
2974
+ else:
2975
+ possibilities = n
2976
+ num_roots = 2**possibilities
2977
+ children = [-1]*num_roots
2978
+
2979
+ # union-find C(g) under Aut(g)
2980
+ for gen in aut_gens:
2981
+ for i in range(len(children)):
2982
+ k = 0
2983
+ for j in range(possibilities):
2984
+ if (1 << j) & i:
2985
+ if dig and j >= n:
2986
+ k += (1 << (gen[j - n] + n))
2987
+ else:
2988
+ k += (1 << gen[j])
2989
+ while children[k] != -1:
2990
+ k = children[k]
2991
+ while children[i] != -1:
2992
+ i = children[i]
2993
+ if i != k:
2994
+ # union i & k
2995
+ smaller, larger = sorted([i, k])
2996
+ children[larger] = smaller
2997
+ num_roots -= 1
2998
+
2999
+ # find representatives of orbits of C(g)
3000
+ roots = []
3001
+ found_roots = 0
3002
+ i = 0
3003
+ while found_roots < num_roots:
3004
+ if children[i] == -1:
3005
+ found_roots += 1
3006
+ roots.append(i)
3007
+ i += 1
3008
+ for i in roots:
3009
+ # construct a z for each number in roots...
3010
+ z = g.copy(sparse=sparse)
3011
+ z.add_vertex(n)
3012
+ edges = []
3013
+ if dig:
3014
+ index = 0
3015
+ while 2 * index < possibilities:
3016
+ if (1 << index) & i:
3017
+ edges.append((index, n))
3018
+ index += 1
3019
+ while index < possibilities:
3020
+ if (1 << index) & i:
3021
+ edges.append((n, index - n))
3022
+ index += 1
3023
+ else:
3024
+ index = 0
3025
+ while (1 << index) <= i:
3026
+ if (1 << index) & i:
3027
+ edges.append((index, n))
3028
+ index += 1
3029
+ z.add_edges(edges)
3030
+ z_s = []
3031
+ if property(z):
3032
+ z_s.append(z)
3033
+ if loops:
3034
+ z = z.copy(sparse=sparse)
3035
+ z.add_edge((n, n))
3036
+ if property(z):
3037
+ z_s.append(z)
3038
+ for z in z_s:
3039
+ z_aut_gens, _, canonical_relabeling = search_tree(z, [z.vertices(sort=True)], certificate=True, dig=(dig or loops))
3040
+ cut_vert = 0
3041
+ while canonical_relabeling[cut_vert] != n:
3042
+ cut_vert += 1
3043
+ sub_verts = [v for v in z if v != cut_vert]
3044
+ m_z = z.subgraph(sub_verts)
3045
+
3046
+ if m_z == g:
3047
+ for a in canaug_traverse_vert(z, z_aut_gens, max_verts, property, dig=dig, loops=loops, sparse=sparse):
3048
+ yield a
3049
+ else:
3050
+ for possibility in check_aut(z_aut_gens, cut_vert, n):
3051
+ if m_z.relabel(dict(enumerate(possibility)), check_input=False, inplace=False) == g:
3052
+ for a in canaug_traverse_vert(z, z_aut_gens, max_verts, property, dig=dig, loops=loops, sparse=sparse):
3053
+ yield a
3054
+ break
3055
+
3056
+
3057
+ def check_aut(aut_gens, cut_vert, n):
3058
+ """
3059
+ Helper function for exhaustive generation.
3060
+
3061
+ At the start, check_aut is given a set of generators for the
3062
+ automorphism group, aut_gens. We already know we are looking for
3063
+ an element of the auto- morphism group that sends cut_vert to n,
3064
+ and check_aut generates these for the canaug_traverse function.
3065
+
3066
+ EXAMPLES:
3067
+
3068
+ Note that the last two entries indicate that none of the
3069
+ automorphism group has yet been searched - we are starting at the
3070
+ identity [0, 1, 2, 3] and so far that is all we have seen. We
3071
+ return automorphisms mapping 2 to 3::
3072
+
3073
+ sage: from sage.graphs.graph_generators import check_aut
3074
+ sage: list( check_aut( [ [0, 3, 2, 1], [1, 0, 3, 2], [2, 1, 0, 3] ], 2, 3))
3075
+ [[1, 0, 3, 2], [1, 2, 3, 0]]
3076
+ """
3077
+ from copy import copy
3078
+ perm = list(range(n + 1))
3079
+ seen_perms = [perm]
3080
+ unchecked_perms = [perm]
3081
+ while unchecked_perms:
3082
+ perm = unchecked_perms.pop(0)
3083
+ for gen in aut_gens:
3084
+ new_perm = copy(perm)
3085
+ for i in range(len(perm)):
3086
+ new_perm[i] = gen[perm[i]]
3087
+ if new_perm not in seen_perms:
3088
+ seen_perms.append(new_perm)
3089
+ unchecked_perms.append(new_perm)
3090
+ if new_perm[cut_vert] == n:
3091
+ yield new_perm
3092
+
3093
+
3094
+ def canaug_traverse_edge(g, aut_gens, property, dig=False, loops=False, sparse=True):
3095
+ """
3096
+ Main function for exhaustive generation. Recursive traversal of a
3097
+ canonically generated tree of isomorph free graphs satisfying a
3098
+ given property.
3099
+
3100
+ INPUT:
3101
+
3102
+ - ``g`` -- current position on the tree
3103
+
3104
+ - ``aut_gens`` -- list of generators of Aut(g), in list notation
3105
+
3106
+ - ``property`` -- check before traversing below g
3107
+
3108
+ EXAMPLES::
3109
+
3110
+ sage: from sage.graphs.graph_generators import canaug_traverse_edge
3111
+ sage: G = Graph(3)
3112
+ sage: list(canaug_traverse_edge(G, [], lambda x: True))
3113
+ [Graph on 3 vertices, ... Graph on 3 vertices]
3114
+
3115
+ The best way to access this function is through the graphs()
3116
+ iterator:
3117
+
3118
+ Print graphs on 3 or less vertices.
3119
+
3120
+ ::
3121
+
3122
+ sage: for G in graphs(3): # needs nauty
3123
+ ....: print(G)
3124
+ Graph on 3 vertices
3125
+ Graph on 3 vertices
3126
+ Graph on 3 vertices
3127
+ Graph on 3 vertices
3128
+
3129
+ Print digraphs on 3 or less vertices.
3130
+
3131
+ ::
3132
+
3133
+ sage: for G in digraphs(3): # needs nauty
3134
+ ....: print(G)
3135
+ Digraph on 3 vertices
3136
+ Digraph on 3 vertices
3137
+ ...
3138
+ Digraph on 3 vertices
3139
+ Digraph on 3 vertices
3140
+ """
3141
+ from sage.groups.perm_gps.partn_ref.refinement_graphs import search_tree
3142
+
3143
+ if not property(g):
3144
+ return
3145
+ yield g
3146
+ n = g.order()
3147
+ if dig:
3148
+ max_size = n * (n - 1)
3149
+ else:
3150
+ max_size = (n * (n - 1)) >> 1 # >> 1 is just / 2 (this is n choose 2)
3151
+ if loops:
3152
+ max_size += n
3153
+ if g.size() < max_size:
3154
+ # build a list representing C(g) - the edge to be added
3155
+ # is one of max_size choices
3156
+ if dig:
3157
+ children = [[(j, i) for i in range(n)] for j in range(n)]
3158
+ else:
3159
+ children = [[(j, i) for i in range(j)] for j in range(n)]
3160
+ # union-find C(g) under Aut(g)
3161
+ orbits = list(range(n))
3162
+ for gen in aut_gens:
3163
+ for iii in range(n):
3164
+ if orbits[gen[iii]] != orbits[iii]:
3165
+ temp = orbits[gen[iii]]
3166
+ for jjj in range(n):
3167
+ if orbits[jjj] == temp:
3168
+ orbits[jjj] = orbits[iii]
3169
+ if dig:
3170
+ jjj_range = list(range(iii)) + list(range(iii + 1, n))
3171
+ else:
3172
+ jjj_range = list(range(iii)) # iii > jjj
3173
+ for jjj in jjj_range:
3174
+ i, j = iii, jjj
3175
+ if dig:
3176
+ x, y = gen[i], gen[j]
3177
+ else:
3178
+ y, x = sorted([gen[i], gen[j]])
3179
+ if children[i][j] != children[x][y]:
3180
+ x_val, y_val = x, y
3181
+ i_val, j_val = i, j
3182
+ if dig:
3183
+ while (x_val, y_val) != children[x_val][y_val]:
3184
+ x_val, y_val = children[x_val][y_val]
3185
+ while (i_val, j_val) != children[i_val][j_val]:
3186
+ i_val, j_val = children[i_val][j_val]
3187
+ else:
3188
+ while (x_val, y_val) != children[x_val][y_val]:
3189
+ y_val, x_val = sorted(children[x_val][y_val])
3190
+ while (i_val, j_val) != children[i_val][j_val]:
3191
+ j_val, i_val = sorted(children[i_val][j_val])
3192
+ while (x, y) != (x_val, y_val):
3193
+ xx, yy = x, y
3194
+ x, y = children[x][y]
3195
+ children[xx][yy] = (x_val, y_val)
3196
+ while (i, j) != (i_val, j_val):
3197
+ ii, jj = i, j
3198
+ i, j = children[i][j]
3199
+ children[ii][jj] = (i_val, j_val)
3200
+ if x < i:
3201
+ children[i][j] = (x, y)
3202
+ elif x > i:
3203
+ children[x][y] = (i, j)
3204
+ elif y < j:
3205
+ children[i][j] = (x, y)
3206
+ elif y > j:
3207
+ children[x][y] = (i, j)
3208
+ else:
3209
+ continue
3210
+ # find representatives of orbits of C(g)
3211
+ roots = []
3212
+ for i in range(n):
3213
+ if dig:
3214
+ j_range = list(range(i)) + list(range(i + 1, n))
3215
+ else:
3216
+ j_range = list(range(i))
3217
+ for j in j_range:
3218
+ if children[i][j] == (i, j):
3219
+ roots.append((i, j))
3220
+ if loops:
3221
+ seen = []
3222
+ for i in range(n):
3223
+ if orbits[i] not in seen:
3224
+ roots.append((i, i))
3225
+ seen.append(orbits[i])
3226
+ for i, j in roots:
3227
+ if g.has_edge(i, j):
3228
+ continue
3229
+ # construct a z for each edge in roots...
3230
+ z = g.copy(sparse=sparse)
3231
+ z.add_edge(i, j)
3232
+ if not property(z):
3233
+ continue
3234
+ z_aut_gens, _, canonical_relabeling = search_tree(z, [z.vertices(sort=True)], certificate=True, dig=(dig or loops))
3235
+ relabel_inverse = [0]*n
3236
+ for ii in range(n):
3237
+ relabel_inverse[canonical_relabeling[ii]] = ii
3238
+ z_can = z.relabel(canonical_relabeling, inplace=False)
3239
+ cut_edge_can = z_can.edges(labels=False, sort=True)[-1]
3240
+ cut_edge = [relabel_inverse[cut_edge_can[0]], relabel_inverse[cut_edge_can[1]]]
3241
+ if dig:
3242
+ cut_edge = tuple(cut_edge)
3243
+ else:
3244
+ cut_edge = tuple(sorted(cut_edge))
3245
+
3246
+ from copy import copy
3247
+ m_z = copy(z)
3248
+ m_z.delete_edge(cut_edge)
3249
+ if m_z == g:
3250
+ for a in canaug_traverse_edge(z, z_aut_gens, property, dig=dig, loops=loops, sparse=sparse):
3251
+ yield a
3252
+ else:
3253
+ for possibility in check_aut_edge(z_aut_gens, cut_edge, i, j, n, dig=dig):
3254
+ if m_z.relabel(possibility, inplace=False) == g:
3255
+ for a in canaug_traverse_edge(z, z_aut_gens, property, dig=dig, loops=loops, sparse=sparse):
3256
+ yield a
3257
+ break
3258
+
3259
+
3260
+ def check_aut_edge(aut_gens, cut_edge, i, j, n, dig=False):
3261
+ """
3262
+ Helper function for exhaustive generation.
3263
+
3264
+ At the start, check_aut_edge is given a set of generators for the
3265
+ automorphism group, aut_gens. We already know we are looking for
3266
+ an element of the auto- morphism group that sends cut_edge to {i,
3267
+ j}, and check_aut generates these for the canaug_traverse
3268
+ function.
3269
+
3270
+ EXAMPLES:
3271
+
3272
+ Note that the last two entries indicate that none of the
3273
+ automorphism group has yet been searched - we are starting at the
3274
+ identity [0, 1, 2, 3] and so far that is all we have seen. We
3275
+ return automorphisms mapping 2 to 3::
3276
+
3277
+ sage: from sage.graphs.graph_generators import check_aut
3278
+ sage: list( check_aut( [ [0, 3, 2, 1], [1, 0, 3, 2], [2, 1, 0, 3] ], 2, 3))
3279
+ [[1, 0, 3, 2], [1, 2, 3, 0]]
3280
+ """
3281
+ from copy import copy
3282
+ perm = list(range(n))
3283
+ seen_perms = [perm]
3284
+ unchecked_perms = [perm]
3285
+ while unchecked_perms:
3286
+ perm = unchecked_perms.pop(0)
3287
+ for gen in aut_gens:
3288
+ new_perm = copy(perm)
3289
+ for ii in range(n):
3290
+ new_perm[ii] = gen[perm[ii]]
3291
+ if new_perm not in seen_perms:
3292
+ seen_perms.append(new_perm)
3293
+ unchecked_perms.append(new_perm)
3294
+ if new_perm[cut_edge[0]] == i and new_perm[cut_edge[1]] == j:
3295
+ yield new_perm
3296
+ if not dig and new_perm[cut_edge[0]] == j and new_perm[cut_edge[1]] == i:
3297
+ yield new_perm
3298
+
3299
+
3300
+ # Easy access to the graph generators from the command line:
3301
+ graphs = GraphGenerators()