passagemath-graphs 10.6.1rc1__cp310-cp310-musllinux_1_2_aarch64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (260) hide show
  1. passagemath_graphs-10.6.1rc1.dist-info/METADATA +292 -0
  2. passagemath_graphs-10.6.1rc1.dist-info/RECORD +260 -0
  3. passagemath_graphs-10.6.1rc1.dist-info/WHEEL +5 -0
  4. passagemath_graphs-10.6.1rc1.dist-info/top_level.txt +2 -0
  5. passagemath_graphs.libs/libgcc_s-69c45f16.so.1 +0 -0
  6. passagemath_graphs.libs/libgmp-8e78bd9b.so.10.5.0 +0 -0
  7. passagemath_graphs.libs/libstdc++-1f1a71be.so.6.0.33 +0 -0
  8. sage/all__sagemath_graphs.py +39 -0
  9. sage/combinat/abstract_tree.py +2723 -0
  10. sage/combinat/all__sagemath_graphs.py +34 -0
  11. sage/combinat/binary_tree.py +5306 -0
  12. sage/combinat/cluster_algebra_quiver/all.py +22 -0
  13. sage/combinat/cluster_algebra_quiver/cluster_seed.py +5208 -0
  14. sage/combinat/cluster_algebra_quiver/interact.py +124 -0
  15. sage/combinat/cluster_algebra_quiver/mutation_class.py +625 -0
  16. sage/combinat/cluster_algebra_quiver/mutation_type.py +1555 -0
  17. sage/combinat/cluster_algebra_quiver/quiver.py +2290 -0
  18. sage/combinat/cluster_algebra_quiver/quiver_mutation_type.py +2468 -0
  19. sage/combinat/designs/MOLS_handbook_data.py +570 -0
  20. sage/combinat/designs/all.py +58 -0
  21. sage/combinat/designs/bibd.py +1655 -0
  22. sage/combinat/designs/block_design.py +1071 -0
  23. sage/combinat/designs/covering_array.py +269 -0
  24. sage/combinat/designs/covering_design.py +530 -0
  25. sage/combinat/designs/database.py +5615 -0
  26. sage/combinat/designs/design_catalog.py +122 -0
  27. sage/combinat/designs/designs_pyx.cpython-310-aarch64-linux-gnu.so +0 -0
  28. sage/combinat/designs/designs_pyx.pxd +21 -0
  29. sage/combinat/designs/designs_pyx.pyx +993 -0
  30. sage/combinat/designs/difference_family.py +3951 -0
  31. sage/combinat/designs/difference_matrices.py +279 -0
  32. sage/combinat/designs/evenly_distributed_sets.cpython-310-aarch64-linux-gnu.so +0 -0
  33. sage/combinat/designs/evenly_distributed_sets.pyx +661 -0
  34. sage/combinat/designs/ext_rep.py +1064 -0
  35. sage/combinat/designs/gen_quadrangles_with_spread.cpython-310-aarch64-linux-gnu.so +0 -0
  36. sage/combinat/designs/gen_quadrangles_with_spread.pyx +339 -0
  37. sage/combinat/designs/group_divisible_designs.py +361 -0
  38. sage/combinat/designs/incidence_structures.py +2357 -0
  39. sage/combinat/designs/latin_squares.py +581 -0
  40. sage/combinat/designs/orthogonal_arrays.py +2244 -0
  41. sage/combinat/designs/orthogonal_arrays_build_recursive.py +1780 -0
  42. sage/combinat/designs/orthogonal_arrays_find_recursive.cpython-310-aarch64-linux-gnu.so +0 -0
  43. sage/combinat/designs/orthogonal_arrays_find_recursive.pyx +967 -0
  44. sage/combinat/designs/resolvable_bibd.py +815 -0
  45. sage/combinat/designs/steiner_quadruple_systems.py +1306 -0
  46. sage/combinat/designs/subhypergraph_search.cpython-310-aarch64-linux-gnu.so +0 -0
  47. sage/combinat/designs/subhypergraph_search.pyx +530 -0
  48. sage/combinat/designs/twographs.py +306 -0
  49. sage/combinat/finite_state_machine.py +14874 -0
  50. sage/combinat/finite_state_machine_generators.py +2006 -0
  51. sage/combinat/graph_path.py +448 -0
  52. sage/combinat/interval_posets.py +3908 -0
  53. sage/combinat/nu_tamari_lattice.py +269 -0
  54. sage/combinat/ordered_tree.py +1446 -0
  55. sage/combinat/posets/all.py +46 -0
  56. sage/combinat/posets/bubble_shuffle.py +247 -0
  57. sage/combinat/posets/cartesian_product.py +493 -0
  58. sage/combinat/posets/d_complete.py +182 -0
  59. sage/combinat/posets/elements.py +273 -0
  60. sage/combinat/posets/forest.py +30 -0
  61. sage/combinat/posets/hasse_cython.cpython-310-aarch64-linux-gnu.so +0 -0
  62. sage/combinat/posets/hasse_cython.pyx +174 -0
  63. sage/combinat/posets/hasse_diagram.py +3672 -0
  64. sage/combinat/posets/hochschild_lattice.py +158 -0
  65. sage/combinat/posets/incidence_algebras.py +794 -0
  66. sage/combinat/posets/lattices.py +5117 -0
  67. sage/combinat/posets/linear_extension_iterator.cpython-310-aarch64-linux-gnu.so +0 -0
  68. sage/combinat/posets/linear_extension_iterator.pyx +292 -0
  69. sage/combinat/posets/linear_extensions.py +1037 -0
  70. sage/combinat/posets/mobile.py +275 -0
  71. sage/combinat/posets/moebius_algebra.py +776 -0
  72. sage/combinat/posets/poset_examples.py +2178 -0
  73. sage/combinat/posets/posets.py +9360 -0
  74. sage/combinat/rooted_tree.py +1070 -0
  75. sage/combinat/shard_order.py +239 -0
  76. sage/combinat/tamari_lattices.py +384 -0
  77. sage/combinat/yang_baxter_graph.py +923 -0
  78. sage/databases/all__sagemath_graphs.py +1 -0
  79. sage/databases/knotinfo_db.py +1231 -0
  80. sage/ext_data/all__sagemath_graphs.py +1 -0
  81. sage/ext_data/graphs/graph_plot_js.html +330 -0
  82. sage/ext_data/kenzo/CP2.txt +45 -0
  83. sage/ext_data/kenzo/CP3.txt +349 -0
  84. sage/ext_data/kenzo/CP4.txt +4774 -0
  85. sage/ext_data/kenzo/README.txt +49 -0
  86. sage/ext_data/kenzo/S4.txt +20 -0
  87. sage/graphs/all.py +42 -0
  88. sage/graphs/asteroidal_triples.cpython-310-aarch64-linux-gnu.so +0 -0
  89. sage/graphs/asteroidal_triples.pyx +320 -0
  90. sage/graphs/base/all.py +1 -0
  91. sage/graphs/base/boost_graph.cpython-310-aarch64-linux-gnu.so +0 -0
  92. sage/graphs/base/boost_graph.pxd +106 -0
  93. sage/graphs/base/boost_graph.pyx +3045 -0
  94. sage/graphs/base/c_graph.cpython-310-aarch64-linux-gnu.so +0 -0
  95. sage/graphs/base/c_graph.pxd +106 -0
  96. sage/graphs/base/c_graph.pyx +5096 -0
  97. sage/graphs/base/dense_graph.cpython-310-aarch64-linux-gnu.so +0 -0
  98. sage/graphs/base/dense_graph.pxd +28 -0
  99. sage/graphs/base/dense_graph.pyx +801 -0
  100. sage/graphs/base/graph_backends.cpython-310-aarch64-linux-gnu.so +0 -0
  101. sage/graphs/base/graph_backends.pxd +5 -0
  102. sage/graphs/base/graph_backends.pyx +797 -0
  103. sage/graphs/base/overview.py +85 -0
  104. sage/graphs/base/sparse_graph.cpython-310-aarch64-linux-gnu.so +0 -0
  105. sage/graphs/base/sparse_graph.pxd +90 -0
  106. sage/graphs/base/sparse_graph.pyx +1653 -0
  107. sage/graphs/base/static_dense_graph.cpython-310-aarch64-linux-gnu.so +0 -0
  108. sage/graphs/base/static_dense_graph.pxd +5 -0
  109. sage/graphs/base/static_dense_graph.pyx +1032 -0
  110. sage/graphs/base/static_sparse_backend.cpython-310-aarch64-linux-gnu.so +0 -0
  111. sage/graphs/base/static_sparse_backend.pxd +27 -0
  112. sage/graphs/base/static_sparse_backend.pyx +1583 -0
  113. sage/graphs/base/static_sparse_graph.cpython-310-aarch64-linux-gnu.so +0 -0
  114. sage/graphs/base/static_sparse_graph.pxd +37 -0
  115. sage/graphs/base/static_sparse_graph.pyx +1375 -0
  116. sage/graphs/bipartite_graph.py +2732 -0
  117. sage/graphs/centrality.cpython-310-aarch64-linux-gnu.so +0 -0
  118. sage/graphs/centrality.pyx +1038 -0
  119. sage/graphs/cographs.py +519 -0
  120. sage/graphs/comparability.cpython-310-aarch64-linux-gnu.so +0 -0
  121. sage/graphs/comparability.pyx +851 -0
  122. sage/graphs/connectivity.cpython-310-aarch64-linux-gnu.so +0 -0
  123. sage/graphs/connectivity.pxd +157 -0
  124. sage/graphs/connectivity.pyx +4813 -0
  125. sage/graphs/convexity_properties.cpython-310-aarch64-linux-gnu.so +0 -0
  126. sage/graphs/convexity_properties.pxd +16 -0
  127. sage/graphs/convexity_properties.pyx +870 -0
  128. sage/graphs/digraph.py +4754 -0
  129. sage/graphs/digraph_generators.py +1993 -0
  130. sage/graphs/distances_all_pairs.cpython-310-aarch64-linux-gnu.so +0 -0
  131. sage/graphs/distances_all_pairs.pxd +12 -0
  132. sage/graphs/distances_all_pairs.pyx +2938 -0
  133. sage/graphs/domination.py +1363 -0
  134. sage/graphs/dot2tex_utils.py +100 -0
  135. sage/graphs/edge_connectivity.cpython-310-aarch64-linux-gnu.so +0 -0
  136. sage/graphs/edge_connectivity.pyx +1215 -0
  137. sage/graphs/generators/all.py +1 -0
  138. sage/graphs/generators/basic.py +1769 -0
  139. sage/graphs/generators/chessboard.py +538 -0
  140. sage/graphs/generators/classical_geometries.py +1611 -0
  141. sage/graphs/generators/degree_sequence.py +235 -0
  142. sage/graphs/generators/distance_regular.cpython-310-aarch64-linux-gnu.so +0 -0
  143. sage/graphs/generators/distance_regular.pyx +2846 -0
  144. sage/graphs/generators/families.py +4759 -0
  145. sage/graphs/generators/intersection.py +565 -0
  146. sage/graphs/generators/platonic_solids.py +262 -0
  147. sage/graphs/generators/random.py +2623 -0
  148. sage/graphs/generators/smallgraphs.py +5741 -0
  149. sage/graphs/generators/world_map.py +724 -0
  150. sage/graphs/generic_graph.py +26867 -0
  151. sage/graphs/generic_graph_pyx.cpython-310-aarch64-linux-gnu.so +0 -0
  152. sage/graphs/generic_graph_pyx.pxd +34 -0
  153. sage/graphs/generic_graph_pyx.pyx +1673 -0
  154. sage/graphs/genus.cpython-310-aarch64-linux-gnu.so +0 -0
  155. sage/graphs/genus.pyx +622 -0
  156. sage/graphs/graph.py +9645 -0
  157. sage/graphs/graph_coloring.cpython-310-aarch64-linux-gnu.so +0 -0
  158. sage/graphs/graph_coloring.pyx +2284 -0
  159. sage/graphs/graph_database.py +1177 -0
  160. sage/graphs/graph_decompositions/all.py +1 -0
  161. sage/graphs/graph_decompositions/bandwidth.cpython-310-aarch64-linux-gnu.so +0 -0
  162. sage/graphs/graph_decompositions/bandwidth.pyx +428 -0
  163. sage/graphs/graph_decompositions/clique_separators.cpython-310-aarch64-linux-gnu.so +0 -0
  164. sage/graphs/graph_decompositions/clique_separators.pyx +616 -0
  165. sage/graphs/graph_decompositions/cutwidth.cpython-310-aarch64-linux-gnu.so +0 -0
  166. sage/graphs/graph_decompositions/cutwidth.pyx +753 -0
  167. sage/graphs/graph_decompositions/fast_digraph.cpython-310-aarch64-linux-gnu.so +0 -0
  168. sage/graphs/graph_decompositions/fast_digraph.pxd +13 -0
  169. sage/graphs/graph_decompositions/fast_digraph.pyx +212 -0
  170. sage/graphs/graph_decompositions/graph_products.cpython-310-aarch64-linux-gnu.so +0 -0
  171. sage/graphs/graph_decompositions/graph_products.pyx +508 -0
  172. sage/graphs/graph_decompositions/modular_decomposition.cpython-310-aarch64-linux-gnu.so +0 -0
  173. sage/graphs/graph_decompositions/modular_decomposition.pxd +27 -0
  174. sage/graphs/graph_decompositions/modular_decomposition.pyx +1536 -0
  175. sage/graphs/graph_decompositions/slice_decomposition.cpython-310-aarch64-linux-gnu.so +0 -0
  176. sage/graphs/graph_decompositions/slice_decomposition.pxd +18 -0
  177. sage/graphs/graph_decompositions/slice_decomposition.pyx +1106 -0
  178. sage/graphs/graph_decompositions/tree_decomposition.cpython-310-aarch64-linux-gnu.so +0 -0
  179. sage/graphs/graph_decompositions/tree_decomposition.pxd +17 -0
  180. sage/graphs/graph_decompositions/tree_decomposition.pyx +1996 -0
  181. sage/graphs/graph_decompositions/vertex_separation.cpython-310-aarch64-linux-gnu.so +0 -0
  182. sage/graphs/graph_decompositions/vertex_separation.pxd +5 -0
  183. sage/graphs/graph_decompositions/vertex_separation.pyx +1963 -0
  184. sage/graphs/graph_editor.py +82 -0
  185. sage/graphs/graph_generators.py +3314 -0
  186. sage/graphs/graph_generators_pyx.cpython-310-aarch64-linux-gnu.so +0 -0
  187. sage/graphs/graph_generators_pyx.pyx +95 -0
  188. sage/graphs/graph_input.py +812 -0
  189. sage/graphs/graph_latex.py +2064 -0
  190. sage/graphs/graph_list.py +410 -0
  191. sage/graphs/graph_plot.py +1756 -0
  192. sage/graphs/graph_plot_js.py +338 -0
  193. sage/graphs/hyperbolicity.cpython-310-aarch64-linux-gnu.so +0 -0
  194. sage/graphs/hyperbolicity.pyx +1704 -0
  195. sage/graphs/hypergraph_generators.py +364 -0
  196. sage/graphs/independent_sets.cpython-310-aarch64-linux-gnu.so +0 -0
  197. sage/graphs/independent_sets.pxd +13 -0
  198. sage/graphs/independent_sets.pyx +402 -0
  199. sage/graphs/isgci.py +1033 -0
  200. sage/graphs/isoperimetric_inequalities.cpython-310-aarch64-linux-gnu.so +0 -0
  201. sage/graphs/isoperimetric_inequalities.pyx +489 -0
  202. sage/graphs/line_graph.cpython-310-aarch64-linux-gnu.so +0 -0
  203. sage/graphs/line_graph.pyx +743 -0
  204. sage/graphs/lovasz_theta.py +77 -0
  205. sage/graphs/matching.py +1633 -0
  206. sage/graphs/matching_covered_graph.py +3590 -0
  207. sage/graphs/orientations.py +1489 -0
  208. sage/graphs/partial_cube.py +459 -0
  209. sage/graphs/path_enumeration.cpython-310-aarch64-linux-gnu.so +0 -0
  210. sage/graphs/path_enumeration.pyx +2040 -0
  211. sage/graphs/pq_trees.py +1129 -0
  212. sage/graphs/print_graphs.py +201 -0
  213. sage/graphs/schnyder.py +865 -0
  214. sage/graphs/spanning_tree.cpython-310-aarch64-linux-gnu.so +0 -0
  215. sage/graphs/spanning_tree.pyx +1457 -0
  216. sage/graphs/strongly_regular_db.cpython-310-aarch64-linux-gnu.so +0 -0
  217. sage/graphs/strongly_regular_db.pyx +3340 -0
  218. sage/graphs/traversals.cpython-310-aarch64-linux-gnu.so +0 -0
  219. sage/graphs/traversals.pxd +9 -0
  220. sage/graphs/traversals.pyx +1872 -0
  221. sage/graphs/trees.cpython-310-aarch64-linux-gnu.so +0 -0
  222. sage/graphs/trees.pxd +15 -0
  223. sage/graphs/trees.pyx +310 -0
  224. sage/graphs/tutte_polynomial.py +713 -0
  225. sage/graphs/views.cpython-310-aarch64-linux-gnu.so +0 -0
  226. sage/graphs/views.pyx +794 -0
  227. sage/graphs/weakly_chordal.cpython-310-aarch64-linux-gnu.so +0 -0
  228. sage/graphs/weakly_chordal.pyx +604 -0
  229. sage/groups/all__sagemath_graphs.py +1 -0
  230. sage/groups/perm_gps/all__sagemath_graphs.py +1 -0
  231. sage/groups/perm_gps/partn_ref/all__sagemath_graphs.py +1 -0
  232. sage/groups/perm_gps/partn_ref/refinement_graphs.cpython-310-aarch64-linux-gnu.so +0 -0
  233. sage/groups/perm_gps/partn_ref/refinement_graphs.pxd +38 -0
  234. sage/groups/perm_gps/partn_ref/refinement_graphs.pyx +1666 -0
  235. sage/knots/all.py +6 -0
  236. sage/knots/free_knotinfo_monoid.py +507 -0
  237. sage/knots/gauss_code.py +291 -0
  238. sage/knots/knot.py +682 -0
  239. sage/knots/knot_table.py +284 -0
  240. sage/knots/knotinfo.py +2900 -0
  241. sage/knots/link.py +4715 -0
  242. sage/sandpiles/all.py +13 -0
  243. sage/sandpiles/examples.py +225 -0
  244. sage/sandpiles/sandpile.py +6365 -0
  245. sage/topology/all.py +22 -0
  246. sage/topology/cell_complex.py +1214 -0
  247. sage/topology/cubical_complex.py +1976 -0
  248. sage/topology/delta_complex.py +1806 -0
  249. sage/topology/filtered_simplicial_complex.py +744 -0
  250. sage/topology/moment_angle_complex.py +823 -0
  251. sage/topology/simplicial_complex.py +5160 -0
  252. sage/topology/simplicial_complex_catalog.py +92 -0
  253. sage/topology/simplicial_complex_examples.py +1680 -0
  254. sage/topology/simplicial_complex_homset.py +205 -0
  255. sage/topology/simplicial_complex_morphism.py +836 -0
  256. sage/topology/simplicial_set.py +4102 -0
  257. sage/topology/simplicial_set_catalog.py +55 -0
  258. sage/topology/simplicial_set_constructions.py +2954 -0
  259. sage/topology/simplicial_set_examples.py +865 -0
  260. sage/topology/simplicial_set_morphism.py +1464 -0
@@ -0,0 +1,3314 @@
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 bipartite 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 binary 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 binary 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 binary
1548
+ file in memory and reads it using the ``_read_planar_code`` method::
1549
+
1550
+ sage: from io import BytesIO
1551
+ sage: code_input = BytesIO()
1552
+ sage: n = code_input.write(b'>>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
+ ....: n = code_input.write(bytes('{:c}'.format(c),'ascii'))
1555
+ sage: n = code_input.seek(0)
1556
+ sage: gen = graphs._read_planar_code(code_input)
1557
+ sage: l = list(gen); l
1558
+ [Graph on 4 vertices]
1559
+ sage: l[0].is_isomorphic(graphs.CompleteGraph(4))
1560
+ True
1561
+ sage: l[0].get_embedding()
1562
+ {1: [2, 3, 4],
1563
+ 2: [1, 4, 3],
1564
+ 3: [1, 2, 4],
1565
+ 4: [1, 3, 2]}
1566
+
1567
+ TESTS::
1568
+
1569
+ sage: from io import StringIO
1570
+ sage: code_input = StringIO()
1571
+ sage: n = code_input.write('>>planar_code<<')
1572
+ sage: n = code_input.seek(0)
1573
+ sage: list(graphs._read_planar_code(code_input))
1574
+ Traceback (most recent call last):
1575
+ ...
1576
+ TypeError: not a binary file
1577
+
1578
+ sage: from io import BytesIO
1579
+ sage: code_input = BytesIO()
1580
+ sage: n = code_input.write(b'>>wrong header<<')
1581
+ sage: n = code_input.seek(0)
1582
+ sage: list(graphs._read_planar_code(code_input))
1583
+ Traceback (most recent call last):
1584
+ ...
1585
+ TypeError: file has no valid planar code header
1586
+ """
1587
+ # start of code to read planar code
1588
+ header = code_input.read(15)
1589
+ if not isinstance(header, bytes):
1590
+ raise TypeError('not a binary file')
1591
+ if header != b'>>planar_code<<':
1592
+ raise TypeError('file has no valid planar code header')
1593
+
1594
+ # read graph per graph
1595
+ while True:
1596
+ c = code_input.read(1)
1597
+ if not c:
1598
+ return
1599
+
1600
+ # Each graph is stored in the following way :
1601
+ #
1602
+ # The first character is the number of vertices, followed by
1603
+ # n11,...,n1k,null character,n21,...,n2k',null character, ...
1604
+ #
1605
+ # where the n1* are all neighbors of n1 and all n2* are the
1606
+ # neighbors of n2, ...
1607
+ #
1608
+ # Besides, these neighbors are enumerated in clockwise order.
1609
+ order = ord(c)
1610
+
1611
+ zeroCount = 0
1612
+
1613
+ g = [[] for i in range(order)]
1614
+
1615
+ while zeroCount < order:
1616
+ c = code_input.read(1)
1617
+ if ord(c) == 0:
1618
+ zeroCount += 1
1619
+ else:
1620
+ g[zeroCount].append(ord(c))
1621
+
1622
+ # construct graph based on g
1623
+
1624
+ # first taking care that every edge is given twice
1625
+ edges_g = {i + 1: [j for j in di if j < i + 1]
1626
+ for i, di in enumerate(g)}
1627
+
1628
+ # then adding half of the loops (if any)
1629
+ has_loops = False
1630
+ for i, di in enumerate(g):
1631
+ Ni = di.count(i + 1)
1632
+ if Ni > 1:
1633
+ edges_g[i + 1] += [i + 1] * (Ni // 2)
1634
+ has_loops = True
1635
+ G = graph.Graph(edges_g, loops=has_loops, immutable=immutable)
1636
+
1637
+ if not (G.has_multiple_edges() or has_loops):
1638
+ embed_g = {i + 1: di for i, di in enumerate(g)}
1639
+ G.set_embedding(embed_g)
1640
+ yield G
1641
+
1642
+ def fullerenes(self, order, ipr=False, immutable=False):
1643
+ r"""
1644
+ Return a generator which creates fullerene graphs using
1645
+ the buckygen generator (see [BGM2012]_).
1646
+
1647
+ INPUT:
1648
+
1649
+ - ``order`` -- a positive even integer smaller than or equal to 254
1650
+ This specifies the number of vertices in the generated fullerenes
1651
+
1652
+ - ``ipr`` -- boolean (default: ``False``); if ``True`` only fullerenes
1653
+ that satisfy the Isolated Pentagon Rule are generated. This means that
1654
+ no pentagonal faces share an edge.
1655
+
1656
+ - ``immutable`` -- boolean (default: ``False``); whether to return
1657
+ immutable or mutable graphs
1658
+
1659
+ OUTPUT:
1660
+
1661
+ A generator which will produce the fullerene graphs as Sage graphs
1662
+ with an embedding set. These will be simple graphs: no loops, no
1663
+ multiple edges, no directed edges.
1664
+
1665
+ .. SEEALSO::
1666
+
1667
+ - :meth:`~sage.graphs.generic_graph.GenericGraph.set_embedding`,
1668
+ :meth:`~sage.graphs.generic_graph.GenericGraph.get_embedding` --
1669
+ get/set methods for embeddings.
1670
+
1671
+ EXAMPLES:
1672
+
1673
+ There are 1812 isomers of `\textrm{C}_{60}`, i.e., 1812 fullerene graphs
1674
+ on 60 vertices::
1675
+
1676
+ sage: gen = graphs.fullerenes(60) # optional - buckygen
1677
+ sage: len(list(gen)) # optional - buckygen
1678
+ 1812
1679
+
1680
+ However, there is only one IPR fullerene graph on 60 vertices: the famous
1681
+ Buckminster Fullerene::
1682
+
1683
+ sage: gen = graphs.fullerenes(60, ipr=True) # optional - buckygen
1684
+ sage: next(gen) # optional - buckygen
1685
+ Graph on 60 vertices
1686
+ sage: next(gen) # optional - buckygen
1687
+ Traceback (most recent call last):
1688
+ ...
1689
+ StopIteration
1690
+
1691
+ The unique fullerene graph on 20 vertices is isomorphic to the dodecahedron
1692
+ graph. ::
1693
+
1694
+ sage: # optional - buckygen
1695
+ sage: gen = graphs.fullerenes(20)
1696
+ sage: g = next(gen)
1697
+ sage: g.is_isomorphic(graphs.DodecahedralGraph())
1698
+ True
1699
+ sage: g.get_embedding()
1700
+ {1: [2, 3, 4],
1701
+ 2: [1, 5, 6],
1702
+ 3: [1, 7, 8],
1703
+ 4: [1, 9, 10],
1704
+ 5: [2, 10, 11],
1705
+ 6: [2, 12, 7],
1706
+ 7: [3, 6, 13],
1707
+ 8: [3, 14, 9],
1708
+ 9: [4, 8, 15],
1709
+ 10: [4, 16, 5],
1710
+ 11: [5, 17, 12],
1711
+ 12: [6, 11, 18],
1712
+ 13: [7, 18, 14],
1713
+ 14: [8, 13, 19],
1714
+ 15: [9, 19, 16],
1715
+ 16: [10, 15, 17],
1716
+ 17: [11, 16, 20],
1717
+ 18: [12, 20, 13],
1718
+ 19: [14, 20, 15],
1719
+ 20: [17, 19, 18]}
1720
+ sage: g.plot3d(layout='spring') # needs sage.plot
1721
+ Graphics3d Object
1722
+ """
1723
+ # number of vertices should be positive
1724
+ if order < 0:
1725
+ raise ValueError("number of vertices should be nonnegative")
1726
+
1727
+ # buckygen can only output fullerenes on up to 254 vertices
1728
+ if order > 254:
1729
+ raise ValueError("number of vertices should be at most 254")
1730
+
1731
+ # fullerenes only exist for an even number of vertices, larger than 20
1732
+ # and different from 22
1733
+ if order % 2 == 1 or order < 20 or order == 22:
1734
+ return
1735
+
1736
+ from sage.features.graph_generators import Buckygen
1737
+ Buckygen().require()
1738
+
1739
+ import shlex
1740
+ command = shlex.quote(Buckygen().absolute_filename())
1741
+ command += ' -' + ('I' if ipr else '') + 'd {0}d'.format(order)
1742
+
1743
+ sp = subprocess.Popen(command, shell=True,
1744
+ stdin=subprocess.PIPE, stdout=subprocess.PIPE,
1745
+ stderr=subprocess.PIPE, close_fds=True)
1746
+
1747
+ yield from graphs._read_planar_code(sp.stdout, immutable=immutable)
1748
+
1749
+ def fusenes(self, hexagon_count, benzenoids=False, immutable=False):
1750
+ r"""
1751
+ Return a generator which creates fusenes and benzenoids using
1752
+ the benzene generator (see [BCH2002]_). Fusenes are planar
1753
+ polycyclic hydrocarbons with all bounded faces hexagons. Benzenoids
1754
+ are fusenes that are subgraphs of the hexagonal lattice.
1755
+
1756
+ INPUT:
1757
+
1758
+ - ``hexagon_count`` -- positive integer smaller than or equal to 30;
1759
+ this specifies the number of hexagons in the generated benzenoids
1760
+
1761
+ - ``benzenoids`` -- boolean (default: ``False``); if ``True`` only
1762
+ benzenoids are generated
1763
+
1764
+ - ``immutable`` -- boolean (default: ``False``); whether to return
1765
+ immutable or mutable graphs
1766
+
1767
+ OUTPUT:
1768
+
1769
+ A generator which will produce the fusenes as Sage graphs
1770
+ with an embedding set. These will be simple graphs: no loops, no
1771
+ multiple edges, no directed edges.
1772
+
1773
+ .. SEEALSO::
1774
+
1775
+ - :meth:`~sage.graphs.generic_graph.GenericGraph.set_embedding`,
1776
+ :meth:`~sage.graphs.generic_graph.GenericGraph.get_embedding` --
1777
+ get/set methods for embeddings.
1778
+
1779
+ EXAMPLES:
1780
+
1781
+ There is a unique fusene with 2 hexagons::
1782
+
1783
+ sage: gen = graphs.fusenes(2) # optional - benzene
1784
+ sage: len(list(gen)) # optional - benzene
1785
+ 1
1786
+
1787
+ This fusene is naphthalene (`\textrm{C}_{10}\textrm{H}_{8}`).
1788
+ In the fusene graph the H-atoms are not stored, so this is
1789
+ a graph on just 10 vertices::
1790
+
1791
+ sage: gen = graphs.fusenes(2) # optional - benzene
1792
+ sage: next(gen) # optional - benzene
1793
+ Graph on 10 vertices
1794
+ sage: next(gen) # optional - benzene
1795
+ Traceback (most recent call last):
1796
+ ...
1797
+ StopIteration
1798
+
1799
+ There are 6505 benzenoids with 9 hexagons::
1800
+
1801
+ sage: gen = graphs.fusenes(9, benzenoids=True) # optional - benzene
1802
+ sage: len(list(gen)) # optional - benzene
1803
+ 6505
1804
+ """
1805
+ if hexagon_count < 0:
1806
+ raise ValueError("number of hexagons should be nonnegative")
1807
+
1808
+ # benzene is only built for fusenes with up to 30 hexagons
1809
+ if hexagon_count > 30:
1810
+ raise ValueError("number of hexagons should be at most 30")
1811
+
1812
+ # there are no fusenes with 0 hexagons
1813
+ if hexagon_count == 0:
1814
+ return
1815
+
1816
+ # there is only one unique fusene with 1 hexagon (and benzene doesn't generate it)
1817
+ if hexagon_count == 1:
1818
+ g = {1: [6, 2], 2: [1, 3], 3: [2, 4], 4: [3, 5], 5: [4, 6], 6: [5, 1]}
1819
+ G = graph.Graph(g)
1820
+ G.set_embedding(g)
1821
+ yield G
1822
+ return
1823
+
1824
+ from sage.features.graph_generators import Benzene
1825
+ Benzene().require()
1826
+
1827
+ import shlex
1828
+ command = shlex.quote(Benzene().absolute_filename())
1829
+ command += (' b' if benzenoids else '') + ' {0} p'.format(hexagon_count)
1830
+
1831
+ sp = subprocess.Popen(command, shell=True,
1832
+ stdin=subprocess.PIPE, stdout=subprocess.PIPE,
1833
+ stderr=subprocess.PIPE, close_fds=True)
1834
+
1835
+ yield from graphs._read_planar_code(sp.stdout, immutable=immutable)
1836
+
1837
+ def plantri_gen(self, options="", immutable=False):
1838
+ r"""
1839
+ Iterator over planar graphs created using the ``plantri`` generator.
1840
+
1841
+ ``plantri`` is a (optional) program that generates certain types of
1842
+ graphs that are embedded on the sphere. It outputs exactly one member of
1843
+ each isomorphism class, using an amount of memory almost independent of
1844
+ the number of graphs produced. Isomorphisms are defined with respect to
1845
+ the embeddings, so in some cases outputs may be isomorphic as abstract
1846
+ graphs.
1847
+
1848
+ This method allows for passing command directly to ``plantry``,
1849
+ similarly to method :meth:`nauty_geng`, provide that the output format
1850
+ is not changed.
1851
+
1852
+ INPUT:
1853
+
1854
+ - ``options`` -- string (default: ``""``); a string passed to
1855
+ ``plantri`` as if it was run at a system command line. At a minimum,
1856
+ you *must* pass the number of vertices you desire. Sage expects the
1857
+ output of plantri to be in "planar code" format, so do not set an
1858
+ option to change this default or results will be unpredictable.
1859
+
1860
+ - ``immutable`` -- boolean (default: ``False``); whether to return
1861
+ immutable or mutable graphs
1862
+
1863
+ The possible options are::
1864
+
1865
+ n : the number of vertices (the only compulsory parameter).
1866
+ This number must be in range `3\cdots 64`.
1867
+ It can also be given as "nd", where the suffix "d" means
1868
+ "dual", in which case it is converted by adding 4 then
1869
+ dividing by 2, i.e., `(28+4)/2 = 16`. In the case of
1870
+ triangulations, this calculation yields the number of
1871
+ faces, which is the number of vertices in the dual cubic
1872
+ graph.
1873
+
1874
+ -d : output the dual instead of the original graph.
1875
+ Note that it is applied only at the output stage. All
1876
+ other switches refer to the original graph before the dual
1877
+ is taken.
1878
+
1879
+ -o : Normally, one member of each isomorphism class is written.
1880
+ If this switch is given, one member of each O-P
1881
+ isomorphism class is written.
1882
+
1883
+ -V : output only graphs with non-trivial group. If -o is
1884
+ given the O-P group is used, the full group otherwise.
1885
+
1886
+ -m<int> : lower bound on the minimum degree. The default is -m3.
1887
+ In the dual graph, this means a lower bound on the minimum
1888
+ face size.
1889
+
1890
+ -c<int> : lower bound on the connectivity. The default is -c3.
1891
+
1892
+ -x : when used in combination with -cN, the connectivity must
1893
+ be exactly N rather than at least N.
1894
+
1895
+ -e : used to specify bounds on the number of edges.
1896
+ There are four possible forms:
1897
+ -e<int> exactly <int> edges
1898
+ -e:<int> at most <int> edges
1899
+ -e<int>: at least <int> edges
1900
+ -e<int>:<int> between <int> and <int> edges
1901
+
1902
+ -f<int> : upper bound on the size of a face, and so on the maximum
1903
+ degree of the dual.
1904
+
1905
+ -b but not -p : select eulerian triangulations, where "eulerian"
1906
+ means that every vertex has even degree.
1907
+ This parameter can be used in combination with
1908
+ parameters -c and -x.
1909
+
1910
+ -p but not -b : select general planar simple graphs.
1911
+ This parameter can be used in combination with
1912
+ parameters -m, -c, -x, -e and -f.
1913
+
1914
+ -bp or -pb : select general planar simple bipartite graphs.
1915
+ This parameter can be used in combination with
1916
+ parameters -m, -c, -x, -e and -f, except -c4, -m4,
1917
+ -m5 and -f3.
1918
+
1919
+ -P<int> : select triangulations of a disk. These are embedded simple
1920
+ graphs with a distinguished "outer" face. The outer face
1921
+ can be of any size (here called the disk size) but the
1922
+ other faces must be triangles. The argument <int> to -P
1923
+ is the disk size. If no argument (or 0) is given, all disk
1924
+ sizes are permitted.
1925
+ This parameter can be used in combination with
1926
+ parameters -m, -c, and -x.
1927
+
1928
+ -q : select simple quadrangulations. These are planar simple
1929
+ graphs for which every face has length 4.
1930
+ This parameter can be used in combination with parameters
1931
+ -c and -m.
1932
+
1933
+ -A : select Appolonian networks. These are simple planar
1934
+ triangulations that can be formed starting with `K_4` then
1935
+ repeatedly dividing a face into three by addition of a new
1936
+ vertex. They all have minimum degree and connectivity
1937
+ equal to 3.
1938
+
1939
+ res/mod : only generate subset res out of subsets 0..mod-1.
1940
+ The set of objects is divided into mod disjoint classes
1941
+ and only the res-th class is generated.
1942
+
1943
+ If -b, -q, -p, -P and -A are absent, the graphs found are triangulations
1944
+ only restricted by connectivity and minimum degree. In this case,
1945
+ there is the possibility of connectivity lower than 3.
1946
+
1947
+ Other options listed in the ``plantri`` guide might cause unpredictable
1948
+ behavior, in particular those changing the output format of ``plantri``
1949
+ as they will confuse the creation of a Sage graph.
1950
+
1951
+ OUTPUT:
1952
+
1953
+ An iterator which yields the graphs generated by ``plantri`` as Sage
1954
+ :class:`~sage.graphs.graph.Graph`.
1955
+
1956
+ .. SEEALSO::
1957
+
1958
+ - :meth:`planar_graphs` -- iterator over connected planar graphs
1959
+ using the ``plantri`` generator
1960
+ - :meth:`triangulations` -- iterator over connected planar
1961
+ triangulations using the ``plantri`` generator
1962
+ - :meth:`quadrangulations` -- iterator over connected planar
1963
+ quadrangulations using the ``plantri`` generator
1964
+
1965
+ EXAMPLES:
1966
+
1967
+ The generator can be used to construct graphs for testing, one at a time
1968
+ (usually inside a loop). Or it can be used to create an entire list all
1969
+ at once if there is sufficient memory to contain it::
1970
+
1971
+ sage: # optional - plantri
1972
+ sage: gen = graphs.plantri_gen("6")
1973
+ sage: next(gen)
1974
+ Graph on 6 vertices
1975
+ sage: next(gen)
1976
+ Graph on 6 vertices
1977
+ sage: next(gen)
1978
+ Traceback (most recent call last):
1979
+ ...
1980
+ StopIteration
1981
+
1982
+ An overview of the number of quadrangulations on up to 12 vertices. This
1983
+ agrees with :oeis:`A113201`::
1984
+
1985
+ sage: for i in range(4, 13): # optional - plantri
1986
+ ....: cmd = '-qm2c2 {}'.format(i)
1987
+ ....: L = len(list(graphs.plantri_gen(cmd)))
1988
+ ....: print("{:2d} {:3d}".format(i, L))
1989
+ 4 1
1990
+ 5 1
1991
+ 6 2
1992
+ 7 3
1993
+ 8 9
1994
+ 9 18
1995
+ 10 62
1996
+ 11 198
1997
+ 12 803
1998
+
1999
+ TESTS:
2000
+
2001
+ Wrong input, ``"-c=3"`` instead of ``"-c3"``::
2002
+
2003
+ sage: list(graphs.plantri_gen("6 -c3")) # optional - plantri
2004
+ [Graph on 6 vertices, Graph on 6 vertices]
2005
+ sage: list(graphs.plantri_gen("6 -c=3")) # optional - plantri
2006
+ Traceback (most recent call last):
2007
+ ...
2008
+ AttributeError: invalid options '6 -c=3'
2009
+ """
2010
+ from sage.features.graph_generators import Plantri
2011
+ Plantri().require()
2012
+
2013
+ import shlex
2014
+ command = '{} {}'.format(shlex.quote(Plantri().absolute_filename()),
2015
+ options)
2016
+ sp = subprocess.Popen(command, shell=True,
2017
+ stdin=subprocess.PIPE, stdout=subprocess.PIPE,
2018
+ stderr=subprocess.PIPE, close_fds=True)
2019
+
2020
+ try:
2021
+ yield from graphs._read_planar_code(sp.stdout, immutable=immutable)
2022
+ except (TypeError, AssertionError):
2023
+ raise AttributeError("invalid options '{}'".format(options))
2024
+
2025
+ def planar_graphs(self, order, minimum_degree=None,
2026
+ minimum_connectivity=None,
2027
+ exact_connectivity=False,
2028
+ minimum_edges=None,
2029
+ maximum_edges=None,
2030
+ maximum_face_size=None,
2031
+ only_bipartite=False,
2032
+ dual=False,
2033
+ immutable=False):
2034
+ r"""
2035
+ An iterator over connected planar graphs using the plantri generator.
2036
+
2037
+ This uses the plantri generator (see [BM2007]_) which is available
2038
+ through the optional package plantri.
2039
+
2040
+ .. NOTE::
2041
+
2042
+ The non-3-connected graphs will be returned several times, with all
2043
+ its possible embeddings.
2044
+
2045
+ INPUT:
2046
+
2047
+ - ``order`` -- positive integer smaller than or equal to 64;
2048
+ this specifies the number of vertices in the generated graphs
2049
+
2050
+ - ``minimum_degree`` -- (default: ``None``) a value `\geq 1` and `\leq
2051
+ 5`, or ``None``. This specifies the minimum degree of the generated
2052
+ graphs. If this is ``None`` and the order is 1, then this is set to
2053
+ 0. If this is ``None`` and the minimum connectivity is specified, then
2054
+ this is set to the same value as the minimum connectivity. If the
2055
+ minimum connectivity is also equal to ``None``, then this is set to 1.
2056
+
2057
+ - ``minimum_connectivity`` -- (default: ``None``) a value `\geq 1`
2058
+ and `\leq 3`, or ``None``. This specifies the minimum connectivity of the
2059
+ generated graphs. If this is ``None`` and the minimum degree is
2060
+ specified, then this is set to the minimum of the minimum degree
2061
+ and 3. If the minimum degree is also equal to ``None``, then this
2062
+ is set to 1.
2063
+
2064
+ - ``exact_connectivity`` -- (default: ``False``) if ``True`` only
2065
+ graphs with exactly the specified connectivity will be generated.
2066
+ This option cannot be used with ``minimum_connectivity=3``, or if
2067
+ the minimum connectivity is not explicitly set.
2068
+
2069
+ - ``minimum_edges`` -- integer (default: ``None``); lower bound on the
2070
+ number of edges
2071
+
2072
+ - ``maximum_edges`` -- integer (default: ``None``); upper bound on the
2073
+ number of edges
2074
+
2075
+ - ``maximum_face_size`` -- integer (default: ``None``); upper bound on
2076
+ the size of a face and so on the maximum degree of the dual graph
2077
+
2078
+ - ``only_bipartite`` -- (default: ``False``) if ``True`` only bipartite
2079
+ graphs will be generated. This option cannot be used for graphs with
2080
+ a minimum degree larger than 3.
2081
+
2082
+ - ``dual`` -- (default: ``False``) if ``True`` return instead the
2083
+ planar duals of the generated graphs
2084
+
2085
+ - ``immutable`` -- boolean (default: ``False``); whether to return
2086
+ immutable or mutable graphs
2087
+
2088
+ OUTPUT:
2089
+
2090
+ An iterator which will produce all planar graphs with the given
2091
+ number of vertices as Sage graphs with an embedding set. These will be
2092
+ simple graphs (no loops, no multiple edges, no directed edges)
2093
+ unless the option ``dual=True`` is used.
2094
+
2095
+ .. SEEALSO::
2096
+
2097
+ - :meth:`~sage.graphs.generic_graph.GenericGraph.set_embedding`,
2098
+ :meth:`~sage.graphs.generic_graph.GenericGraph.get_embedding` --
2099
+ get/set methods for embeddings.
2100
+
2101
+ EXAMPLES:
2102
+
2103
+ There are 6 planar graphs on 4 vertices::
2104
+
2105
+ sage: gen = graphs.planar_graphs(4) # optional - plantri
2106
+ sage: len(list(gen)) # optional - plantri
2107
+ 6
2108
+
2109
+ Three of these planar graphs are bipartite::
2110
+
2111
+ sage: gen = graphs.planar_graphs(4, only_bipartite=True) # optional - plantri
2112
+ sage: len(list(gen)) # optional - plantri
2113
+ 3
2114
+
2115
+ Setting ``dual=True`` gives the planar dual graphs::
2116
+
2117
+ sage: gen = graphs.planar_graphs(4, dual=True) # optional - plantri
2118
+ sage: [u for u in list(gen)] # optional - plantri
2119
+ [Graph on 4 vertices,
2120
+ Multi-graph on 3 vertices,
2121
+ Multi-graph on 2 vertices,
2122
+ Looped multi-graph on 2 vertices,
2123
+ Looped multi-graph on 1 vertex,
2124
+ Looped multi-graph on 1 vertex]
2125
+
2126
+ The cycle of length 4 is the only 2-connected bipartite planar graph
2127
+ on 4 vertices::
2128
+
2129
+ sage: l = list(graphs.planar_graphs(4, minimum_connectivity=2, only_bipartite=True)) # optional - plantri
2130
+ sage: l[0].get_embedding() # optional - plantri
2131
+ {1: [2, 3],
2132
+ 2: [1, 4],
2133
+ 3: [1, 4],
2134
+ 4: [2, 3]}
2135
+
2136
+ There is one planar graph with one vertex. This graph obviously has
2137
+ minimum degree equal to 0::
2138
+
2139
+ sage: list(graphs.planar_graphs(1)) # optional - plantri
2140
+ [Graph on 1 vertex]
2141
+ sage: list(graphs.planar_graphs(1, minimum_degree=1)) # optional - plantri
2142
+ []
2143
+
2144
+ Specifying lower and upper bounds on the number of edges::
2145
+
2146
+ sage: # optional - plantri
2147
+ sage: len(list(graphs.planar_graphs(4)))
2148
+ 6
2149
+ sage: len(list(graphs.planar_graphs(4, minimum_edges=4)))
2150
+ 4
2151
+ sage: len(list(graphs.planar_graphs(4, maximum_edges=4)))
2152
+ 4
2153
+ sage: len(list(graphs.planar_graphs(4, minimum_edges=4, maximum_edges=4)))
2154
+ 2
2155
+
2156
+ Specifying the maximum size of a face::
2157
+
2158
+ sage: len(list(graphs.planar_graphs(4, maximum_face_size=3))) # optional - plantri
2159
+ 1
2160
+ sage: len(list(graphs.planar_graphs(4, maximum_face_size=4))) # optional - plantri
2161
+ 3
2162
+
2163
+ TESTS:
2164
+
2165
+ The number of edges in a planar graph is equal to the number of edges in
2166
+ its dual::
2167
+
2168
+ sage: # optional - plantri
2169
+ sage: planar = list(graphs.planar_graphs(5,dual=True))
2170
+ sage: dual_planar = list(graphs.planar_graphs(5,dual=False))
2171
+ sage: planar_sizes = [g.size() for g in planar]
2172
+ sage: dual_planar_sizes = [g.size() for g in dual_planar]
2173
+ sage: planar_sizes == dual_planar_sizes
2174
+ True
2175
+ """
2176
+ if order < 0:
2177
+ raise ValueError("number of vertices should be nonnegative")
2178
+
2179
+ # plantri can only output general planar graphs on up to 64 vertices
2180
+ if order > 64:
2181
+ raise ValueError("number of vertices should be at most 64")
2182
+
2183
+ if exact_connectivity and minimum_connectivity is None:
2184
+ raise ValueError("Minimum connectivity must be specified to use the exact_connectivity option.")
2185
+
2186
+ if minimum_connectivity is not None and not (1 <= minimum_connectivity <= 3):
2187
+ raise ValueError("Minimum connectivity should be a number between 1 and 3.")
2188
+
2189
+ # minimum degree should be None or a number between 1 and 5
2190
+ if minimum_degree == 0:
2191
+ if order != 1:
2192
+ raise ValueError("Minimum degree equal to 0 is only possible if the graphs have 1 vertex.")
2193
+ elif minimum_degree is not None and not (1 <= minimum_degree <= 5):
2194
+ raise ValueError("Minimum degree should be a number between 1 and 5 if the order is greater than 1.")
2195
+ elif minimum_degree is None and order == 1:
2196
+ minimum_degree = 0
2197
+
2198
+ # check combination of values of minimum degree and minimum connectivity
2199
+ if minimum_connectivity is None:
2200
+ if minimum_degree is not None:
2201
+ minimum_connectivity = min(3, minimum_degree)
2202
+ elif minimum_degree is None:
2203
+ minimum_degree, minimum_connectivity = 1, 1
2204
+ else:
2205
+ if minimum_degree is None:
2206
+ minimum_degree = minimum_connectivity
2207
+ elif (minimum_degree < minimum_connectivity and
2208
+ minimum_degree > 0):
2209
+ raise ValueError("Minimum connectivity can be at most the minimum degree.")
2210
+
2211
+ # exact connectivity is not implemented for minimum connectivity 3
2212
+ if exact_connectivity and minimum_connectivity == 3:
2213
+ raise NotImplementedError("Generation of planar graphs with connectivity exactly 3 is not implemented.")
2214
+
2215
+ if only_bipartite and minimum_degree > 3:
2216
+ raise NotImplementedError("Generation of bipartite planar graphs with minimum degree 4 or 5 is not implemented.")
2217
+
2218
+ edges = ''
2219
+ if minimum_edges is None:
2220
+ if maximum_edges is not None:
2221
+ if maximum_edges < order - 1:
2222
+ raise ValueError("the number of edges cannot be less than order - 1")
2223
+ edges = '-e:{}'.format(maximum_edges)
2224
+ else:
2225
+ if minimum_edges > 3 * order - 6:
2226
+ raise ValueError("the number of edges cannot be more than 3*order - 6")
2227
+ if maximum_edges is None:
2228
+ edges = '-e{}:'.format(minimum_edges)
2229
+ elif minimum_edges > maximum_edges:
2230
+ raise ValueError("the maximum number of edges must be larger "
2231
+ "or equal to the minimum number of edges")
2232
+ elif minimum_edges == maximum_edges:
2233
+ edges = '-e{}'.format(minimum_edges)
2234
+ else:
2235
+ edges = '-e{}:{}'.format(minimum_edges, maximum_edges)
2236
+
2237
+ faces = ''
2238
+ if maximum_face_size is not None:
2239
+ if maximum_face_size < 3:
2240
+ raise ValueError("the upper bound on the size of a face must be at least 3")
2241
+ faces = '-f{}'.format(maximum_face_size)
2242
+
2243
+ if order == 0:
2244
+ return
2245
+
2246
+ minimum_order = {0: 1, 1: 2, 2: 3, 3: 4, 4: 6, 5: 12}[minimum_degree]
2247
+
2248
+ if order < minimum_order:
2249
+ return
2250
+
2251
+ if order == 1:
2252
+ if minimum_degree == 0:
2253
+ G = graph.Graph(1, immutable=immutable)
2254
+ G.set_embedding({0: []})
2255
+ yield G
2256
+ return
2257
+
2258
+ cmd = '-p{}m{}c{}{}{} {} {} {}'
2259
+ command = cmd.format('b' if only_bipartite else '',
2260
+ minimum_degree,
2261
+ minimum_connectivity,
2262
+ 'x' if exact_connectivity else '',
2263
+ 'd' if dual else '',
2264
+ edges, faces,
2265
+ order)
2266
+
2267
+ yield from graphs.plantri_gen(command, immutable=immutable)
2268
+
2269
+ def triangulations(self, order, minimum_degree=None, minimum_connectivity=None,
2270
+ exact_connectivity=False, only_eulerian=False, dual=False,
2271
+ immutable=False):
2272
+ r"""
2273
+ An iterator over connected planar triangulations using the plantri generator.
2274
+
2275
+ This uses the plantri generator (see [BM2007]_) which is available
2276
+ through the optional package plantri.
2277
+
2278
+ INPUT:
2279
+
2280
+ - ``order`` -- positive integer smaller than or equal to 64;
2281
+ this specifies the number of vertices in the generated triangulations
2282
+
2283
+ - ``minimum_degree`` -- (default: ``None``) a value `\geq 3` and `\leq 5`,
2284
+ or ``None``. This specifies the minimum degree of the generated
2285
+ triangulations. If this is ``None`` and the minimum connectivity
2286
+ is specified, then this is set to the same value as the minimum
2287
+ connectivity. If the minimum connectivity is also equal to ``None``,
2288
+ then this is set to 3.
2289
+
2290
+ - ``minimum_connectivity`` -- (default: ``None``) a value `\geq 3` and
2291
+ `\leq 5`, or ``None``. This specifies the minimum connectivity of the
2292
+ generated triangulations. If this is ``None`` and the minimum degree
2293
+ is specified, then this is set to the minimum of the minimum degree
2294
+ and 3. If the minimum degree is also equal to ``None``, then this is
2295
+ set to 3.
2296
+
2297
+ - ``exact_connectivity`` -- (default: ``False``) if ``True`` only
2298
+ triangulations with exactly the specified connectivity will be generated.
2299
+ This option cannot be used with ``minimum_connectivity=3``, or if
2300
+ the minimum connectivity is not explicitly set.
2301
+
2302
+ - ``only_eulerian`` -- (default: ``False``) if ``True`` only Eulerian
2303
+ triangulations will be generated. This option cannot be used if the
2304
+ minimum degree is explicitly set to anything else than 4.
2305
+
2306
+ - ``dual`` -- (default: ``False``) if ``True`` return instead the
2307
+ planar duals of the generated graphs
2308
+
2309
+ - ``immutable`` -- boolean (default: ``False``); whether to return
2310
+ immutable or mutable graphs
2311
+
2312
+ OUTPUT:
2313
+
2314
+ An iterator which will produce all planar triangulations with the given
2315
+ number of vertices as Sage graphs with an embedding set. These will be
2316
+ simple graphs (no loops, no multiple edges, no directed edges).
2317
+
2318
+ .. SEEALSO::
2319
+
2320
+ - :meth:`~sage.graphs.generic_graph.GenericGraph.set_embedding`,
2321
+ :meth:`~sage.graphs.generic_graph.GenericGraph.get_embedding` --
2322
+ get/set methods for embeddings.
2323
+
2324
+ - :meth:`~sage.graphs.graph_generators.GraphGenerators.RandomTriangulation`
2325
+ -- build a random triangulation.
2326
+
2327
+ EXAMPLES:
2328
+
2329
+ The unique planar embedding of the `K_4` is the only planar triangulations
2330
+ on 4 vertices::
2331
+
2332
+ sage: gen = graphs.triangulations(4) # optional - plantri
2333
+ sage: [g.get_embedding() for g in gen] # optional - plantri
2334
+ [{1: [2, 3, 4], 2: [1, 4, 3], 3: [1, 2, 4], 4: [1, 3, 2]}]
2335
+
2336
+ but, of course, this graph is not Eulerian::
2337
+
2338
+ sage: gen = graphs.triangulations(4, only_eulerian=True) # optional - plantri
2339
+ sage: len(list(gen)) # optional - plantri
2340
+ 0
2341
+
2342
+ The unique Eulerian triangulation on 6 vertices is isomorphic to the octahedral
2343
+ graph. ::
2344
+
2345
+ sage: gen = graphs.triangulations(6, only_eulerian=True) # optional - plantri
2346
+ sage: g = next(gen) # optional - plantri
2347
+ sage: g.is_isomorphic(graphs.OctahedralGraph()) # optional - plantri
2348
+ True
2349
+
2350
+ The minimum degree of a triangulation is 3, so the method can not output
2351
+ a triangle::
2352
+
2353
+ sage: list(graphs.triangulations(3)) # optional - plantri
2354
+ []
2355
+
2356
+ An overview of the number of 5-connected triangulations on up to 22 vertices. This
2357
+ agrees with :oeis:`A081621`::
2358
+
2359
+ sage: for i in range(12, 23): # optional - plantri
2360
+ ....: L = len(list(graphs.triangulations(i, minimum_connectivity=5)))
2361
+ ....: print("{} {:3d}".format(i,L))
2362
+ 12 1
2363
+ 13 0
2364
+ 14 1
2365
+ 15 1
2366
+ 16 3
2367
+ 17 4
2368
+ 18 12
2369
+ 19 23
2370
+ 20 71
2371
+ 21 187
2372
+ 22 627
2373
+
2374
+ The minimum connectivity can be at most the minimum degree::
2375
+
2376
+ sage: gen = next(graphs.triangulations(10, minimum_degree=3, # optional - plantri
2377
+ ....: minimum_connectivity=5))
2378
+ Traceback (most recent call last):
2379
+ ...
2380
+ ValueError: Minimum connectivity can be at most the minimum degree.
2381
+
2382
+ There are 5 triangulations with 9 vertices and minimum degree equal to 4
2383
+ that are 3-connected, but only one of them is not 4-connected::
2384
+
2385
+ sage: len([g for g in graphs.triangulations(9, minimum_degree=4, # optional - plantri
2386
+ ....: minimum_connectivity=3)])
2387
+ 5
2388
+ sage: len([g for g in graphs.triangulations(9, minimum_degree=4, # optional - plantri
2389
+ ....: minimum_connectivity=3,
2390
+ ....: exact_connectivity=True)])
2391
+ 1
2392
+
2393
+ Setting ``dual=True`` gives the planar dual graphs::
2394
+
2395
+ sage: [len(g) for g in graphs.triangulations(9, minimum_degree=4, # optional plantri
2396
+ ....: minimum_connectivity=3, dual=True)]
2397
+ [14, 14, 14, 14, 14]
2398
+
2399
+ TESTS::
2400
+
2401
+ sage: [g.size() for g in graphs.triangulations(6, minimum_connectivity=3)] # optional - plantri
2402
+ [12, 12]
2403
+ """
2404
+ if order < 0:
2405
+ raise ValueError("number of vertices should be nonnegative")
2406
+
2407
+ # plantri can only output planar triangulations on up to 64 vertices
2408
+ if order > 64:
2409
+ raise ValueError("number of vertices should be at most 64")
2410
+
2411
+ if exact_connectivity and minimum_connectivity is None:
2412
+ raise ValueError("Minimum connectivity must be specified to use the exact_connectivity option.")
2413
+
2414
+ if minimum_connectivity is not None and not (3 <= minimum_connectivity <= 5):
2415
+ raise ValueError("Minimum connectivity should be None or a number between 3 and 5.")
2416
+
2417
+ if minimum_degree is not None and not (3 <= minimum_degree <= 5):
2418
+ raise ValueError("Minimum degree should be None or a number between 3 and 5.")
2419
+
2420
+ # for Eulerian triangulations the minimum degree is set to 4 (unless it was already specifically set)
2421
+ if only_eulerian and minimum_degree is None:
2422
+ minimum_degree = 4
2423
+
2424
+ # check combination of values of minimum degree and minimum connectivity
2425
+ if minimum_connectivity is None:
2426
+ if minimum_degree is not None:
2427
+ minimum_connectivity = min(3, minimum_degree)
2428
+ else:
2429
+ minimum_degree, minimum_connectivity = 3, 3
2430
+ else:
2431
+ if minimum_degree is None:
2432
+ minimum_degree = minimum_connectivity
2433
+ elif minimum_degree < minimum_connectivity:
2434
+ raise ValueError("Minimum connectivity can be at most the minimum degree.")
2435
+
2436
+ # exact connectivity is not implemented for minimum connectivity equal
2437
+ # to minimum degree
2438
+ if exact_connectivity and minimum_connectivity == minimum_degree:
2439
+ raise NotImplementedError("Generation of triangulations with minimum connectivity equal to minimum degree is not implemented.")
2440
+
2441
+ minimum_order = {3: 4, 4: 6, 5: 12}[minimum_degree]
2442
+
2443
+ if order < minimum_order:
2444
+ return
2445
+
2446
+ if only_eulerian and order < 6:
2447
+ return
2448
+
2449
+ cmd = '-{}m{}c{}{}{} {}'
2450
+ command = cmd.format('b' if only_eulerian else '',
2451
+ minimum_degree,
2452
+ minimum_connectivity,
2453
+ 'x' if exact_connectivity else '',
2454
+ 'd' if dual else '',
2455
+ order)
2456
+
2457
+ yield from graphs.plantri_gen(command, immutable=immutable)
2458
+
2459
+ def quadrangulations(self, order, minimum_degree=None, minimum_connectivity=None,
2460
+ no_nonfacial_quadrangles=False, dual=False,
2461
+ immutable=False):
2462
+ r"""
2463
+ An iterator over planar quadrangulations using the plantri generator.
2464
+
2465
+ This uses the plantri generator (see [BM2007]_) which is available
2466
+ through the optional package plantri.
2467
+
2468
+ INPUT:
2469
+
2470
+ - ``order`` -- positive integer smaller than or equal to 64;
2471
+ this specifies the number of vertices in the generated quadrangulations
2472
+
2473
+ - ``minimum_degree`` -- (default: ``None``) a value `\geq 2` and `\leq
2474
+ 3`, or ``None``. This specifies the minimum degree of the generated
2475
+ quadrangulations. If this is ``None`` and the minimum connectivity is
2476
+ specified, then this is set to the same value as the minimum
2477
+ connectivity. If the minimum connectivity is also equal to ``None``,
2478
+ then this is set to 2.
2479
+
2480
+ - ``minimum_connectivity`` -- (default: ``None``) a value `\geq 2` and
2481
+ `\leq 3`, or ``None``. This specifies the minimum connectivity of the
2482
+ generated quadrangulations. If this is ``None`` and the option
2483
+ ``no_nonfacial_quadrangles`` is set to ``True``, then this is set to
2484
+ 3. Otherwise if this is ``None`` and the minimum degree is specified,
2485
+ then this is set to the minimum degree. If the minimum degree is also
2486
+ equal to ``None``, then this is set to 3.
2487
+
2488
+ - ``no_nonfacial_quadrangles`` -- (default: ``False``) if ``True`` only
2489
+ quadrangulations with no non-facial quadrangles are generated. This
2490
+ option cannot be used if ``minimum_connectivity`` is set to 2.
2491
+
2492
+ - ``dual`` -- (default: ``False``) if ``True`` return instead the
2493
+ planar duals of the generated graphs
2494
+
2495
+ - ``immutable`` -- boolean (default: ``False``); whether to return
2496
+ immutable or mutable graphs
2497
+
2498
+ OUTPUT:
2499
+
2500
+ An iterator which will produce all planar quadrangulations with the given
2501
+ number of vertices as Sage graphs with an embedding set. These will be
2502
+ simple graphs (no loops, no multiple edges, no directed edges).
2503
+
2504
+ .. SEEALSO::
2505
+
2506
+ - :meth:`~sage.graphs.generic_graph.GenericGraph.set_embedding`,
2507
+ :meth:`~sage.graphs.generic_graph.GenericGraph.get_embedding` --
2508
+ get/set methods for embeddings.
2509
+
2510
+ EXAMPLES:
2511
+
2512
+ The cube is the only 3-connected planar quadrangulation on 8 vertices::
2513
+
2514
+ sage: # optional - plantri
2515
+ sage: gen = graphs.quadrangulations(8, minimum_connectivity=3)
2516
+ sage: g = next(gen)
2517
+ sage: g.is_isomorphic(graphs.CubeGraph(3))
2518
+ True
2519
+ sage: next(gen)
2520
+ Traceback (most recent call last):
2521
+ ...
2522
+ StopIteration
2523
+
2524
+ An overview of the number of quadrangulations on up to 12 vertices. This
2525
+ agrees with :oeis:`A113201`::
2526
+
2527
+ sage: for i in range(4,13): # optional - plantri
2528
+ ....: L = len(list(graphs.quadrangulations(i)))
2529
+ ....: print("{:2d} {:3d}".format(i,L))
2530
+ 4 1
2531
+ 5 1
2532
+ 6 2
2533
+ 7 3
2534
+ 8 9
2535
+ 9 18
2536
+ 10 62
2537
+ 11 198
2538
+ 12 803
2539
+
2540
+ There are 2 planar quadrangulation on 12 vertices that do not have a
2541
+ non-facial quadrangle::
2542
+
2543
+ sage: len([g for g in graphs.quadrangulations(12, no_nonfacial_quadrangles=True)]) # optional - plantri
2544
+ 2
2545
+
2546
+ Setting ``dual=True`` gives the planar dual graphs::
2547
+
2548
+ sage: [len(g) for g in graphs.quadrangulations(12, no_nonfacial_quadrangles=True, dual=True)] # optional - plantri
2549
+ [10, 10]
2550
+ """
2551
+ if order < 0:
2552
+ raise ValueError("number of vertices should be nonnegative")
2553
+
2554
+ # plantri can only output planar quadrangulations on up to 64 vertices
2555
+ if order > 64:
2556
+ raise ValueError("number of vertices should be at most 64")
2557
+
2558
+ if minimum_connectivity not in {None, 2, 3}:
2559
+ raise ValueError("Minimum connectivity should be None, 2 or 3.")
2560
+
2561
+ if minimum_degree not in {None, 2, 3}:
2562
+ raise ValueError("Minimum degree should be None, 2 or 3.")
2563
+
2564
+ if (no_nonfacial_quadrangles and
2565
+ minimum_connectivity == 2):
2566
+ raise NotImplementedError("Generation of no non-facial quadrangles "
2567
+ "and minimum connectivity 2 is not implemented")
2568
+
2569
+ # check combination of values of minimum degree and minimum connectivity
2570
+ if minimum_connectivity is None:
2571
+ if minimum_degree is not None:
2572
+ minimum_connectivity = min(2, minimum_degree)
2573
+ else:
2574
+ minimum_degree, minimum_connectivity = 2, 2
2575
+ else:
2576
+ if minimum_degree is None:
2577
+ minimum_degree = minimum_connectivity
2578
+ elif minimum_degree < minimum_connectivity:
2579
+ raise ValueError("Minimum connectivity can be at most the minimum degree.")
2580
+
2581
+ minimum_order = {2: 4, 3: 8}[minimum_degree]
2582
+
2583
+ if order < minimum_order:
2584
+ return
2585
+
2586
+ if no_nonfacial_quadrangles:
2587
+ # for plantri -q the option -c4 means 3-connected with no non-facial quadrangles
2588
+ minimum_connectivity = 4
2589
+
2590
+ cmd = '-qm{}c{}{} {}'
2591
+ command = cmd.format(minimum_degree,
2592
+ minimum_connectivity,
2593
+ 'd' if dual else '',
2594
+ order)
2595
+
2596
+ yield from graphs.plantri_gen(command, immutable=immutable)
2597
+
2598
+ ###########################################################################
2599
+ # Basic Graphs
2600
+ ###########################################################################
2601
+ from .generators import basic
2602
+ BullGraph = staticmethod(basic.BullGraph)
2603
+ ButterflyGraph = staticmethod(basic.ButterflyGraph)
2604
+ CircularLadderGraph = staticmethod(basic.CircularLadderGraph)
2605
+ ClawGraph = staticmethod(basic.ClawGraph)
2606
+ CycleGraph = staticmethod(basic.CycleGraph)
2607
+ CompleteGraph = staticmethod(basic.CompleteGraph)
2608
+ CompleteBipartiteGraph = staticmethod(basic.CompleteBipartiteGraph)
2609
+ CompleteMultipartiteGraph = staticmethod(basic.CompleteMultipartiteGraph)
2610
+ CorrelationGraph = staticmethod(basic.CorrelationGraph)
2611
+ DiamondGraph = staticmethod(basic.DiamondGraph)
2612
+ GemGraph = staticmethod(basic.GemGraph)
2613
+ DartGraph = staticmethod(basic.DartGraph)
2614
+ ForkGraph = staticmethod(basic.ForkGraph)
2615
+ EmptyGraph = staticmethod(basic.EmptyGraph)
2616
+ Grid2dGraph = staticmethod(basic.Grid2dGraph)
2617
+ GridGraph = staticmethod(basic.GridGraph)
2618
+ HouseGraph = staticmethod(basic.HouseGraph)
2619
+ HouseXGraph = staticmethod(basic.HouseXGraph)
2620
+ LadderGraph = staticmethod(basic.LadderGraph)
2621
+ MoebiusLadderGraph = staticmethod(basic.MoebiusLadderGraph)
2622
+ PathGraph = staticmethod(basic.PathGraph)
2623
+ StarGraph = staticmethod(basic.StarGraph)
2624
+ Toroidal6RegularGrid2dGraph = staticmethod(basic.Toroidal6RegularGrid2dGraph)
2625
+ ToroidalGrid2dGraph = staticmethod(basic.ToroidalGrid2dGraph)
2626
+
2627
+ ###########################################################################
2628
+ # Small Graphs
2629
+ ###########################################################################
2630
+ from .generators import smallgraphs, distance_regular
2631
+ Balaban10Cage = staticmethod(smallgraphs.Balaban10Cage)
2632
+ Balaban11Cage = staticmethod(smallgraphs.Balaban11Cage)
2633
+ BidiakisCube = staticmethod(smallgraphs.BidiakisCube)
2634
+ BiggsSmithGraph = staticmethod(smallgraphs.BiggsSmithGraph)
2635
+ BlanusaFirstSnarkGraph = staticmethod(smallgraphs.BlanusaFirstSnarkGraph)
2636
+ BlanusaSecondSnarkGraph = staticmethod(smallgraphs.BlanusaSecondSnarkGraph)
2637
+ BrinkmannGraph = staticmethod(smallgraphs.BrinkmannGraph)
2638
+ BrouwerHaemersGraph = staticmethod(smallgraphs.BrouwerHaemersGraph)
2639
+ BuckyBall = staticmethod(smallgraphs.BuckyBall)
2640
+ CameronGraph = staticmethod(smallgraphs.CameronGraph)
2641
+ Cell600 = staticmethod(smallgraphs.Cell600)
2642
+ Cell120 = staticmethod(smallgraphs.Cell120)
2643
+ ChvatalGraph = staticmethod(smallgraphs.ChvatalGraph)
2644
+ ClebschGraph = staticmethod(smallgraphs.ClebschGraph)
2645
+ cocliques_HoffmannSingleton = staticmethod(distance_regular.cocliques_HoffmannSingleton)
2646
+ ConwaySmith_for_3S7 = staticmethod(distance_regular.ConwaySmith_for_3S7)
2647
+ CoxeterGraph = staticmethod(smallgraphs.CoxeterGraph)
2648
+ CubeplexGraph = staticmethod(smallgraphs.CubeplexGraph)
2649
+ DejterGraph = staticmethod(smallgraphs.DejterGraph)
2650
+ DesarguesGraph = staticmethod(smallgraphs.DesarguesGraph)
2651
+ distance_3_doubly_truncated_Golay_code_graph = staticmethod(distance_regular.distance_3_doubly_truncated_Golay_code_graph)
2652
+ DoubleStarSnark = staticmethod(smallgraphs.DoubleStarSnark)
2653
+ DoublyTruncatedWittGraph = staticmethod(distance_regular.DoublyTruncatedWittGraph)
2654
+ DurerGraph = staticmethod(smallgraphs.DurerGraph)
2655
+ DyckGraph = staticmethod(smallgraphs.DyckGraph)
2656
+ EllinghamHorton54Graph = staticmethod(smallgraphs.EllinghamHorton54Graph)
2657
+ EllinghamHorton78Graph = staticmethod(smallgraphs.EllinghamHorton78Graph)
2658
+ ErreraGraph = staticmethod(smallgraphs.ErreraGraph)
2659
+ F26AGraph = staticmethod(smallgraphs.F26AGraph)
2660
+ FlowerSnark = staticmethod(smallgraphs.FlowerSnark)
2661
+ FolkmanGraph = staticmethod(smallgraphs.FolkmanGraph)
2662
+ FosterGraph = staticmethod(smallgraphs.FosterGraph)
2663
+ FosterGraph3S6 = staticmethod(distance_regular.FosterGraph3S6)
2664
+ FranklinGraph = staticmethod(smallgraphs.FranklinGraph)
2665
+ FruchtGraph = staticmethod(smallgraphs.FruchtGraph)
2666
+ GoldnerHararyGraph = staticmethod(smallgraphs.GoldnerHararyGraph)
2667
+ GolombGraph = staticmethod(smallgraphs.GolombGraph)
2668
+ GossetGraph = staticmethod(smallgraphs.GossetGraph)
2669
+ graph_3O73 = staticmethod(distance_regular.graph_3O73)
2670
+ GrayGraph = staticmethod(smallgraphs.GrayGraph)
2671
+ GritsenkoGraph = staticmethod(smallgraphs.GritsenkoGraph)
2672
+ GrotzschGraph = staticmethod(smallgraphs.GrotzschGraph)
2673
+ HallJankoGraph = staticmethod(smallgraphs.HallJankoGraph)
2674
+ WellsGraph = staticmethod(smallgraphs.WellsGraph)
2675
+ HarborthGraph = staticmethod(smallgraphs.HarborthGraph)
2676
+ HarriesGraph = staticmethod(smallgraphs.HarriesGraph)
2677
+ HarriesWongGraph = staticmethod(smallgraphs.HarriesWongGraph)
2678
+ HeawoodGraph = staticmethod(smallgraphs.HeawoodGraph)
2679
+ HerschelGraph = staticmethod(smallgraphs.HerschelGraph)
2680
+ HigmanSimsGraph = staticmethod(smallgraphs.HigmanSimsGraph)
2681
+ HoffmanGraph = staticmethod(smallgraphs.HoffmanGraph)
2682
+ HoffmanSingletonGraph = staticmethod(smallgraphs.HoffmanSingletonGraph)
2683
+ HoltGraph = staticmethod(smallgraphs.HoltGraph)
2684
+ HortonGraph = staticmethod(smallgraphs.HortonGraph)
2685
+ IoninKharaghani765Graph = staticmethod(smallgraphs.IoninKharaghani765Graph)
2686
+ IvanovIvanovFaradjevGraph = staticmethod(distance_regular.IvanovIvanovFaradjevGraph)
2687
+ J2Graph = staticmethod(distance_regular.J2Graph)
2688
+ JankoKharaghaniGraph = staticmethod(smallgraphs.JankoKharaghaniGraph)
2689
+ JankoKharaghaniTonchevGraph = staticmethod(smallgraphs.JankoKharaghaniTonchevGraph)
2690
+ KittellGraph = staticmethod(smallgraphs.KittellGraph)
2691
+ KrackhardtKiteGraph = staticmethod(smallgraphs.KrackhardtKiteGraph)
2692
+ Klein3RegularGraph = staticmethod(smallgraphs.Klein3RegularGraph)
2693
+ Klein7RegularGraph = staticmethod(smallgraphs.Klein7RegularGraph)
2694
+ LargeWittGraph = staticmethod(distance_regular.LargeWittGraph)
2695
+ LeonardGraph = staticmethod(distance_regular.LeonardGraph)
2696
+ LjubljanaGraph = staticmethod(smallgraphs.LjubljanaGraph)
2697
+ vanLintSchrijverGraph = staticmethod(distance_regular.vanLintSchrijverGraph)
2698
+ LivingstoneGraph = staticmethod(smallgraphs.LivingstoneGraph)
2699
+ locally_GQ42_distance_transitive_graph = staticmethod(distance_regular.locally_GQ42_distance_transitive_graph)
2700
+ LocalMcLaughlinGraph = staticmethod(smallgraphs.LocalMcLaughlinGraph)
2701
+ M22Graph = staticmethod(smallgraphs.M22Graph)
2702
+ MarkstroemGraph = staticmethod(smallgraphs.MarkstroemGraph)
2703
+ MathonStronglyRegularGraph = staticmethod(smallgraphs.MathonStronglyRegularGraph)
2704
+ McGeeGraph = staticmethod(smallgraphs.McGeeGraph)
2705
+ McLaughlinGraph = staticmethod(smallgraphs.McLaughlinGraph)
2706
+ MeredithGraph = staticmethod(smallgraphs.MeredithGraph)
2707
+ MoebiusKantorGraph = staticmethod(smallgraphs.MoebiusKantorGraph)
2708
+ MoserSpindle = staticmethod(smallgraphs.MoserSpindle)
2709
+ MurtyGraph = staticmethod(smallgraphs.MurtyGraph)
2710
+ NauruGraph = staticmethod(smallgraphs.NauruGraph)
2711
+ PappusGraph = staticmethod(smallgraphs.PappusGraph)
2712
+ PoussinGraph = staticmethod(smallgraphs.PoussinGraph)
2713
+ PerkelGraph = staticmethod(smallgraphs.PerkelGraph)
2714
+ PetersenGraph = staticmethod(smallgraphs.PetersenGraph)
2715
+ RobertsonGraph = staticmethod(smallgraphs.RobertsonGraph)
2716
+ SchlaefliGraph = staticmethod(smallgraphs.SchlaefliGraph)
2717
+ shortened_00_11_binary_Golay_code_graph = staticmethod(distance_regular.shortened_00_11_binary_Golay_code_graph)
2718
+ shortened_000_111_extended_binary_Golay_code_graph = staticmethod(distance_regular.shortened_000_111_extended_binary_Golay_code_graph)
2719
+ ShrikhandeGraph = staticmethod(smallgraphs.ShrikhandeGraph)
2720
+ SimsGewirtzGraph = staticmethod(smallgraphs.SimsGewirtzGraph)
2721
+ SousselierGraph = staticmethod(smallgraphs.SousselierGraph)
2722
+ SylvesterGraph = staticmethod(smallgraphs.SylvesterGraph)
2723
+ SzekeresSnarkGraph = staticmethod(smallgraphs.SzekeresSnarkGraph)
2724
+ ThomsenGraph = staticmethod(smallgraphs.ThomsenGraph)
2725
+ TietzeGraph = staticmethod(smallgraphs.TietzeGraph)
2726
+ TricornGraph = staticmethod(smallgraphs.TricornGraph)
2727
+ Tutte12Cage = staticmethod(smallgraphs.Tutte12Cage)
2728
+ TruncatedIcosidodecahedralGraph = staticmethod(smallgraphs.TruncatedIcosidodecahedralGraph)
2729
+ TruncatedTetrahedralGraph = staticmethod(smallgraphs.TruncatedTetrahedralGraph)
2730
+ TruncatedWittGraph = staticmethod(distance_regular.TruncatedWittGraph)
2731
+ TutteCoxeterGraph = staticmethod(smallgraphs.TutteCoxeterGraph)
2732
+ TutteGraph = staticmethod(smallgraphs.TutteGraph)
2733
+ TwinplexGraph = staticmethod(smallgraphs.TwinplexGraph)
2734
+ U42Graph216 = staticmethod(smallgraphs.U42Graph216)
2735
+ U42Graph540 = staticmethod(smallgraphs.U42Graph540)
2736
+ WagnerGraph = staticmethod(smallgraphs.WagnerGraph)
2737
+ WatkinsSnarkGraph = staticmethod(smallgraphs.WatkinsSnarkGraph)
2738
+ WienerArayaGraph = staticmethod(smallgraphs.WienerArayaGraph)
2739
+ SuzukiGraph = staticmethod(smallgraphs.SuzukiGraph)
2740
+
2741
+ ###########################################################################
2742
+ # Platonic Solids
2743
+ ###########################################################################
2744
+ from .generators import platonic_solids
2745
+ DodecahedralGraph = staticmethod(platonic_solids.DodecahedralGraph)
2746
+ HexahedralGraph = staticmethod(platonic_solids.HexahedralGraph)
2747
+ IcosahedralGraph = staticmethod(platonic_solids.IcosahedralGraph)
2748
+ OctahedralGraph = staticmethod(platonic_solids.OctahedralGraph)
2749
+ TetrahedralGraph = staticmethod(platonic_solids.TetrahedralGraph)
2750
+
2751
+ ###########################################################################
2752
+ # Families
2753
+ ###########################################################################
2754
+ from . import cographs as cographs_module
2755
+ from .generators import families
2756
+ from . import strongly_regular_db
2757
+ AlternatingFormsGraph = staticmethod(distance_regular.AlternatingFormsGraph)
2758
+ AztecDiamondGraph = staticmethod(families.AztecDiamondGraph)
2759
+ BalancedTree = staticmethod(families.BalancedTree)
2760
+ BarbellGraph = staticmethod(families.BarbellGraph)
2761
+ BilinearFormsGraph = staticmethod(distance_regular.BilinearFormsGraph)
2762
+ BiwheelGraph = staticmethod(families.BiwheelGraph)
2763
+ BubbleSortGraph = staticmethod(families.BubbleSortGraph)
2764
+ CaiFurerImmermanGraph = staticmethod(families.CaiFurerImmermanGraph)
2765
+ chang_graphs = staticmethod(families.chang_graphs)
2766
+ CirculantGraph = staticmethod(families.CirculantGraph)
2767
+ cographs = staticmethod(cographs_module.cographs)
2768
+ CubeGraph = staticmethod(families.CubeGraph)
2769
+ CubeConnectedCycle = staticmethod(families.CubeConnectedCycle)
2770
+ DipoleGraph = staticmethod(families.DipoleGraph)
2771
+ distance_regular_graph = staticmethod(distance_regular.distance_regular_graph)
2772
+ DorogovtsevGoltsevMendesGraph = staticmethod(families.DorogovtsevGoltsevMendesGraph)
2773
+ DoubleGeneralizedPetersenGraph = staticmethod(families.DoubleGeneralizedPetersenGraph)
2774
+ DoubleGrassmannGraph = staticmethod(distance_regular.DoubleGrassmannGraph)
2775
+ DoubleOddGraph = staticmethod(distance_regular.DoubleOddGraph)
2776
+ EgawaGraph = staticmethod(families.EgawaGraph)
2777
+ FibonacciTree = staticmethod(families.FibonacciTree)
2778
+ FoldedCubeGraph = staticmethod(families.FoldedCubeGraph)
2779
+ FriendshipGraph = staticmethod(families.FriendshipGraph)
2780
+ FurerGadget = staticmethod(families.FurerGadget)
2781
+ FuzzyBallGraph = staticmethod(families.FuzzyBallGraph)
2782
+ GeneralisedDodecagonGraph = staticmethod(distance_regular.GeneralisedDodecagonGraph)
2783
+ GeneralisedHexagonGraph = staticmethod(distance_regular.GeneralisedHexagonGraph)
2784
+ GeneralisedOctagonGraph = staticmethod(distance_regular.GeneralisedOctagonGraph)
2785
+ GeneralizedPetersenGraph = staticmethod(families.GeneralizedPetersenGraph)
2786
+ GeneralizedSierpinskiGraph = staticmethod(families.GeneralizedSierpinskiGraph)
2787
+ GoethalsSeidelGraph = staticmethod(families.GoethalsSeidelGraph)
2788
+ GrassmannGraph = staticmethod(distance_regular.GrassmannGraph)
2789
+ HalfCube = staticmethod(distance_regular.HalfCube)
2790
+ HammingGraph = staticmethod(families.HammingGraph)
2791
+ HanoiTowerGraph = staticmethod(families.HanoiTowerGraph)
2792
+ HararyGraph = staticmethod(families.HararyGraph)
2793
+ HermitianFormsGraph = staticmethod(distance_regular.HermitianFormsGraph)
2794
+ HyperStarGraph = staticmethod(families.HyperStarGraph)
2795
+ IGraph = staticmethod(families.IGraph)
2796
+ JohnsonGraph = staticmethod(families.JohnsonGraph)
2797
+ KneserGraph = staticmethod(families.KneserGraph)
2798
+ LCFGraph = staticmethod(families.LCFGraph)
2799
+ line_graph_forbidden_subgraphs = staticmethod(families.line_graph_forbidden_subgraphs)
2800
+ LollipopGraph = staticmethod(families.LollipopGraph)
2801
+ MathonPseudocyclicMergingGraph = staticmethod(families.MathonPseudocyclicMergingGraph)
2802
+ MathonPseudocyclicStronglyRegularGraph = staticmethod(families.MathonPseudocyclicStronglyRegularGraph)
2803
+ MuzychukS6Graph = staticmethod(families.MuzychukS6Graph)
2804
+ MycielskiGraph = staticmethod(families.MycielskiGraph)
2805
+ MycielskiStep = staticmethod(families.MycielskiStep)
2806
+ NKStarGraph = staticmethod(families.NKStarGraph)
2807
+ NStarGraph = staticmethod(families.NStarGraph)
2808
+ OddGraph = staticmethod(families.OddGraph)
2809
+ PaleyGraph = staticmethod(families.PaleyGraph)
2810
+ PasechnikGraph = staticmethod(families.PasechnikGraph)
2811
+ petersen_family = staticmethod(families.petersen_family)
2812
+ RingedTree = staticmethod(families.RingedTree)
2813
+ RoseWindowGraph = staticmethod(families.RoseWindowGraph)
2814
+ SierpinskiGasketGraph = staticmethod(families.SierpinskiGasketGraph)
2815
+ SquaredSkewHadamardMatrixGraph = staticmethod(families.SquaredSkewHadamardMatrixGraph)
2816
+ SwitchedSquaredSkewHadamardMatrixGraph = staticmethod(families.SwitchedSquaredSkewHadamardMatrixGraph)
2817
+ StaircaseGraph = staticmethod(families.StaircaseGraph)
2818
+ strongly_regular_graph = staticmethod(strongly_regular_db.strongly_regular_graph)
2819
+ TabacjnGraph = staticmethod(families.TabacjnGraph)
2820
+ TadpoleGraph = staticmethod(families.TadpoleGraph)
2821
+ trees = staticmethod(families.trees)
2822
+ TruncatedBiwheelGraph = staticmethod(families.TruncatedBiwheelGraph)
2823
+ nauty_gentreeg = staticmethod(families.nauty_gentreeg)
2824
+ TuranGraph = staticmethod(families.TuranGraph)
2825
+ UstimenkoGraph = staticmethod(distance_regular.UstimenkoGraph)
2826
+ WheelGraph = staticmethod(families.WheelGraph)
2827
+ WindmillGraph = staticmethod(families.WindmillGraph)
2828
+
2829
+ ###########################################################################
2830
+ # Graphs from classical geometries over `F_q`
2831
+ ###########################################################################
2832
+ from .generators import classical_geometries
2833
+ AffineOrthogonalPolarGraph = staticmethod(classical_geometries.AffineOrthogonalPolarGraph)
2834
+ AhrensSzekeresGeneralizedQuadrangleGraph = staticmethod(classical_geometries.AhrensSzekeresGeneralizedQuadrangleGraph)
2835
+ NonisotropicOrthogonalPolarGraph = staticmethod(classical_geometries.NonisotropicOrthogonalPolarGraph)
2836
+ NonisotropicUnitaryPolarGraph = staticmethod(classical_geometries.NonisotropicUnitaryPolarGraph)
2837
+ OrthogonalDualPolarGraph = staticmethod(classical_geometries.OrthogonalDualPolarGraph)
2838
+ OrthogonalPolarGraph = staticmethod(classical_geometries.OrthogonalPolarGraph)
2839
+ SymplecticDualPolarGraph = staticmethod(classical_geometries.SymplecticDualPolarGraph)
2840
+ SymplecticPolarGraph = staticmethod(classical_geometries.SymplecticPolarGraph)
2841
+ TaylorTwographDescendantSRG = staticmethod(classical_geometries.TaylorTwographDescendantSRG)
2842
+ TaylorTwographSRG = staticmethod(classical_geometries.TaylorTwographSRG)
2843
+ T2starGeneralizedQuadrangleGraph = staticmethod(classical_geometries.T2starGeneralizedQuadrangleGraph)
2844
+ Nowhere0WordsTwoWeightCodeGraph = staticmethod(classical_geometries.Nowhere0WordsTwoWeightCodeGraph)
2845
+ HaemersGraph = staticmethod(classical_geometries.HaemersGraph)
2846
+ CossidentePenttilaGraph = staticmethod(classical_geometries.CossidentePenttilaGraph)
2847
+ UnitaryDualPolarGraph = staticmethod(classical_geometries.UnitaryDualPolarGraph)
2848
+ UnitaryPolarGraph = staticmethod(classical_geometries.UnitaryPolarGraph)
2849
+
2850
+ ###########################################################################
2851
+ # Chessboard Graphs
2852
+ ###########################################################################
2853
+ from .generators import chessboard
2854
+ ChessboardGraphGenerator = staticmethod(chessboard.ChessboardGraphGenerator)
2855
+ BishopGraph = staticmethod(chessboard.BishopGraph)
2856
+ KingGraph = staticmethod(chessboard.KingGraph)
2857
+ KnightGraph = staticmethod(chessboard.KnightGraph)
2858
+ QueenGraph = staticmethod(chessboard.QueenGraph)
2859
+ RookGraph = staticmethod(chessboard.RookGraph)
2860
+
2861
+ ###########################################################################
2862
+ # Intersection graphs
2863
+ ###########################################################################
2864
+ from .generators import intersection
2865
+ IntervalGraph = staticmethod(intersection.IntervalGraph)
2866
+ IntersectionGraph = staticmethod(intersection.IntersectionGraph)
2867
+ PermutationGraph = staticmethod(intersection.PermutationGraph)
2868
+ OrthogonalArrayBlockGraph = staticmethod(intersection.OrthogonalArrayBlockGraph)
2869
+ ToleranceGraph = staticmethod(intersection.ToleranceGraph)
2870
+
2871
+ ###########################################################################
2872
+ # Random Graphs
2873
+ ###########################################################################
2874
+ from .generators import random
2875
+ RandomBarabasiAlbert = staticmethod(random.RandomBarabasiAlbert)
2876
+ RandomBipartite = staticmethod(random.RandomBipartite)
2877
+ RandomRegularBipartite = staticmethod(random.RandomRegularBipartite)
2878
+ RandomBicubicPlanar = staticmethod(random.RandomBicubicPlanar)
2879
+ RandomBlockGraph = staticmethod(random.RandomBlockGraph)
2880
+ RandomBoundedToleranceGraph = staticmethod(random.RandomBoundedToleranceGraph)
2881
+ RandomChordalGraph = staticmethod(random.RandomChordalGraph)
2882
+ RandomGNM = staticmethod(random.RandomGNM)
2883
+ RandomGNP = staticmethod(random.RandomGNP)
2884
+ RandomHolmeKim = staticmethod(random.RandomHolmeKim)
2885
+ RandomIntervalGraph = staticmethod(random.RandomIntervalGraph)
2886
+ RandomLobster = staticmethod(random.RandomLobster)
2887
+ RandomNewmanWattsStrogatz = staticmethod(random.RandomNewmanWattsStrogatz)
2888
+ RandomProperIntervalGraph = staticmethod(random.RandomProperIntervalGraph)
2889
+ RandomRegular = staticmethod(random.RandomRegular)
2890
+ RandomShell = staticmethod(random.RandomShell)
2891
+ RandomKTree = staticmethod(random.RandomKTree)
2892
+ RandomPartialKTree = staticmethod(random.RandomPartialKTree)
2893
+ RandomToleranceGraph = staticmethod(random.RandomToleranceGraph)
2894
+ RandomTreePowerlaw = staticmethod(random.RandomTreePowerlaw)
2895
+ RandomTree = staticmethod(random.RandomTree)
2896
+ RandomTriangulation = staticmethod(random.RandomTriangulation)
2897
+ RandomUnitDiskGraph = staticmethod(random.RandomUnitDiskGraph)
2898
+
2899
+ ###########################################################################
2900
+ # Maps
2901
+ ###########################################################################
2902
+ from .generators import world_map
2903
+ WorldMap = staticmethod(world_map.WorldMap)
2904
+ EuropeMap = staticmethod(world_map.EuropeMap)
2905
+ AfricaMap = staticmethod(world_map.AfricaMap)
2906
+ USAMap = staticmethod(world_map.USAMap)
2907
+
2908
+ ###########################################################################
2909
+ # Degree Sequence
2910
+ ###########################################################################
2911
+ from .generators import degree_sequence
2912
+ DegreeSequence = staticmethod(degree_sequence.DegreeSequence)
2913
+ DegreeSequenceBipartite = staticmethod(degree_sequence.DegreeSequenceBipartite)
2914
+ DegreeSequenceConfigurationModel = staticmethod(degree_sequence.DegreeSequenceConfigurationModel)
2915
+ DegreeSequenceTree = staticmethod(degree_sequence.DegreeSequenceTree)
2916
+ DegreeSequenceExpected = staticmethod(degree_sequence.DegreeSequenceExpected)
2917
+
2918
+
2919
+ def canaug_traverse_vert(g, aut_gens, max_verts, property, dig=False, loops=False, sparse=True):
2920
+ """
2921
+ Main function for exhaustive generation. Recursive traversal of a
2922
+ canonically generated tree of isomorph free (di)graphs satisfying a
2923
+ given property.
2924
+
2925
+ INPUT:
2926
+
2927
+ - ``g`` -- current position on the tree
2928
+
2929
+ - ``aut_gens`` -- list of generators of Aut(g), in list notation
2930
+
2931
+ - ``max_verts`` -- when to retreat
2932
+
2933
+ - ``property`` -- check before traversing below g
2934
+
2935
+ - ``degree_sequence`` -- specify a degree sequence to try to obtain
2936
+
2937
+ EXAMPLES::
2938
+
2939
+ sage: from sage.graphs.graph_generators import canaug_traverse_vert
2940
+ sage: list(canaug_traverse_vert(Graph(), [], 3, lambda x: True))
2941
+ [Graph on 0 vertices, ... Graph on 3 vertices]
2942
+
2943
+ The best way to access this function is through the graphs()
2944
+ iterator:
2945
+
2946
+ Print graphs on 3 or less vertices.
2947
+
2948
+ ::
2949
+
2950
+ sage: for G in graphs(3, augment='vertices'):
2951
+ ....: print(G)
2952
+ Graph on 0 vertices
2953
+ Graph on 1 vertex
2954
+ Graph on 2 vertices
2955
+ Graph on 3 vertices
2956
+ Graph on 3 vertices
2957
+ Graph on 3 vertices
2958
+ Graph on 2 vertices
2959
+ Graph on 3 vertices
2960
+
2961
+ Print digraphs on 2 or less vertices.
2962
+
2963
+ ::
2964
+
2965
+ sage: for D in digraphs(2, augment='vertices'):
2966
+ ....: print(D)
2967
+ Digraph on 0 vertices
2968
+ Digraph on 1 vertex
2969
+ Digraph on 2 vertices
2970
+ Digraph on 2 vertices
2971
+ Digraph on 2 vertices
2972
+ """
2973
+ from sage.groups.perm_gps.partn_ref.refinement_graphs import search_tree
2974
+ if not property(g):
2975
+ return
2976
+ yield g
2977
+
2978
+ n = g.order()
2979
+ if n < max_verts:
2980
+
2981
+ # build a list representing C(g) - the vertex to be added
2982
+ # is at the end, so only specify which edges...
2983
+ # in the case of graphs, there are n possibilities,
2984
+ # and in the case of digraphs, there are 2*n.
2985
+ if dig:
2986
+ possibilities = 2 * n
2987
+ else:
2988
+ possibilities = n
2989
+ num_roots = 2**possibilities
2990
+ children = [-1]*num_roots
2991
+
2992
+ # union-find C(g) under Aut(g)
2993
+ for gen in aut_gens:
2994
+ for i in range(len(children)):
2995
+ k = 0
2996
+ for j in range(possibilities):
2997
+ if (1 << j) & i:
2998
+ if dig and j >= n:
2999
+ k += (1 << (gen[j - n] + n))
3000
+ else:
3001
+ k += (1 << gen[j])
3002
+ while children[k] != -1:
3003
+ k = children[k]
3004
+ while children[i] != -1:
3005
+ i = children[i]
3006
+ if i != k:
3007
+ # union i & k
3008
+ smaller, larger = sorted([i, k])
3009
+ children[larger] = smaller
3010
+ num_roots -= 1
3011
+
3012
+ # find representatives of orbits of C(g)
3013
+ roots = []
3014
+ found_roots = 0
3015
+ i = 0
3016
+ while found_roots < num_roots:
3017
+ if children[i] == -1:
3018
+ found_roots += 1
3019
+ roots.append(i)
3020
+ i += 1
3021
+ for i in roots:
3022
+ # construct a z for each number in roots...
3023
+ z = g.copy(sparse=sparse)
3024
+ z.add_vertex(n)
3025
+ edges = []
3026
+ if dig:
3027
+ index = 0
3028
+ while 2 * index < possibilities:
3029
+ if (1 << index) & i:
3030
+ edges.append((index, n))
3031
+ index += 1
3032
+ while index < possibilities:
3033
+ if (1 << index) & i:
3034
+ edges.append((n, index - n))
3035
+ index += 1
3036
+ else:
3037
+ index = 0
3038
+ while (1 << index) <= i:
3039
+ if (1 << index) & i:
3040
+ edges.append((index, n))
3041
+ index += 1
3042
+ z.add_edges(edges)
3043
+ z_s = []
3044
+ if property(z):
3045
+ z_s.append(z)
3046
+ if loops:
3047
+ z = z.copy(sparse=sparse)
3048
+ z.add_edge((n, n))
3049
+ if property(z):
3050
+ z_s.append(z)
3051
+ for z in z_s:
3052
+ z_aut_gens, _, canonical_relabeling = search_tree(z, [z.vertices(sort=True)], certificate=True, dig=(dig or loops))
3053
+ cut_vert = 0
3054
+ while canonical_relabeling[cut_vert] != n:
3055
+ cut_vert += 1
3056
+ sub_verts = [v for v in z if v != cut_vert]
3057
+ m_z = z.subgraph(sub_verts)
3058
+
3059
+ if m_z == g:
3060
+ for a in canaug_traverse_vert(z, z_aut_gens, max_verts, property, dig=dig, loops=loops, sparse=sparse):
3061
+ yield a
3062
+ else:
3063
+ for possibility in check_aut(z_aut_gens, cut_vert, n):
3064
+ if m_z.relabel(dict(enumerate(possibility)), check_input=False, inplace=False) == g:
3065
+ for a in canaug_traverse_vert(z, z_aut_gens, max_verts, property, dig=dig, loops=loops, sparse=sparse):
3066
+ yield a
3067
+ break
3068
+
3069
+
3070
+ def check_aut(aut_gens, cut_vert, n):
3071
+ """
3072
+ Helper function for exhaustive generation.
3073
+
3074
+ At the start, check_aut is given a set of generators for the
3075
+ automorphism group, aut_gens. We already know we are looking for
3076
+ an element of the auto- morphism group that sends cut_vert to n,
3077
+ and check_aut generates these for the canaug_traverse function.
3078
+
3079
+ EXAMPLES:
3080
+
3081
+ Note that the last two entries indicate that none of the
3082
+ automorphism group has yet been searched - we are starting at the
3083
+ identity [0, 1, 2, 3] and so far that is all we have seen. We
3084
+ return automorphisms mapping 2 to 3::
3085
+
3086
+ sage: from sage.graphs.graph_generators import check_aut
3087
+ sage: list( check_aut( [ [0, 3, 2, 1], [1, 0, 3, 2], [2, 1, 0, 3] ], 2, 3))
3088
+ [[1, 0, 3, 2], [1, 2, 3, 0]]
3089
+ """
3090
+ from copy import copy
3091
+ perm = list(range(n + 1))
3092
+ seen_perms = [perm]
3093
+ unchecked_perms = [perm]
3094
+ while unchecked_perms:
3095
+ perm = unchecked_perms.pop(0)
3096
+ for gen in aut_gens:
3097
+ new_perm = copy(perm)
3098
+ for i in range(len(perm)):
3099
+ new_perm[i] = gen[perm[i]]
3100
+ if new_perm not in seen_perms:
3101
+ seen_perms.append(new_perm)
3102
+ unchecked_perms.append(new_perm)
3103
+ if new_perm[cut_vert] == n:
3104
+ yield new_perm
3105
+
3106
+
3107
+ def canaug_traverse_edge(g, aut_gens, property, dig=False, loops=False, sparse=True):
3108
+ """
3109
+ Main function for exhaustive generation. Recursive traversal of a
3110
+ canonically generated tree of isomorph free graphs satisfying a
3111
+ given property.
3112
+
3113
+ INPUT:
3114
+
3115
+ - ``g`` -- current position on the tree
3116
+
3117
+ - ``aut_gens`` -- list of generators of Aut(g), in list notation
3118
+
3119
+ - ``property`` -- check before traversing below g
3120
+
3121
+ EXAMPLES::
3122
+
3123
+ sage: from sage.graphs.graph_generators import canaug_traverse_edge
3124
+ sage: G = Graph(3)
3125
+ sage: list(canaug_traverse_edge(G, [], lambda x: True))
3126
+ [Graph on 3 vertices, ... Graph on 3 vertices]
3127
+
3128
+ The best way to access this function is through the graphs()
3129
+ iterator:
3130
+
3131
+ Print graphs on 3 or less vertices.
3132
+
3133
+ ::
3134
+
3135
+ sage: for G in graphs(3): # needs nauty
3136
+ ....: print(G)
3137
+ Graph on 3 vertices
3138
+ Graph on 3 vertices
3139
+ Graph on 3 vertices
3140
+ Graph on 3 vertices
3141
+
3142
+ Print digraphs on 3 or less vertices.
3143
+
3144
+ ::
3145
+
3146
+ sage: for G in digraphs(3): # needs nauty
3147
+ ....: print(G)
3148
+ Digraph on 3 vertices
3149
+ Digraph on 3 vertices
3150
+ ...
3151
+ Digraph on 3 vertices
3152
+ Digraph on 3 vertices
3153
+ """
3154
+ from sage.groups.perm_gps.partn_ref.refinement_graphs import search_tree
3155
+
3156
+ if not property(g):
3157
+ return
3158
+ yield g
3159
+ n = g.order()
3160
+ if dig:
3161
+ max_size = n * (n - 1)
3162
+ else:
3163
+ max_size = (n * (n - 1)) >> 1 # >> 1 is just / 2 (this is n choose 2)
3164
+ if loops:
3165
+ max_size += n
3166
+ if g.size() < max_size:
3167
+ # build a list representing C(g) - the edge to be added
3168
+ # is one of max_size choices
3169
+ if dig:
3170
+ children = [[(j, i) for i in range(n)] for j in range(n)]
3171
+ else:
3172
+ children = [[(j, i) for i in range(j)] for j in range(n)]
3173
+ # union-find C(g) under Aut(g)
3174
+ orbits = list(range(n))
3175
+ for gen in aut_gens:
3176
+ for iii in range(n):
3177
+ if orbits[gen[iii]] != orbits[iii]:
3178
+ temp = orbits[gen[iii]]
3179
+ for jjj in range(n):
3180
+ if orbits[jjj] == temp:
3181
+ orbits[jjj] = orbits[iii]
3182
+ if dig:
3183
+ jjj_range = list(range(iii)) + list(range(iii + 1, n))
3184
+ else:
3185
+ jjj_range = list(range(iii)) # iii > jjj
3186
+ for jjj in jjj_range:
3187
+ i, j = iii, jjj
3188
+ if dig:
3189
+ x, y = gen[i], gen[j]
3190
+ else:
3191
+ y, x = sorted([gen[i], gen[j]])
3192
+ if children[i][j] != children[x][y]:
3193
+ x_val, y_val = x, y
3194
+ i_val, j_val = i, j
3195
+ if dig:
3196
+ while (x_val, y_val) != children[x_val][y_val]:
3197
+ x_val, y_val = children[x_val][y_val]
3198
+ while (i_val, j_val) != children[i_val][j_val]:
3199
+ i_val, j_val = children[i_val][j_val]
3200
+ else:
3201
+ while (x_val, y_val) != children[x_val][y_val]:
3202
+ y_val, x_val = sorted(children[x_val][y_val])
3203
+ while (i_val, j_val) != children[i_val][j_val]:
3204
+ j_val, i_val = sorted(children[i_val][j_val])
3205
+ while (x, y) != (x_val, y_val):
3206
+ xx, yy = x, y
3207
+ x, y = children[x][y]
3208
+ children[xx][yy] = (x_val, y_val)
3209
+ while (i, j) != (i_val, j_val):
3210
+ ii, jj = i, j
3211
+ i, j = children[i][j]
3212
+ children[ii][jj] = (i_val, j_val)
3213
+ if x < i:
3214
+ children[i][j] = (x, y)
3215
+ elif x > i:
3216
+ children[x][y] = (i, j)
3217
+ elif y < j:
3218
+ children[i][j] = (x, y)
3219
+ elif y > j:
3220
+ children[x][y] = (i, j)
3221
+ else:
3222
+ continue
3223
+ # find representatives of orbits of C(g)
3224
+ roots = []
3225
+ for i in range(n):
3226
+ if dig:
3227
+ j_range = list(range(i)) + list(range(i + 1, n))
3228
+ else:
3229
+ j_range = list(range(i))
3230
+ for j in j_range:
3231
+ if children[i][j] == (i, j):
3232
+ roots.append((i, j))
3233
+ if loops:
3234
+ seen = []
3235
+ for i in range(n):
3236
+ if orbits[i] not in seen:
3237
+ roots.append((i, i))
3238
+ seen.append(orbits[i])
3239
+ for i, j in roots:
3240
+ if g.has_edge(i, j):
3241
+ continue
3242
+ # construct a z for each edge in roots...
3243
+ z = g.copy(sparse=sparse)
3244
+ z.add_edge(i, j)
3245
+ if not property(z):
3246
+ continue
3247
+ z_aut_gens, _, canonical_relabeling = search_tree(z, [z.vertices(sort=True)], certificate=True, dig=(dig or loops))
3248
+ relabel_inverse = [0]*n
3249
+ for ii in range(n):
3250
+ relabel_inverse[canonical_relabeling[ii]] = ii
3251
+ z_can = z.relabel(canonical_relabeling, inplace=False)
3252
+ cut_edge_can = z_can.edges(labels=False, sort=True)[-1]
3253
+ cut_edge = [relabel_inverse[cut_edge_can[0]], relabel_inverse[cut_edge_can[1]]]
3254
+ if dig:
3255
+ cut_edge = tuple(cut_edge)
3256
+ else:
3257
+ cut_edge = tuple(sorted(cut_edge))
3258
+
3259
+ from copy import copy
3260
+ m_z = copy(z)
3261
+ m_z.delete_edge(cut_edge)
3262
+ if m_z == g:
3263
+ for a in canaug_traverse_edge(z, z_aut_gens, property, dig=dig, loops=loops, sparse=sparse):
3264
+ yield a
3265
+ else:
3266
+ for possibility in check_aut_edge(z_aut_gens, cut_edge, i, j, n, dig=dig):
3267
+ if m_z.relabel(possibility, inplace=False) == g:
3268
+ for a in canaug_traverse_edge(z, z_aut_gens, property, dig=dig, loops=loops, sparse=sparse):
3269
+ yield a
3270
+ break
3271
+
3272
+
3273
+ def check_aut_edge(aut_gens, cut_edge, i, j, n, dig=False):
3274
+ """
3275
+ Helper function for exhaustive generation.
3276
+
3277
+ At the start, check_aut_edge is given a set of generators for the
3278
+ automorphism group, aut_gens. We already know we are looking for
3279
+ an element of the auto- morphism group that sends cut_edge to {i,
3280
+ j}, and check_aut generates these for the canaug_traverse
3281
+ function.
3282
+
3283
+ EXAMPLES:
3284
+
3285
+ Note that the last two entries indicate that none of the
3286
+ automorphism group has yet been searched - we are starting at the
3287
+ identity [0, 1, 2, 3] and so far that is all we have seen. We
3288
+ return automorphisms mapping 2 to 3::
3289
+
3290
+ sage: from sage.graphs.graph_generators import check_aut
3291
+ sage: list( check_aut( [ [0, 3, 2, 1], [1, 0, 3, 2], [2, 1, 0, 3] ], 2, 3))
3292
+ [[1, 0, 3, 2], [1, 2, 3, 0]]
3293
+ """
3294
+ from copy import copy
3295
+ perm = list(range(n))
3296
+ seen_perms = [perm]
3297
+ unchecked_perms = [perm]
3298
+ while unchecked_perms:
3299
+ perm = unchecked_perms.pop(0)
3300
+ for gen in aut_gens:
3301
+ new_perm = copy(perm)
3302
+ for ii in range(n):
3303
+ new_perm[ii] = gen[perm[ii]]
3304
+ if new_perm not in seen_perms:
3305
+ seen_perms.append(new_perm)
3306
+ unchecked_perms.append(new_perm)
3307
+ if new_perm[cut_edge[0]] == i and new_perm[cut_edge[1]] == j:
3308
+ yield new_perm
3309
+ if not dig and new_perm[cut_edge[0]] == j and new_perm[cut_edge[1]] == i:
3310
+ yield new_perm
3311
+
3312
+
3313
+ # Easy access to the graph generators from the command line:
3314
+ graphs = GraphGenerators()