passagemath-graphs 10.6.1__cp310-cp310-manylinux_2_24_x86_64.manylinux_2_28_x86_64.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 (263) hide show
  1. passagemath_graphs-10.6.1.dist-info/METADATA +303 -0
  2. passagemath_graphs-10.6.1.dist-info/METADATA.bak +304 -0
  3. passagemath_graphs-10.6.1.dist-info/RECORD +263 -0
  4. passagemath_graphs-10.6.1.dist-info/WHEEL +6 -0
  5. passagemath_graphs-10.6.1.dist-info/top_level.txt +2 -0
  6. passagemath_graphs.libs/libgmp-6e109695.so.10.5.0 +0 -0
  7. sage/all__sagemath_graphs.py +40 -0
  8. sage/combinat/abstract_tree.py +2723 -0
  9. sage/combinat/all__sagemath_graphs.py +34 -0
  10. sage/combinat/binary_tree.py +5306 -0
  11. sage/combinat/cluster_algebra_quiver/all.py +22 -0
  12. sage/combinat/cluster_algebra_quiver/cluster_seed.py +5208 -0
  13. sage/combinat/cluster_algebra_quiver/interact.py +124 -0
  14. sage/combinat/cluster_algebra_quiver/mutation_class.py +625 -0
  15. sage/combinat/cluster_algebra_quiver/mutation_type.py +1555 -0
  16. sage/combinat/cluster_algebra_quiver/quiver.py +2290 -0
  17. sage/combinat/cluster_algebra_quiver/quiver_mutation_type.py +2468 -0
  18. sage/combinat/designs/MOLS_handbook_data.py +570 -0
  19. sage/combinat/designs/all.py +58 -0
  20. sage/combinat/designs/bibd.py +1655 -0
  21. sage/combinat/designs/block_design.py +1071 -0
  22. sage/combinat/designs/covering_array.py +269 -0
  23. sage/combinat/designs/covering_design.py +530 -0
  24. sage/combinat/designs/database.py +5615 -0
  25. sage/combinat/designs/design_catalog.py +122 -0
  26. sage/combinat/designs/designs_pyx.cpython-310-x86_64-linux-gnu.so +0 -0
  27. sage/combinat/designs/designs_pyx.pxd +21 -0
  28. sage/combinat/designs/designs_pyx.pyx +993 -0
  29. sage/combinat/designs/difference_family.py +3951 -0
  30. sage/combinat/designs/difference_matrices.py +279 -0
  31. sage/combinat/designs/evenly_distributed_sets.cpython-310-x86_64-linux-gnu.so +0 -0
  32. sage/combinat/designs/evenly_distributed_sets.pyx +661 -0
  33. sage/combinat/designs/ext_rep.py +1064 -0
  34. sage/combinat/designs/gen_quadrangles_with_spread.cpython-310-x86_64-linux-gnu.so +0 -0
  35. sage/combinat/designs/gen_quadrangles_with_spread.pyx +339 -0
  36. sage/combinat/designs/group_divisible_designs.py +361 -0
  37. sage/combinat/designs/incidence_structures.py +2357 -0
  38. sage/combinat/designs/latin_squares.py +581 -0
  39. sage/combinat/designs/orthogonal_arrays.py +2244 -0
  40. sage/combinat/designs/orthogonal_arrays_build_recursive.py +1780 -0
  41. sage/combinat/designs/orthogonal_arrays_find_recursive.cpython-310-x86_64-linux-gnu.so +0 -0
  42. sage/combinat/designs/orthogonal_arrays_find_recursive.pyx +967 -0
  43. sage/combinat/designs/resolvable_bibd.py +815 -0
  44. sage/combinat/designs/steiner_quadruple_systems.py +1306 -0
  45. sage/combinat/designs/subhypergraph_search.cpython-310-x86_64-linux-gnu.so +0 -0
  46. sage/combinat/designs/subhypergraph_search.pyx +530 -0
  47. sage/combinat/designs/twographs.py +306 -0
  48. sage/combinat/finite_state_machine.py +14874 -0
  49. sage/combinat/finite_state_machine_generators.py +2006 -0
  50. sage/combinat/graph_path.py +448 -0
  51. sage/combinat/interval_posets.py +3908 -0
  52. sage/combinat/nu_tamari_lattice.py +269 -0
  53. sage/combinat/ordered_tree.py +1446 -0
  54. sage/combinat/posets/all.py +46 -0
  55. sage/combinat/posets/bubble_shuffle.py +247 -0
  56. sage/combinat/posets/cartesian_product.py +493 -0
  57. sage/combinat/posets/d_complete.py +182 -0
  58. sage/combinat/posets/elements.py +273 -0
  59. sage/combinat/posets/forest.py +30 -0
  60. sage/combinat/posets/hasse_cython.cpython-310-x86_64-linux-gnu.so +0 -0
  61. sage/combinat/posets/hasse_cython.pyx +174 -0
  62. sage/combinat/posets/hasse_diagram.py +3672 -0
  63. sage/combinat/posets/hochschild_lattice.py +158 -0
  64. sage/combinat/posets/incidence_algebras.py +794 -0
  65. sage/combinat/posets/lattices.py +5117 -0
  66. sage/combinat/posets/linear_extension_iterator.cpython-310-x86_64-linux-gnu.so +0 -0
  67. sage/combinat/posets/linear_extension_iterator.pyx +292 -0
  68. sage/combinat/posets/linear_extensions.py +1038 -0
  69. sage/combinat/posets/mobile.py +275 -0
  70. sage/combinat/posets/moebius_algebra.py +776 -0
  71. sage/combinat/posets/poset_examples.py +2181 -0
  72. sage/combinat/posets/posets.py +9360 -0
  73. sage/combinat/rooted_tree.py +1070 -0
  74. sage/combinat/shard_order.py +239 -0
  75. sage/combinat/tamari_lattices.py +384 -0
  76. sage/combinat/yang_baxter_graph.py +923 -0
  77. sage/databases/all__sagemath_graphs.py +1 -0
  78. sage/databases/knotinfo_db.py +1231 -0
  79. sage/ext_data/all__sagemath_graphs.py +1 -0
  80. sage/ext_data/graphs/graph_plot_js.html +330 -0
  81. sage/ext_data/kenzo/CP2.txt +45 -0
  82. sage/ext_data/kenzo/CP3.txt +349 -0
  83. sage/ext_data/kenzo/CP4.txt +4774 -0
  84. sage/ext_data/kenzo/README.txt +49 -0
  85. sage/ext_data/kenzo/S4.txt +20 -0
  86. sage/graphs/all.py +42 -0
  87. sage/graphs/asteroidal_triples.cpython-310-x86_64-linux-gnu.so +0 -0
  88. sage/graphs/asteroidal_triples.pyx +320 -0
  89. sage/graphs/base/all.py +1 -0
  90. sage/graphs/base/boost_graph.cpython-310-x86_64-linux-gnu.so +0 -0
  91. sage/graphs/base/boost_graph.pxd +106 -0
  92. sage/graphs/base/boost_graph.pyx +3045 -0
  93. sage/graphs/base/c_graph.cpython-310-x86_64-linux-gnu.so +0 -0
  94. sage/graphs/base/c_graph.pxd +106 -0
  95. sage/graphs/base/c_graph.pyx +5096 -0
  96. sage/graphs/base/dense_graph.cpython-310-x86_64-linux-gnu.so +0 -0
  97. sage/graphs/base/dense_graph.pxd +28 -0
  98. sage/graphs/base/dense_graph.pyx +801 -0
  99. sage/graphs/base/graph_backends.cpython-310-x86_64-linux-gnu.so +0 -0
  100. sage/graphs/base/graph_backends.pxd +5 -0
  101. sage/graphs/base/graph_backends.pyx +797 -0
  102. sage/graphs/base/overview.py +85 -0
  103. sage/graphs/base/sparse_graph.cpython-310-x86_64-linux-gnu.so +0 -0
  104. sage/graphs/base/sparse_graph.pxd +90 -0
  105. sage/graphs/base/sparse_graph.pyx +1653 -0
  106. sage/graphs/base/static_dense_graph.cpython-310-x86_64-linux-gnu.so +0 -0
  107. sage/graphs/base/static_dense_graph.pxd +5 -0
  108. sage/graphs/base/static_dense_graph.pyx +1032 -0
  109. sage/graphs/base/static_sparse_backend.cpython-310-x86_64-linux-gnu.so +0 -0
  110. sage/graphs/base/static_sparse_backend.pxd +27 -0
  111. sage/graphs/base/static_sparse_backend.pyx +1583 -0
  112. sage/graphs/base/static_sparse_graph.cpython-310-x86_64-linux-gnu.so +0 -0
  113. sage/graphs/base/static_sparse_graph.pxd +37 -0
  114. sage/graphs/base/static_sparse_graph.pyx +1375 -0
  115. sage/graphs/bipartite_graph.py +2732 -0
  116. sage/graphs/centrality.cpython-310-x86_64-linux-gnu.so +0 -0
  117. sage/graphs/centrality.pyx +1038 -0
  118. sage/graphs/cographs.py +519 -0
  119. sage/graphs/comparability.cpython-310-x86_64-linux-gnu.so +0 -0
  120. sage/graphs/comparability.pyx +851 -0
  121. sage/graphs/connectivity.cpython-310-x86_64-linux-gnu.so +0 -0
  122. sage/graphs/connectivity.pxd +157 -0
  123. sage/graphs/connectivity.pyx +4813 -0
  124. sage/graphs/convexity_properties.cpython-310-x86_64-linux-gnu.so +0 -0
  125. sage/graphs/convexity_properties.pxd +16 -0
  126. sage/graphs/convexity_properties.pyx +870 -0
  127. sage/graphs/digraph.py +4754 -0
  128. sage/graphs/digraph_generators.py +1993 -0
  129. sage/graphs/distances_all_pairs.cpython-310-x86_64-linux-gnu.so +0 -0
  130. sage/graphs/distances_all_pairs.pxd +12 -0
  131. sage/graphs/distances_all_pairs.pyx +2938 -0
  132. sage/graphs/domination.py +1363 -0
  133. sage/graphs/dot2tex_utils.py +100 -0
  134. sage/graphs/edge_connectivity.cpython-310-x86_64-linux-gnu.so +0 -0
  135. sage/graphs/edge_connectivity.pyx +1215 -0
  136. sage/graphs/generators/all.py +1 -0
  137. sage/graphs/generators/basic.py +1769 -0
  138. sage/graphs/generators/chessboard.py +538 -0
  139. sage/graphs/generators/classical_geometries.py +1611 -0
  140. sage/graphs/generators/degree_sequence.py +235 -0
  141. sage/graphs/generators/distance_regular.cpython-310-x86_64-linux-gnu.so +0 -0
  142. sage/graphs/generators/distance_regular.pyx +2846 -0
  143. sage/graphs/generators/families.py +4759 -0
  144. sage/graphs/generators/intersection.py +565 -0
  145. sage/graphs/generators/platonic_solids.py +262 -0
  146. sage/graphs/generators/random.py +2623 -0
  147. sage/graphs/generators/smallgraphs.py +5741 -0
  148. sage/graphs/generators/world_map.py +724 -0
  149. sage/graphs/generic_graph.py +26868 -0
  150. sage/graphs/generic_graph_pyx.cpython-310-x86_64-linux-gnu.so +0 -0
  151. sage/graphs/generic_graph_pyx.pxd +34 -0
  152. sage/graphs/generic_graph_pyx.pyx +1673 -0
  153. sage/graphs/genus.cpython-310-x86_64-linux-gnu.so +0 -0
  154. sage/graphs/genus.pyx +622 -0
  155. sage/graphs/graph.py +9645 -0
  156. sage/graphs/graph_coloring.cpython-310-x86_64-linux-gnu.so +0 -0
  157. sage/graphs/graph_coloring.pyx +2284 -0
  158. sage/graphs/graph_database.py +1177 -0
  159. sage/graphs/graph_decompositions/all.py +1 -0
  160. sage/graphs/graph_decompositions/bandwidth.cpython-310-x86_64-linux-gnu.so +0 -0
  161. sage/graphs/graph_decompositions/bandwidth.pyx +428 -0
  162. sage/graphs/graph_decompositions/clique_separators.cpython-310-x86_64-linux-gnu.so +0 -0
  163. sage/graphs/graph_decompositions/clique_separators.pyx +616 -0
  164. sage/graphs/graph_decompositions/cutwidth.cpython-310-x86_64-linux-gnu.so +0 -0
  165. sage/graphs/graph_decompositions/cutwidth.pyx +753 -0
  166. sage/graphs/graph_decompositions/fast_digraph.cpython-310-x86_64-linux-gnu.so +0 -0
  167. sage/graphs/graph_decompositions/fast_digraph.pxd +13 -0
  168. sage/graphs/graph_decompositions/fast_digraph.pyx +212 -0
  169. sage/graphs/graph_decompositions/graph_products.cpython-310-x86_64-linux-gnu.so +0 -0
  170. sage/graphs/graph_decompositions/graph_products.pyx +508 -0
  171. sage/graphs/graph_decompositions/modular_decomposition.cpython-310-x86_64-linux-gnu.so +0 -0
  172. sage/graphs/graph_decompositions/modular_decomposition.pxd +27 -0
  173. sage/graphs/graph_decompositions/modular_decomposition.pyx +1536 -0
  174. sage/graphs/graph_decompositions/slice_decomposition.cpython-310-x86_64-linux-gnu.so +0 -0
  175. sage/graphs/graph_decompositions/slice_decomposition.pxd +18 -0
  176. sage/graphs/graph_decompositions/slice_decomposition.pyx +1106 -0
  177. sage/graphs/graph_decompositions/tree_decomposition.cpython-310-x86_64-linux-gnu.so +0 -0
  178. sage/graphs/graph_decompositions/tree_decomposition.pxd +17 -0
  179. sage/graphs/graph_decompositions/tree_decomposition.pyx +1996 -0
  180. sage/graphs/graph_decompositions/vertex_separation.cpython-310-x86_64-linux-gnu.so +0 -0
  181. sage/graphs/graph_decompositions/vertex_separation.pxd +5 -0
  182. sage/graphs/graph_decompositions/vertex_separation.pyx +1963 -0
  183. sage/graphs/graph_editor.py +82 -0
  184. sage/graphs/graph_generators.py +3314 -0
  185. sage/graphs/graph_generators_pyx.cpython-310-x86_64-linux-gnu.so +0 -0
  186. sage/graphs/graph_generators_pyx.pyx +95 -0
  187. sage/graphs/graph_input.py +812 -0
  188. sage/graphs/graph_latex.py +2064 -0
  189. sage/graphs/graph_list.py +410 -0
  190. sage/graphs/graph_plot.py +1756 -0
  191. sage/graphs/graph_plot_js.py +338 -0
  192. sage/graphs/hyperbolicity.cpython-310-x86_64-linux-gnu.so +0 -0
  193. sage/graphs/hyperbolicity.pyx +1704 -0
  194. sage/graphs/hypergraph_generators.py +364 -0
  195. sage/graphs/independent_sets.cpython-310-x86_64-linux-gnu.so +0 -0
  196. sage/graphs/independent_sets.pxd +13 -0
  197. sage/graphs/independent_sets.pyx +402 -0
  198. sage/graphs/isgci.py +1033 -0
  199. sage/graphs/isoperimetric_inequalities.cpython-310-x86_64-linux-gnu.so +0 -0
  200. sage/graphs/isoperimetric_inequalities.pyx +489 -0
  201. sage/graphs/line_graph.cpython-310-x86_64-linux-gnu.so +0 -0
  202. sage/graphs/line_graph.pyx +743 -0
  203. sage/graphs/lovasz_theta.py +77 -0
  204. sage/graphs/matching.py +1633 -0
  205. sage/graphs/matching_covered_graph.py +3591 -0
  206. sage/graphs/orientations.py +1489 -0
  207. sage/graphs/partial_cube.py +459 -0
  208. sage/graphs/path_enumeration.cpython-310-x86_64-linux-gnu.so +0 -0
  209. sage/graphs/path_enumeration.pyx +2040 -0
  210. sage/graphs/pq_trees.py +1129 -0
  211. sage/graphs/print_graphs.py +201 -0
  212. sage/graphs/schnyder.py +865 -0
  213. sage/graphs/spanning_tree.cpython-310-x86_64-linux-gnu.so +0 -0
  214. sage/graphs/spanning_tree.pyx +1457 -0
  215. sage/graphs/strongly_regular_db.cpython-310-x86_64-linux-gnu.so +0 -0
  216. sage/graphs/strongly_regular_db.pyx +3340 -0
  217. sage/graphs/traversals.cpython-310-x86_64-linux-gnu.so +0 -0
  218. sage/graphs/traversals.pxd +9 -0
  219. sage/graphs/traversals.pyx +1872 -0
  220. sage/graphs/trees.cpython-310-x86_64-linux-gnu.so +0 -0
  221. sage/graphs/trees.pxd +15 -0
  222. sage/graphs/trees.pyx +310 -0
  223. sage/graphs/tutte_polynomial.py +713 -0
  224. sage/graphs/views.cpython-310-x86_64-linux-gnu.so +0 -0
  225. sage/graphs/views.pyx +794 -0
  226. sage/graphs/weakly_chordal.cpython-310-x86_64-linux-gnu.so +0 -0
  227. sage/graphs/weakly_chordal.pyx +604 -0
  228. sage/groups/all__sagemath_graphs.py +1 -0
  229. sage/groups/perm_gps/all__sagemath_graphs.py +1 -0
  230. sage/groups/perm_gps/partn_ref/all__sagemath_graphs.py +1 -0
  231. sage/groups/perm_gps/partn_ref/refinement_graphs.cpython-310-x86_64-linux-gnu.so +0 -0
  232. sage/groups/perm_gps/partn_ref/refinement_graphs.pxd +38 -0
  233. sage/groups/perm_gps/partn_ref/refinement_graphs.pyx +1666 -0
  234. sage/knots/all.py +6 -0
  235. sage/knots/free_knotinfo_monoid.py +507 -0
  236. sage/knots/gauss_code.py +291 -0
  237. sage/knots/knot.py +682 -0
  238. sage/knots/knot_table.py +284 -0
  239. sage/knots/knotinfo.py +2900 -0
  240. sage/knots/link.py +4715 -0
  241. sage/sandpiles/all.py +13 -0
  242. sage/sandpiles/examples.py +225 -0
  243. sage/sandpiles/sandpile.py +6365 -0
  244. sage/topology/all.py +22 -0
  245. sage/topology/cell_complex.py +1214 -0
  246. sage/topology/cubical_complex.py +1976 -0
  247. sage/topology/delta_complex.py +1806 -0
  248. sage/topology/filtered_simplicial_complex.py +744 -0
  249. sage/topology/moment_angle_complex.py +823 -0
  250. sage/topology/simplicial_complex.py +5160 -0
  251. sage/topology/simplicial_complex_catalog.py +92 -0
  252. sage/topology/simplicial_complex_examples.py +1680 -0
  253. sage/topology/simplicial_complex_homset.py +205 -0
  254. sage/topology/simplicial_complex_morphism.py +836 -0
  255. sage/topology/simplicial_set.py +4102 -0
  256. sage/topology/simplicial_set_catalog.py +55 -0
  257. sage/topology/simplicial_set_constructions.py +2954 -0
  258. sage/topology/simplicial_set_examples.py +865 -0
  259. sage/topology/simplicial_set_morphism.py +1464 -0
  260. sage_wheels/share/graphs/brouwer_srg_database.json +1 -0
  261. sage_wheels/share/graphs/graphs.db +0 -0
  262. sage_wheels/share/graphs/isgci_sage.xml +11116 -0
  263. sage_wheels/share/graphs/smallgraphs.txt +565 -0
@@ -0,0 +1,2181 @@
1
+ # sage_setup: distribution = sagemath-graphs
2
+ # sage.doctest: needs sage.combinat sage.modules
3
+ r"""
4
+ Catalog of posets and lattices
5
+
6
+ Some common posets can be accessed through the ``posets.<tab>`` object::
7
+
8
+ sage: posets.PentagonPoset()
9
+ Finite lattice containing 5 elements
10
+
11
+ Moreover, the set of all posets of order `n` is represented by ``Posets(n)``::
12
+
13
+ sage: Posets(5)
14
+ Posets containing 5 elements
15
+
16
+ The infinite set of all posets can be used to find minimal examples::
17
+
18
+ sage: # needs nauty
19
+ sage: for P in Posets():
20
+ ....: if not P.is_series_parallel():
21
+ ....: break
22
+ sage: P
23
+ Finite poset containing 4 elements
24
+
25
+ **Catalog of common posets:**
26
+
27
+ .. csv-table::
28
+ :class: contentstable
29
+ :widths: 30, 70
30
+ :delim: |
31
+
32
+ :meth:`~Posets.AntichainPoset` | Return an antichain on `n` elements.
33
+ :meth:`~Posets.BooleanLattice` | Return the Boolean lattice on `2^n` elements.
34
+ :meth:`~Posets.BubblePoset` | Return the Bubble lattice for `(m,n)`.
35
+ :meth:`~Posets.ChainPoset` | Return a chain on `n` elements.
36
+ :meth:`~Posets.Crown` | Return the crown poset on `2n` elements.
37
+ :meth:`~Posets.DexterSemilattice` | Return the Dexter semilattice.
38
+ :meth:`~Posets.DiamondPoset` | Return the lattice of rank two on `n` elements.
39
+ :meth:`~Posets.DivisorLattice` | Return the divisor lattice of an integer.
40
+ :meth:`~Posets.DoubleTailedDiamond` | Return the double tailed diamond poset on `2n + 2` elements.
41
+ :meth:`~Posets.HochschildLattice` | Return the Hochschild lattice for `n`.
42
+ :meth:`~Posets.IntegerCompositions` | Return the poset of integer compositions of `n`.
43
+ :meth:`~Posets.IntegerPartitions` | Return the poset of integer partitions of ``n``.
44
+ :meth:`~Posets.IntegerPartitionsDominanceOrder` | Return the lattice of integer partitions of the integer `n` ordered by dominance.
45
+ :meth:`~Posets.MobilePoset` | Return the mobile poset formed by the `ribbon` with `hangers` below and an `anchor` above.
46
+ :meth:`~Posets.NoncrossingPartitions` | Return the poset of noncrossing partitions of a finite Coxeter group ``W``.
47
+ :meth:`~Posets.PentagonPoset` | Return the Pentagon poset.
48
+ :meth:`~Posets.PermutationPattern` | Return the Permutation pattern poset.
49
+ :meth:`~Posets.PermutationPatternInterval` | Return an interval in the Permutation pattern poset.
50
+ :meth:`~Posets.PermutationPatternOccurrenceInterval` | Return the occurrence poset for a pair of comparable elements in the Permutation pattern poset.
51
+ :meth:`~Posets.PowerPoset` | Return a power poset.
52
+ :meth:`~Posets.ProductOfChains` | Return a product of chain posets.
53
+ :meth:`~Posets.RandomLattice` | Return a random lattice on `n` elements.
54
+ :meth:`~Posets.RandomPoset` | Return a random poset on `n` elements.
55
+ :meth:`~Posets.RibbonPoset` | Return a ribbon on `n` elements with descents at `descents`.
56
+ :meth:`~Posets.RestrictedIntegerPartitions` | Return the poset of integer partitions of `n`, ordered by restricted refinement.
57
+ :meth:`~Posets.SetPartitions` | Return the poset of set partitions of the set `\{1,\dots,n\}`.
58
+ :meth:`~Posets.ShardPoset` | Return the shard intersection order.
59
+ :meth:`~Posets.ShufflePoset` | Return the Shuffle lattice for `(m,n)`.
60
+ :meth:`~Posets.SSTPoset` | Return the poset on semistandard tableaux of shape `s` and largest entry `f` that is ordered by componentwise comparison.
61
+ :meth:`~Posets.StandardExample` | Return the standard example of a poset with dimension `n`.
62
+ :meth:`~Posets.SymmetricGroupAbsoluteOrderPoset` | The poset of permutations with respect to absolute order.
63
+ :meth:`~Posets.SymmetricGroupBruhatIntervalPoset` | The poset of permutations with respect to Bruhat order.
64
+ :meth:`~Posets.SymmetricGroupBruhatOrderPoset` | The poset of permutations with respect to Bruhat order.
65
+ :meth:`~Posets.SymmetricGroupWeakOrderPoset` | The poset of permutations of `\{ 1, 2, \ldots, n \}` with respect to the weak order.
66
+ :meth:`~Posets.TamariLattice` | Return the Tamari lattice.
67
+ :meth:`~Posets.TetrahedralPoset` | Return the Tetrahedral poset with `n-1` layers based on the input colors.
68
+ :meth:`~Posets.UpDownPoset` | Return the up-down poset on `n` elements.
69
+ :meth:`~Posets.YoungDiagramPoset` | Return the poset of cells in the Young diagram of a partition.
70
+ :meth:`~Posets.YoungsLattice` | Return Young's Lattice up to rank `n`.
71
+ :meth:`~Posets.YoungsLatticePrincipalOrderIdeal` | Return the principal order ideal of the partition `lam` in Young's Lattice.
72
+ :meth:`~Posets.YoungFibonacci` | Return the Young-Fibonacci lattice up to rank `n`.
73
+
74
+ **Other available posets:**
75
+
76
+ .. csv-table::
77
+ :class: contentstable
78
+ :widths: 30, 70
79
+ :delim: |
80
+
81
+ :meth:`~sage.geometry.polyhedron.base4.Polyhedron_base4.face_lattice` | Return the face lattice of a polyhedron.
82
+ :meth:`~sage.geometry.polyhedron.combinatorial_polyhedron.base.CombinatorialPolyhedron.face_lattice` | Return the face lattice of a combinatorial polyhedron.
83
+
84
+ Constructions
85
+ -------------
86
+ """
87
+ # ****************************************************************************
88
+ # Copyright (C) 2008 Peter Jipsen <jipsen@chapman.edu>,
89
+ # Franco Saliola <saliola@gmail.com>
90
+ #
91
+ # Distributed under the terms of the GNU General Public License (GPL)
92
+ #
93
+ # This code is distributed in the hope that it will be useful,
94
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
95
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
96
+ # General Public License for more details.
97
+ #
98
+ # The full text of the GPL is available at:
99
+ #
100
+ # https://www.gnu.org/licenses/
101
+ # ****************************************************************************
102
+
103
+ from sage.misc.classcall_metaclass import ClasscallMetaclass
104
+ import sage.categories.posets
105
+ from sage.combinat.permutation import Permutations, Permutation, to_standard
106
+ from sage.combinat.posets.posets import Poset, FinitePoset, FinitePosets_n
107
+ from sage.combinat.posets import bubble_shuffle, hochschild_lattice
108
+ from sage.combinat.posets.d_complete import DCompletePoset
109
+ from sage.combinat.posets.mobile import MobilePoset as Mobile
110
+ from sage.combinat.posets.lattices import (LatticePoset, MeetSemilattice,
111
+ JoinSemilattice, FiniteLatticePoset)
112
+ from sage.categories.finite_posets import FinitePosets
113
+ from sage.categories.finite_lattice_posets import FiniteLatticePosets
114
+ from sage.graphs.digraph import DiGraph
115
+ from sage.rings.integer import Integer
116
+ from sage.sets.non_negative_integers import NonNegativeIntegers
117
+
118
+
119
+ def check_int(n, minimum=0):
120
+ """
121
+ Check that ``n`` is an integer at least equal to ``minimum``.
122
+
123
+ This is a boilerplate function ensuring input safety.
124
+
125
+ INPUT:
126
+
127
+ - ``n`` -- anything
128
+
129
+ - ``minimum`` -- an optional integer (default: 0)
130
+
131
+ EXAMPLES::
132
+
133
+ sage: from sage.combinat.posets.poset_examples import check_int
134
+ sage: check_int(6, 3)
135
+ 6
136
+ sage: check_int(6)
137
+ 6
138
+
139
+ sage: check_int(-1)
140
+ Traceback (most recent call last):
141
+ ...
142
+ ValueError: number of elements must be a nonnegative integer, not -1
143
+
144
+ sage: check_int(1, 3)
145
+ Traceback (most recent call last):
146
+ ...
147
+ ValueError: number of elements must be an integer at least 3, not 1
148
+
149
+ sage: check_int('junk')
150
+ Traceback (most recent call last):
151
+ ...
152
+ ValueError: number of elements must be a nonnegative integer, not junk
153
+ """
154
+ if minimum == 0:
155
+ msg = "a nonnegative integer"
156
+ else:
157
+ msg = f"an integer at least {minimum}"
158
+ if n not in NonNegativeIntegers() or n < minimum:
159
+ raise ValueError("number of elements must be " + msg + f", not {n}")
160
+ return Integer(n)
161
+
162
+
163
+ class Posets(metaclass=ClasscallMetaclass):
164
+ r"""
165
+ A collection of posets and lattices.
166
+
167
+ EXAMPLES::
168
+
169
+ sage: posets.BooleanLattice(3)
170
+ Finite lattice containing 8 elements
171
+ sage: posets.ChainPoset(3)
172
+ Finite lattice containing 3 elements
173
+ sage: posets.RandomPoset(17,.15)
174
+ Finite poset containing 17 elements
175
+
176
+ The category of all posets::
177
+
178
+ sage: Posets()
179
+ Category of posets
180
+
181
+ The enumerated set of all posets on `3` elements, up to an
182
+ isomorphism::
183
+
184
+ sage: Posets(3)
185
+ Posets containing 3 elements
186
+
187
+ .. SEEALSO:: :class:`~sage.categories.posets.Posets`, :class:`FinitePosets`, :func:`Poset`
188
+
189
+ TESTS::
190
+
191
+ sage: P = Posets
192
+ sage: TestSuite(P).run()
193
+ """
194
+ @staticmethod
195
+ def __classcall__(cls, n=None):
196
+ r"""
197
+ Return either the category of all posets, or the finite
198
+ enumerated set of all finite posets on ``n`` elements up to an
199
+ isomorphism.
200
+
201
+ EXAMPLES::
202
+
203
+ sage: Posets()
204
+ Category of posets
205
+ sage: Posets(4)
206
+ Posets containing 4 elements
207
+ """
208
+ if n is None:
209
+ return sage.categories.posets.Posets()
210
+ n = check_int(n)
211
+ return FinitePosets_n(n)
212
+
213
+ @staticmethod
214
+ def BooleanLattice(n, facade=None, use_subsets=False):
215
+ r"""
216
+ Return the Boolean lattice containing `2^n` elements.
217
+
218
+ - ``n`` -- integer; number of elements will be `2^n`
219
+ - ``facade`` -- boolean; whether to make the returned poset a
220
+ facade poset (see :mod:`sage.categories.facade_sets`); the
221
+ default behaviour is the same as the default behaviour of
222
+ the :func:`~sage.combinat.posets.posets.Poset` constructor
223
+ - ``use_subsets`` -- boolean (default: ``False``); if ``True``,
224
+ then label the elements by subsets of `\{1, 2, \ldots, n\}`;
225
+ otherwise label the elements by `0, 1, 2, \ldots, 2^n-1`
226
+
227
+ EXAMPLES::
228
+
229
+ sage: posets.BooleanLattice(5)
230
+ Finite lattice containing 32 elements
231
+
232
+ sage: sorted(posets.BooleanLattice(2))
233
+ [0, 1, 2, 3]
234
+ sage: sorted(posets.BooleanLattice(2, use_subsets=True), key=list)
235
+ [{}, {1}, {1, 2}, {2}]
236
+
237
+ TESTS:
238
+
239
+ Check isomorphism::
240
+
241
+ sage: B5 = posets.BooleanLattice(5)
242
+ sage: B5S = posets.BooleanLattice(5, use_subsets=True)
243
+ sage: B5.is_isomorphic(B5S)
244
+ True
245
+
246
+ Check the corner cases::
247
+
248
+ sage: list(posets.BooleanLattice(0, use_subsets=True))
249
+ [{}]
250
+ sage: list(posets.BooleanLattice(1, use_subsets=True))
251
+ [{}, {1}]
252
+ """
253
+ n = check_int(n)
254
+ if n == 0:
255
+ if use_subsets:
256
+ from sage.sets.set import Set
257
+ return LatticePoset(([Set()], []), facade=facade)
258
+ return LatticePoset(([0], []), facade=facade)
259
+ if n == 1:
260
+ if use_subsets:
261
+ from sage.sets.set import Set
262
+ V = [Set(), Set([1])]
263
+ return LatticePoset((V, [V]), facade=facade)
264
+ return LatticePoset(([0, 1], [[0, 1]]), facade=facade)
265
+
266
+ if use_subsets:
267
+ from sage.sets.set import Set
268
+ cur_level = [frozenset(range(1, n + 1))]
269
+ D = DiGraph()
270
+ D.add_vertex(Set(cur_level[0]))
271
+ while cur_level:
272
+ next_level = set()
273
+ for X in cur_level:
274
+ for i in X:
275
+ Y = X.difference([i])
276
+ D.add_edge(Set(Y), Set(X))
277
+ next_level.add(Y)
278
+ cur_level = next_level
279
+ return FiniteLatticePoset(D, category=FiniteLatticePosets(),
280
+ facade=facade)
281
+
282
+ D = DiGraph({v: [Integer(v | (1 << y))
283
+ for y in range(n) if v & (1 << y) == 0]
284
+ for v in range(2**n)})
285
+ return FiniteLatticePoset(hasse_diagram=D,
286
+ category=FiniteLatticePosets(),
287
+ facade=facade)
288
+
289
+ BubblePoset = staticmethod(bubble_shuffle.BubblePoset)
290
+
291
+ ShufflePoset = staticmethod(bubble_shuffle.ShufflePoset)
292
+
293
+ HochschildLattice = staticmethod(hochschild_lattice.hochschild_lattice)
294
+
295
+ @staticmethod
296
+ def ChainPoset(n, facade=None):
297
+ r"""
298
+ Return a chain (a totally ordered poset) containing `n` elements.
299
+
300
+ - ``n`` -- integer; number of elements
301
+ - ``facade`` -- boolean; whether to make the returned poset a
302
+ facade poset (see :mod:`sage.categories.facade_sets`); the
303
+ default behaviour is the same as the default behaviour of
304
+ the :func:`~sage.combinat.posets.posets.Poset` constructor
305
+
306
+ EXAMPLES::
307
+
308
+ sage: C = posets.ChainPoset(6); C
309
+ Finite lattice containing 6 elements
310
+ sage: C.linear_extension()
311
+ [0, 1, 2, 3, 4, 5]
312
+
313
+ TESTS::
314
+
315
+ sage: for i in range(5):
316
+ ....: for j in range(5):
317
+ ....: if C.covers(C(i),C(j)) and j != i+1:
318
+ ....: print("TEST FAILED")
319
+
320
+ Check that :issue:`8422` is solved::
321
+
322
+ sage: posets.ChainPoset(0)
323
+ Finite lattice containing 0 elements
324
+ sage: C = posets.ChainPoset(1); C
325
+ Finite lattice containing 1 elements
326
+ sage: C.cover_relations()
327
+ []
328
+ sage: C = posets.ChainPoset(2); C
329
+ Finite lattice containing 2 elements
330
+ sage: C.cover_relations()
331
+ [[0, 1]]
332
+ """
333
+ n = check_int(n)
334
+ D = DiGraph([range(n), [[x, x + 1] for x in range(n - 1)]],
335
+ format='vertices_and_edges')
336
+ return FiniteLatticePoset(hasse_diagram=D,
337
+ category=FiniteLatticePosets(),
338
+ facade=facade)
339
+
340
+ @staticmethod
341
+ def AntichainPoset(n, facade=None):
342
+ """
343
+ Return an antichain (a poset with no comparable elements)
344
+ containing `n` elements.
345
+
346
+ INPUT:
347
+
348
+ - ``n`` -- integer; number of elements
349
+ - ``facade`` -- boolean; whether to make the returned poset a
350
+ facade poset (see :mod:`sage.categories.facade_sets`); the
351
+ default behaviour is the same as the default behaviour of
352
+ the :func:`~sage.combinat.posets.posets.Poset` constructor
353
+
354
+ EXAMPLES::
355
+
356
+ sage: A = posets.AntichainPoset(6); A
357
+ Finite poset containing 6 elements
358
+
359
+ TESTS::
360
+
361
+ sage: for i in range(5):
362
+ ....: for j in range(5):
363
+ ....: if A.covers(A(i),A(j)):
364
+ ....: print("TEST FAILED")
365
+
366
+ TESTS:
367
+
368
+ Check that :issue:`8422` is solved::
369
+
370
+ sage: posets.AntichainPoset(0)
371
+ Finite poset containing 0 elements
372
+ sage: C = posets.AntichainPoset(1); C
373
+ Finite poset containing 1 elements
374
+ sage: C.cover_relations()
375
+ []
376
+ sage: C = posets.AntichainPoset(2); C
377
+ Finite poset containing 2 elements
378
+ sage: C.cover_relations()
379
+ []
380
+ """
381
+ n = check_int(n)
382
+ return Poset((range(n), []), facade=facade)
383
+
384
+ @staticmethod
385
+ def PentagonPoset(facade=None):
386
+ """
387
+ Return the Pentagon poset.
388
+
389
+ INPUT:
390
+
391
+ - ``facade`` -- boolean; whether to make the returned poset a
392
+ facade poset (see :mod:`sage.categories.facade_sets`); the
393
+ default behaviour is the same as the default behaviour of
394
+ the :func:`~sage.combinat.posets.posets.Poset` constructor
395
+
396
+ EXAMPLES::
397
+
398
+ sage: P = posets.PentagonPoset(); P
399
+ Finite lattice containing 5 elements
400
+ sage: P.cover_relations()
401
+ [[0, 1], [0, 2], [1, 4], [2, 3], [3, 4]]
402
+
403
+ TESTS:
404
+
405
+ This is smallest lattice that is not modular::
406
+
407
+ sage: P.is_modular()
408
+ False
409
+
410
+ This poset and the :meth:`DiamondPoset` are the two smallest
411
+ lattices which are not distributive::
412
+
413
+ sage: P.is_distributive()
414
+ False
415
+ sage: posets.DiamondPoset(5).is_distributive()
416
+ False
417
+ """
418
+ return LatticePoset([[1, 2], [4], [3], [4], []], facade=facade)
419
+
420
+ @staticmethod
421
+ def DiamondPoset(n, facade=None):
422
+ """
423
+ Return the lattice of rank two containing ``n`` elements.
424
+
425
+ INPUT:
426
+
427
+ - ``n`` -- number of elements, an integer at least 3
428
+
429
+ - ``facade`` -- boolean; whether to make the returned poset a
430
+ facade poset (see :mod:`sage.categories.facade_sets`); the
431
+ default behaviour is the same as the default behaviour of
432
+ the :func:`~sage.combinat.posets.posets.Poset` constructor
433
+
434
+ EXAMPLES::
435
+
436
+ sage: posets.DiamondPoset(7)
437
+ Finite lattice containing 7 elements
438
+ """
439
+ n = check_int(n, 3)
440
+ c = [[n - 1] for x in range(n)]
441
+ c[0] = list(range(1, n - 1))
442
+ c[n - 1] = []
443
+ D = DiGraph({v: c[v] for v in range(n)}, format='dict_of_lists')
444
+ return FiniteLatticePoset(hasse_diagram=D,
445
+ category=FiniteLatticePosets(),
446
+ facade=facade)
447
+
448
+ @staticmethod
449
+ def Crown(n, facade=None):
450
+ r"""
451
+ Return the crown poset of `2n` elements.
452
+
453
+ In this poset every element `i` for `0 \leq i \leq n-1`
454
+ is covered by elements `i+n` and `i+n+1`, except that
455
+ `n-1` is covered by `n` and `n+1`.
456
+
457
+ INPUT:
458
+
459
+ - ``n`` -- number of elements, an integer at least 2
460
+
461
+ - ``facade`` -- boolean; whether to make the returned poset a
462
+ facade poset (see :mod:`sage.categories.facade_sets`); the
463
+ default behaviour is the same as the default behaviour of
464
+ the :func:`~sage.combinat.posets.posets.Poset` constructor
465
+
466
+ EXAMPLES::
467
+
468
+ sage: posets.Crown(3)
469
+ Finite poset containing 6 elements
470
+ """
471
+ n = check_int(n, 2)
472
+ D = {i: [i + n, i + n + 1] for i in range(n - 1)}
473
+ D[n - 1] = [n, n + n - 1]
474
+ return FinitePoset(hasse_diagram=DiGraph(D), category=FinitePosets(),
475
+ facade=facade)
476
+
477
+ @staticmethod
478
+ def DivisorLattice(n, facade=None):
479
+ r"""
480
+ Return the divisor lattice of an integer.
481
+
482
+ Elements of the lattice are divisors of `n`, and we have
483
+ `x \leq y` in the lattice if `x` divides `y`.
484
+
485
+ INPUT:
486
+
487
+ - ``n`` -- integer
488
+ - ``facade`` -- boolean; whether to make the returned poset a
489
+ facade poset (see :mod:`sage.categories.facade_sets`); the
490
+ default behaviour is the same as the default behaviour of
491
+ the :func:`~sage.combinat.posets.posets.Poset` constructor
492
+
493
+ EXAMPLES::
494
+
495
+ sage: P = posets.DivisorLattice(12)
496
+ sage: sorted(P.cover_relations())
497
+ [[1, 2], [1, 3], [2, 4], [2, 6], [3, 6], [4, 12], [6, 12]]
498
+
499
+ sage: P = posets.DivisorLattice(10, facade=False)
500
+ sage: P(2) < P(5)
501
+ False
502
+
503
+ TESTS::
504
+
505
+ sage: posets.DivisorLattice(1)
506
+ Finite lattice containing 1 elements with distinguished linear extension
507
+ """
508
+ from sage.arith.misc import divisors, is_prime
509
+ n = check_int(n, 1)
510
+ Div_n = divisors(n)
511
+ hasse = DiGraph([Div_n, lambda a, b: b % a == 0 and is_prime(b // a)])
512
+ return FiniteLatticePoset(hasse, elements=Div_n, facade=facade,
513
+ category=FiniteLatticePosets())
514
+
515
+ @staticmethod
516
+ def HessenbergPoset(H):
517
+ r"""
518
+ Return the poset associated to a Hessenberg function ``H``.
519
+
520
+ A *Hessenberg function* (of length `n`) is a function `H: \{1,\ldots,n\}
521
+ \to \{1,\ldots,n\}` such that `\max(i, H(i-1)) \leq H(i) \leq n` for all
522
+ `i` (where `H(0) = 0` by convention). The corresponding poset is given
523
+ by `i < j` (in the poset) if and only if `H(i) < j` (as integers).
524
+ These posets correspond to the natural unit interval order posets.
525
+
526
+ INPUT:
527
+
528
+ - ``H`` -- list of the Hessenberg function values
529
+ (without `H(0)`)
530
+
531
+ EXAMPLES::
532
+
533
+ sage: P = posets.HessenbergPoset([2, 3, 5, 5, 5]); P
534
+ Finite poset containing 5 elements
535
+ sage: P.cover_relations()
536
+ [[2, 4], [2, 5], [1, 3], [1, 4], [1, 5]]
537
+
538
+ TESTS::
539
+
540
+ sage: P = posets.HessenbergPoset([2, 2, 6, 4, 5, 6])
541
+ Traceback (most recent call last):
542
+ ...
543
+ ValueError: [2, 2, 6, 4, 5, 6] is not a Hessenberg function
544
+ sage: P = posets.HessenbergPoset([]); P
545
+ Finite poset containing 0 elements
546
+ """
547
+ n = len(H)
548
+ if not all(max(i+1, H[i-1]) <= H[i] for i in range(1, n)) or 0 < n < H[-1]:
549
+ raise ValueError(f"{H} is not a Hessenberg function")
550
+ return Poset((tuple(range(1, n+1)), lambda i, j: H[i-1] < j))
551
+
552
+ @staticmethod
553
+ def IntegerCompositions(n):
554
+ r"""
555
+ Return the poset of integer compositions of the integer ``n``.
556
+
557
+ A composition of a positive integer `n` is a list of positive
558
+ integers that sum to `n`. The order is reverse refinement:
559
+ `p = [p_1,p_2,...,p_l] \leq q = [q_1,q_2,...,q_m]` if `q`
560
+ consists of an integer composition of `p_1`, followed by an
561
+ integer composition of `p_2`, and so on.
562
+
563
+ EXAMPLES::
564
+
565
+ sage: P = posets.IntegerCompositions(7); P
566
+ Finite poset containing 64 elements
567
+ sage: len(P.cover_relations())
568
+ 192
569
+ """
570
+ from sage.combinat.composition import Compositions
571
+ C = Compositions(n)
572
+ return Poset((C, [[c, d] for c in C for d in C if d.is_finer(c)]),
573
+ cover_relations=False)
574
+
575
+ @staticmethod
576
+ def IntegerPartitions(n):
577
+ """
578
+ Return the poset of integer partitions of the integer ``n``.
579
+
580
+ A partition of a positive integer `n` is a non-increasing list
581
+ of positive integers that sum to `n`. If `p` and `q` are
582
+ integer partitions of `n`, then `p` covers `q` if and only
583
+ if `q` is obtained from `p` by joining two parts of `p`
584
+ (and sorting, if necessary).
585
+
586
+ EXAMPLES::
587
+
588
+ sage: P = posets.IntegerPartitions(7); P
589
+ Finite poset containing 15 elements
590
+ sage: len(P.cover_relations())
591
+ 28
592
+ """
593
+ def lower_covers(partition):
594
+ r"""
595
+ Nested function for computing the lower covers
596
+ of elements in the poset of integer partitions.
597
+ """
598
+ lc = []
599
+ for i in range(len(partition) - 1):
600
+ for j in range(i + 1, len(partition)):
601
+ new_partition = partition[:]
602
+ del new_partition[j]
603
+ del new_partition[i]
604
+ new_partition.append(partition[i] + partition[j])
605
+ new_partition.sort(reverse=True)
606
+ tup = tuple(new_partition)
607
+ if tup not in lc:
608
+ lc.append(tup)
609
+ return lc
610
+ from sage.combinat.partition import Partitions
611
+ H = DiGraph(dict([[tuple(p), lower_covers(p)] for p in Partitions(n)]))
612
+ return Poset(H.reverse())
613
+
614
+ @staticmethod
615
+ def RestrictedIntegerPartitions(n):
616
+ """
617
+ Return the poset of integer partitions of the integer `n`
618
+ ordered by restricted refinement.
619
+
620
+ That is, if `p` and `q` are integer partitions of `n`, then
621
+ `p` covers `q` if and only if `q` is obtained from `p` by
622
+ joining two distinct parts of `p` (and sorting, if necessary).
623
+
624
+ EXAMPLES::
625
+
626
+ sage: P = posets.RestrictedIntegerPartitions(7); P
627
+ Finite poset containing 15 elements
628
+ sage: len(P.cover_relations())
629
+ 17
630
+ """
631
+ def lower_covers(partition):
632
+ r"""
633
+ Nested function for computing the lower covers of elements in the
634
+ restricted poset of integer partitions.
635
+ """
636
+ lc = []
637
+ for i in range(len(partition) - 1):
638
+ for j in range(i + 1, len(partition)):
639
+ if partition[i] != partition[j]:
640
+ new_partition = partition[:]
641
+ del new_partition[j]
642
+ del new_partition[i]
643
+ new_partition.append(partition[i] + partition[j])
644
+ new_partition.sort(reverse=True)
645
+ tup = tuple(new_partition)
646
+ if tup not in lc:
647
+ lc.append(tup)
648
+ return lc
649
+ from sage.combinat.partition import Partitions
650
+ H = DiGraph(dict([[tuple(p), lower_covers(p)] for p in Partitions(n)]))
651
+ return Poset(H.reverse())
652
+
653
+ @staticmethod
654
+ def IntegerPartitionsDominanceOrder(n):
655
+ r"""
656
+ Return the lattice of integer partitions of the integer `n`
657
+ ordered by dominance.
658
+
659
+ That is, if `p=(p_1,\ldots,p_i)` and `q=(q_1,\ldots,q_j)` are
660
+ integer partitions of `n`, then `p \geq q` if and
661
+ only if `p_1+\cdots+p_k \geq q_1+\cdots+q_k` for all `k`.
662
+
663
+ INPUT:
664
+
665
+ - ``n`` -- positive integer
666
+
667
+ EXAMPLES::
668
+
669
+ sage: P = posets.IntegerPartitionsDominanceOrder(6); P
670
+ Finite lattice containing 11 elements
671
+ sage: P.cover_relations()
672
+ [[[1, 1, 1, 1, 1, 1], [2, 1, 1, 1, 1]],
673
+ [[2, 1, 1, 1, 1], [2, 2, 1, 1]],
674
+ [[2, 2, 1, 1], [2, 2, 2]],
675
+ [[2, 2, 1, 1], [3, 1, 1, 1]],
676
+ [[2, 2, 2], [3, 2, 1]],
677
+ [[3, 1, 1, 1], [3, 2, 1]],
678
+ [[3, 2, 1], [3, 3]],
679
+ [[3, 2, 1], [4, 1, 1]],
680
+ [[3, 3], [4, 2]],
681
+ [[4, 1, 1], [4, 2]],
682
+ [[4, 2], [5, 1]],
683
+ [[5, 1], [6]]]
684
+ """
685
+ n = check_int(n)
686
+ from sage.combinat.partition import Partitions, Partition
687
+ return LatticePoset((Partitions(n), Partition.dominates)).dual()
688
+
689
+ @staticmethod
690
+ def PowerPoset(n):
691
+ r"""
692
+ Return the power poset on `n` element posets.
693
+
694
+ Elements of the power poset are all posets on
695
+ the set `\{0, 1, \ldots, n-1\}` ordered by extension.
696
+ That is, the antichain of `n` elements is the bottom and
697
+ `P_a \le P_b` in the power poset if `P_b` is an extension
698
+ of `P_a`.
699
+
700
+ These were studied in [Bru1994]_.
701
+
702
+ EXAMPLES::
703
+
704
+ sage: # needs nauty
705
+ sage: P3 = posets.PowerPoset(3); P3
706
+ Finite meet-semilattice containing 19 elements
707
+ sage: all(P.is_chain() for P in P3.maximal_elements())
708
+ True
709
+
710
+ TESTS::
711
+
712
+ sage: # needs nauty
713
+ sage: P0 = posets.PowerPoset(0); P0
714
+ Finite meet-semilattice containing 1 elements
715
+ sage: P0[0]
716
+ Finite poset containing 0 elements
717
+ sage: P1 = posets.PowerPoset(1); P1
718
+ Finite meet-semilattice containing 1 elements
719
+ sage: P1[0]
720
+ Finite poset containing 1 elements
721
+ sage: P1[0][0]
722
+ 0
723
+ """
724
+ # Todo: Make this faster.
725
+ n = check_int(n)
726
+ all_pos_n = set()
727
+ Pn = list(Posets(n))
728
+ for P in Pn:
729
+ for r in Permutations(P):
730
+ all_pos_n.add(P.relabel(list(r)))
731
+
732
+ return MeetSemilattice((all_pos_n,
733
+ lambda A, B: all(B.is_lequal(x, y)
734
+ for x, y in A.cover_relations_iterator())))
735
+
736
+ @staticmethod
737
+ def ProductOfChains(chain_lengths, facade=None):
738
+ """
739
+ Return a product of chains.
740
+
741
+ - ``chain_lengths`` -- list of nonnegative integers; number of
742
+ elements in each chain
743
+
744
+ - ``facade`` -- boolean; whether to make the returned poset a
745
+ facade poset (see :mod:`sage.categories.facade_sets`); the
746
+ default behaviour is the same as the default behaviour of
747
+ the :func:`~sage.combinat.posets.posets.Poset` constructor
748
+
749
+ EXAMPLES::
750
+
751
+ sage: P = posets.ProductOfChains([2, 2]); P
752
+ Finite lattice containing 4 elements
753
+ sage: P.linear_extension()
754
+ [(0, 0), (0, 1), (1, 0), (1, 1)]
755
+ sage: P.upper_covers((0,0))
756
+ [(0, 1), (1, 0)]
757
+ sage: P.lower_covers((1,1))
758
+ [(0, 1), (1, 0)]
759
+
760
+ TESTS::
761
+
762
+ sage: P = posets.ProductOfChains([]); P
763
+ Finite lattice containing 0 elements
764
+ sage: P = posets.ProductOfChains([3, 0, 1]); P
765
+ Finite lattice containing 0 elements
766
+ sage: P = posets.ProductOfChains([1,1,1,1]); P
767
+ Finite lattice containing 1 elements
768
+ """
769
+ try:
770
+ l = [Integer(x) for x in chain_lengths]
771
+ except TypeError:
772
+ raise TypeError("parameter chain_lengths must be a list of integers, not {}".format(chain_lengths))
773
+ if any(x < 0 for x in l):
774
+ raise TypeError("parameter chain_lengths must be a list of nonnegative integers, not {}".format(l))
775
+
776
+ # given the empty list, we expect the empty poset.
777
+ if not chain_lengths:
778
+ return LatticePoset(facade=facade)
779
+ from sage.categories.cartesian_product import cartesian_product
780
+ elements = cartesian_product([range(i) for i in l])
781
+
782
+ def compare(a, b):
783
+ return all(x <= y for x, y in zip(a, b))
784
+ return LatticePoset([elements, compare], facade=facade)
785
+
786
+ @staticmethod
787
+ def RandomPoset(n, p):
788
+ r"""
789
+ Generate a random poset on ``n`` elements according to a
790
+ probability ``p``.
791
+
792
+ INPUT:
793
+
794
+ - ``n`` -- number of elements, a nonnegative integer
795
+
796
+ - ``p`` -- a probability, a real number between 0 and 1 (inclusive)
797
+
798
+ OUTPUT:
799
+
800
+ A poset on `n` elements. The probability `p` roughly measures
801
+ width/height of the output: `p=0` always generates an antichain,
802
+ `p=1` will return a chain. To create interesting examples,
803
+ keep the probability small, perhaps on the order of `1/n`.
804
+
805
+ EXAMPLES::
806
+
807
+ sage: set_random_seed(0) # Results are reproducible
808
+ sage: P = posets.RandomPoset(5, 0.3)
809
+ sage: P.cover_relations()
810
+ [[5, 4], [4, 2], [1, 2]]
811
+
812
+ .. SEEALSO:: :meth:`RandomLattice`
813
+
814
+ TESTS::
815
+
816
+ sage: posets.RandomPoset(6, 'garbage')
817
+ Traceback (most recent call last):
818
+ ...
819
+ TypeError: probability must be a real number, not garbage
820
+
821
+ sage: posets.RandomPoset(6, -0.5)
822
+ Traceback (most recent call last):
823
+ ...
824
+ ValueError: probability must be between 0 and 1, not -0.5
825
+
826
+ sage: posets.RandomPoset(0, 0.5)
827
+ Finite poset containing 0 elements
828
+ """
829
+ from sage.misc.prandom import random
830
+ n = check_int(n)
831
+ try:
832
+ p = float(p)
833
+ except (TypeError, ValueError):
834
+ raise TypeError(f"probability must be a real number, not {p}")
835
+ if p < 0 or p > 1:
836
+ raise ValueError(f"probability must be between 0 and 1, not {p}")
837
+
838
+ D = DiGraph(loops=False, multiedges=False)
839
+ D.add_vertices(range(n))
840
+ for i in range(n):
841
+ for j in range(i + 1, n):
842
+ if random() < p:
843
+ D.add_edge(i, j)
844
+ D.relabel(list(Permutations(n).random_element()))
845
+ return Poset(D, cover_relations=False)
846
+
847
+ @staticmethod
848
+ def RandomLattice(n, p, properties=None):
849
+ r"""
850
+ Return a random lattice on ``n`` elements.
851
+
852
+ INPUT:
853
+
854
+ - ``n`` -- number of elements, a nonnegative integer
855
+
856
+ - ``p`` -- a probability, a positive real number less than one
857
+
858
+ - ``properties`` -- list of properties for the lattice. Currently
859
+ implemented:
860
+
861
+ * ``None``, no restrictions for lattices to create
862
+ * ``'planar'``, the lattice has an upward planar drawing
863
+ * ``'dismantlable'`` (implicated by ``'planar'``)
864
+ * ``'distributive'`` (implicated by ``'stone'``)
865
+ * ``'stone'``
866
+
867
+ OUTPUT:
868
+
869
+ A lattice on `n` elements. When ``properties`` is ``None``,
870
+ the probability `p` roughly measures number of covering
871
+ relations of the lattice. To create interesting examples, make
872
+ the probability a little below one, for example `0.9`.
873
+
874
+ Currently parameter ``p`` has no effect only when ``properties``
875
+ is not ``None``.
876
+
877
+ .. NOTE::
878
+
879
+ Results are reproducible in same Sage version only. Underlying
880
+ algorithm may change in future versions.
881
+
882
+ EXAMPLES::
883
+
884
+ sage: set_random_seed(0) # Results are reproducible
885
+ sage: L = posets.RandomLattice(8, 0.995); L
886
+ Finite lattice containing 8 elements
887
+ sage: L.cover_relations()
888
+ [[7, 6], [7, 3], [7, 1], ..., [5, 4], [2, 4], [1, 4], [0, 4]]
889
+ sage: L = posets.RandomLattice(10, 0, properties=['dismantlable'])
890
+ sage: L.is_dismantlable()
891
+ True
892
+
893
+ .. SEEALSO:: :meth:`RandomPoset`
894
+
895
+ TESTS::
896
+
897
+ sage: posets.RandomLattice(6, 'garbage')
898
+ Traceback (most recent call last):
899
+ ...
900
+ TypeError: probability must be a real number, not garbage
901
+
902
+ sage: posets.RandomLattice(6, -0.5)
903
+ Traceback (most recent call last):
904
+ ...
905
+ ValueError: probability must be a positive real number and below 1, not -0.5
906
+
907
+ sage: posets.RandomLattice(10, 0.5, properties=['junk'])
908
+ Traceback (most recent call last):
909
+ ...
910
+ ValueError: unknown value junk for 'properties'
911
+
912
+ sage: posets.RandomLattice(0, 0.5)
913
+ Finite lattice containing 0 elements
914
+ """
915
+ from copy import copy
916
+ n = check_int(n)
917
+ try:
918
+ p = float(p)
919
+ except Exception:
920
+ raise TypeError(f"probability must be a real number, not {p}")
921
+ if p < 0 or p >= 1:
922
+ raise ValueError("probability must be a positive real number and below 1, not {}".format(p))
923
+
924
+ if properties is None:
925
+ # Basic case, no special properties for lattice asked.
926
+ if n <= 3:
927
+ return posets.ChainPoset(n)
928
+ covers = _random_lattice(n, p)
929
+ covers_dict = {i: covers[i] for i in range(n)}
930
+ D = DiGraph(covers_dict)
931
+ D.relabel([i - 1 for i in Permutations(n).random_element()])
932
+ return LatticePoset(D, cover_relations=True)
933
+
934
+ if isinstance(properties, str):
935
+ properties = {properties}
936
+ else:
937
+ properties = set(properties)
938
+
939
+ known_properties = {'planar', 'dismantlable', 'distributive', 'stone'}
940
+ errors = properties.difference(known_properties)
941
+ if errors:
942
+ raise ValueError("unknown value %s for 'properties'" % errors.pop())
943
+
944
+ if n <= 3:
945
+ # Change this, if property='complemented' is added
946
+ return posets.ChainPoset(n)
947
+
948
+ # Handling properties: planar => dismantlable, stone => distributive
949
+ if 'planar' in properties:
950
+ properties.discard('dismantlable')
951
+ if 'stone' in properties:
952
+ properties.discard('distributive')
953
+
954
+ # Test property combinations that are not implemented.
955
+ if 'distributive' in properties and len(properties) > 1:
956
+ raise NotImplementedError("combining 'distributive' with other properties is not implemented")
957
+ if 'stone' in properties and len(properties) > 1:
958
+ raise NotImplementedError("combining 'stone' with other properties is not implemented")
959
+
960
+ if properties == {'planar'}:
961
+ D = _random_planar_lattice(n)
962
+ D.relabel([i - 1 for i in Permutations(n).random_element()])
963
+ return LatticePoset(D)
964
+
965
+ if properties == {'dismantlable'}:
966
+ D = _random_dismantlable_lattice(n)
967
+ D.relabel([i - 1 for i in Permutations(n).random_element()])
968
+ return LatticePoset(D)
969
+
970
+ if properties == {'stone'}:
971
+ D = _random_stone_lattice(n)
972
+ D.relabel([i - 1 for i in Permutations(n).random_element()])
973
+ return LatticePoset(D)
974
+
975
+ if properties == {'distributive'}:
976
+ tmp = Poset(_random_distributive_lattice(n)).order_ideals_lattice(as_ideals=False)
977
+ D = copy(tmp._hasse_diagram)
978
+ D.relabel([i - 1 for i in Permutations(n).random_element()])
979
+ return LatticePoset(D)
980
+
981
+ raise AssertionError("bug in RandomLattice()")
982
+
983
+ @staticmethod
984
+ def SetPartitions(n):
985
+ r"""
986
+ Return the lattice of set partitions of the set `\{1,\ldots,n\}`
987
+ ordered by refinement.
988
+
989
+ INPUT:
990
+
991
+ - ``n`` -- positive integer
992
+
993
+ EXAMPLES::
994
+
995
+ sage: posets.SetPartitions(4)
996
+ Finite lattice containing 15 elements
997
+ """
998
+ from sage.combinat.set_partition import SetPartitions
999
+ n = check_int(n)
1000
+ S = SetPartitions(n)
1001
+
1002
+ def covers(x):
1003
+ for i, s in enumerate(x):
1004
+ for j in range(i + 1, len(x)):
1005
+ L = list(x)
1006
+ L[i] = s.union(x[j])
1007
+ L.pop(j)
1008
+ yield S(L)
1009
+
1010
+ return LatticePoset({x: list(covers(x)) for x in S},
1011
+ cover_relations=True)
1012
+
1013
+ @staticmethod
1014
+ def SSTPoset(s, f=None):
1015
+ """
1016
+ The lattice poset on semistandard tableaux of shape ``s`` and largest
1017
+ entry ``f`` that is ordered by componentwise comparison of the
1018
+ entries.
1019
+
1020
+ INPUT:
1021
+
1022
+ - ``s`` -- shape of the tableaux
1023
+
1024
+ - ``f`` -- integer (default: ``None``); the maximum fill number.
1025
+ By default (``None``), the method uses the number of cells in the shape.
1026
+
1027
+ .. NOTE::
1028
+
1029
+ This is a basic implementation and most certainly
1030
+ not the most efficient.
1031
+
1032
+ EXAMPLES::
1033
+
1034
+ sage: posets.SSTPoset([2,1])
1035
+ Finite lattice containing 8 elements
1036
+
1037
+ sage: posets.SSTPoset([2,1],4)
1038
+ Finite lattice containing 20 elements
1039
+
1040
+ sage: posets.SSTPoset([2,1],2).cover_relations()
1041
+ [[[[1, 1], [2]], [[1, 2], [2]]]]
1042
+
1043
+ sage: posets.SSTPoset([3,2]).bottom() # long time (6s on sage.math, 2012)
1044
+ [[1, 1, 1], [2, 2]]
1045
+
1046
+ sage: posets.SSTPoset([3,2],4).maximal_elements()
1047
+ [[[3, 3, 4], [4, 4]]]
1048
+ """
1049
+ from sage.combinat.tableau import SemistandardTableaux
1050
+
1051
+ def tableaux_is_less_than(a, b):
1052
+ return all(ix <= iy for x, y in zip(a, b) for ix, iy in zip(x, y))
1053
+
1054
+ if f is None:
1055
+ f = sum(s)
1056
+ E = SemistandardTableaux(s, max_entry=f)
1057
+ return LatticePoset((E, tableaux_is_less_than))
1058
+
1059
+ @staticmethod
1060
+ def StandardExample(n, facade=None):
1061
+ r"""
1062
+ Return the partially ordered set on `2n` elements with
1063
+ dimension `n`.
1064
+
1065
+ Let `P` be the poset on `\{0, 1, 2, \ldots, 2n-1\}` whose defining
1066
+ relations are that `i < j` for every `0 \leq i < n \leq j < 2n`
1067
+ except when `i + n = j`. The poset `P` is the so-called
1068
+ *standard example* of a poset with dimension `n`.
1069
+
1070
+ INPUT:
1071
+
1072
+ - ``n`` -- integer `\ge 2`; dimension of the constructed poset
1073
+
1074
+ - ``facade`` -- boolean; whether to make the returned poset a
1075
+ facade poset (see :mod:`sage.categories.facade_sets`); the
1076
+ default behaviour is the same as the default behaviour of
1077
+ the :func:`~sage.combinat.posets.posets.Poset` constructor
1078
+
1079
+ OUTPUT: the standard example of a poset of dimension `n`
1080
+
1081
+ EXAMPLES::
1082
+
1083
+ sage: A = posets.StandardExample(3); A
1084
+ Finite poset containing 6 elements
1085
+ sage: A.dimension() # needs networkx
1086
+ 3
1087
+
1088
+ REFERENCES:
1089
+
1090
+ - [Gar2015]_
1091
+ - [Ros1999]_
1092
+
1093
+ TESTS::
1094
+
1095
+ sage: A = posets.StandardExample(10); A
1096
+ Finite poset containing 20 elements
1097
+ sage: len(A.cover_relations())
1098
+ 90
1099
+
1100
+ sage: P = posets.StandardExample(5, facade=False)
1101
+ sage: P(4) < P(3), P(4) > P(3)
1102
+ (False, False)
1103
+ """
1104
+ n = check_int(n, 2)
1105
+ return Poset((range(2 * n), [[i, j + n] for i in range(n)
1106
+ for j in range(n) if i != j]),
1107
+ facade=facade)
1108
+
1109
+ @staticmethod
1110
+ def SymmetricGroupBruhatOrderPoset(n):
1111
+ """
1112
+ The poset of permutations with respect to Bruhat order.
1113
+
1114
+ EXAMPLES::
1115
+
1116
+ sage: posets.SymmetricGroupBruhatOrderPoset(4)
1117
+ Finite poset containing 24 elements
1118
+ """
1119
+ if n < 10:
1120
+ element_labels = {s: "".join(str(x) for x in s)
1121
+ for s in Permutations(n)}
1122
+ return Poset({s: s.bruhat_succ() for s in Permutations(n)},
1123
+ element_labels)
1124
+
1125
+ @staticmethod
1126
+ def SymmetricGroupBruhatIntervalPoset(start, end):
1127
+ """
1128
+ The poset of permutations with respect to Bruhat order.
1129
+
1130
+ INPUT:
1131
+
1132
+ - ``start`` -- list permutation
1133
+
1134
+ - ``end`` -- list permutation (same n, of course)
1135
+
1136
+ .. NOTE::
1137
+
1138
+ Must have ``start`` <= ``end``.
1139
+
1140
+ EXAMPLES:
1141
+
1142
+ Any interval is rank symmetric if and only if it avoids these
1143
+ permutations::
1144
+
1145
+ sage: P1 = posets.SymmetricGroupBruhatIntervalPoset([1,2,3,4], [3,4,1,2])
1146
+ sage: P2 = posets.SymmetricGroupBruhatIntervalPoset([1,2,3,4], [4,2,3,1])
1147
+ sage: ranks1 = [P1.rank(v) for v in P1]
1148
+ sage: ranks2 = [P2.rank(v) for v in P2]
1149
+ sage: [ranks1.count(i) for i in sorted(set(ranks1))]
1150
+ [1, 3, 5, 4, 1]
1151
+ sage: [ranks2.count(i) for i in sorted(set(ranks2))]
1152
+ [1, 3, 5, 6, 4, 1]
1153
+ """
1154
+ start = Permutation(start)
1155
+ end = Permutation(end)
1156
+ if len(start) != len(end):
1157
+ raise TypeError(f"start ({start}) and end ({end}) must have same length")
1158
+ if not start.bruhat_lequal(end):
1159
+ raise TypeError(f"must have start ({start}) <= end ({end}) in Bruhat order")
1160
+ unseen = [start]
1161
+ nodes = {}
1162
+ while unseen:
1163
+ perm = unseen.pop(0)
1164
+ nodes[perm] = [succ_perm for succ_perm in perm.bruhat_succ()
1165
+ if succ_perm.bruhat_lequal(end)]
1166
+ unseen.extend(succ_perm for succ_perm in nodes[perm]
1167
+ if succ_perm not in nodes)
1168
+ return Poset(nodes)
1169
+
1170
+ @staticmethod
1171
+ def SymmetricGroupWeakOrderPoset(n, labels='permutations', side='right'):
1172
+ r"""
1173
+ The poset of permutations of `\{ 1, 2, \ldots, n \}` with respect
1174
+ to the weak order (also known as the permutohedron order, cf.
1175
+ :meth:`~sage.combinat.permutation.Permutation.permutohedron_lequal`).
1176
+
1177
+ The optional variable ``labels`` (default: ``'permutations'``)
1178
+ determines the labelling of the elements if `n < 10`. The optional
1179
+ variable ``side`` (default: ``'right'``) determines whether the
1180
+ right or the left permutohedron order is to be used.
1181
+
1182
+ EXAMPLES::
1183
+
1184
+ sage: posets.SymmetricGroupWeakOrderPoset(4)
1185
+ Finite poset containing 24 elements
1186
+ """
1187
+ if n < 10 and labels == "permutations":
1188
+ element_labels = dict([[s, "".join(map(str, s))]
1189
+ for s in Permutations(n)])
1190
+ if n < 10 and labels == "reduced_words":
1191
+ element_labels = dict([[s, "".join(map(str, s.reduced_word_lexmin()))]
1192
+ for s in Permutations(n)])
1193
+ if side == "left":
1194
+
1195
+ def weak_covers(s):
1196
+ r"""
1197
+ Nested function for computing the covers of elements in the
1198
+ poset of left weak order for the symmetric group.
1199
+ """
1200
+ return [v for v in s.bruhat_succ() if
1201
+ s.length() + (s.inverse().right_action_product(v)).length() == v.length()]
1202
+ else:
1203
+ def weak_covers(s):
1204
+ r"""
1205
+ Nested function for computing the covers of elements in the
1206
+ poset of right weak order for the symmetric group.
1207
+ """
1208
+ return [v for v in s.bruhat_succ() if
1209
+ s.length() + (s.inverse().left_action_product(v)).length() == v.length()]
1210
+ return Poset(dict([[s, weak_covers(s)] for s in Permutations(n)]),
1211
+ element_labels)
1212
+
1213
+ @staticmethod
1214
+ def TetrahedralPoset(n, *colors, **labels):
1215
+ r"""
1216
+ Return the tetrahedral poset based on the input colors.
1217
+
1218
+ This method will return the tetrahedral poset with `n-1` layers and
1219
+ covering relations based on the input colors of 'green', 'red',
1220
+ 'orange', 'silver', 'yellow' and 'blue' as defined in [Striker2011]_.
1221
+ For particular color choices, the order ideals of the resulting
1222
+ tetrahedral poset will be isomorphic to known combinatorial objects.
1223
+
1224
+ For example, for the colors 'blue', 'yellow', 'orange', and 'green',
1225
+ the order ideals will be in bijection with alternating sign matrices.
1226
+ For the colors 'yellow', 'orange', and 'green', the order ideals will
1227
+ be in bijection with semistandard Young tableaux of staircase shape.
1228
+ For the colors 'red', 'orange', 'green', and optionally 'yellow', the
1229
+ order ideals will be in bijection with totally symmetric
1230
+ self-complementary plane partitions in a `2n \times 2n \times 2n` box.
1231
+
1232
+ INPUT:
1233
+
1234
+ - ``n`` -- defines the number (n-1) of layers in the poset
1235
+
1236
+ - ``colors`` -- the colors that define the covering relations of the
1237
+ poset; colors used are 'green', 'red', 'yellow', 'orange', 'silver',
1238
+ and 'blue'
1239
+
1240
+ - ``labels`` -- keyword variable used to determine whether the poset
1241
+ is labeled with integers or tuples. To label with integers, the
1242
+ method should be called with ``labels='integers'``. Otherwise, the
1243
+ labeling will default to tuples.
1244
+
1245
+ EXAMPLES::
1246
+
1247
+ sage: posets.TetrahedralPoset(4,'green','red','yellow','silver','blue','orange')
1248
+ Finite poset containing 10 elements
1249
+
1250
+ sage: posets.TetrahedralPoset(4,'green','red','yellow','silver','blue','orange',
1251
+ ....: labels='integers')
1252
+ Finite poset containing 10 elements
1253
+
1254
+ sage: A = AlternatingSignMatrices(3)
1255
+ sage: p = A.lattice()
1256
+ sage: ji = p.join_irreducibles_poset()
1257
+ sage: tet = posets.TetrahedralPoset(3, 'green','yellow','blue','orange')
1258
+ sage: ji.is_isomorphic(tet)
1259
+ True
1260
+
1261
+ TESTS::
1262
+
1263
+ sage: posets.TetrahedralPoset(4,'scarlet')
1264
+ Traceback (most recent call last):
1265
+ ...
1266
+ ValueError: color input must be among: 'green', 'red', 'yellow',
1267
+ 'orange', 'silver', and 'blue'
1268
+ """
1269
+ n = check_int(n, 2)
1270
+ n = n - 1
1271
+ for c in colors:
1272
+ if c not in ('green', 'red', 'yellow', 'orange', 'silver', 'blue'):
1273
+ raise ValueError("color input must be among: 'green', 'red', 'yellow', 'orange', 'silver', and 'blue'")
1274
+ elem = [(i, j, k) for i in range(n)
1275
+ for j in range(n - i) for k in range(n - i - j)]
1276
+ rels = []
1277
+ elem_labels = {}
1278
+ if 'labels' in labels:
1279
+ if labels['labels'] == 'integers':
1280
+ labelcount = 0
1281
+ for (i, j, k) in elem:
1282
+ elem_labels[(i, j, k)] = labelcount
1283
+ labelcount += 1
1284
+ for c in colors:
1285
+ for (i, j, k) in elem:
1286
+ if i + j + k < n - 1:
1287
+ if c == 'green':
1288
+ rels.append([(i, j, k), (i + 1, j, k)])
1289
+ if c == 'red':
1290
+ rels.append([(i, j, k), (i, j, k + 1)])
1291
+ if c == 'yellow':
1292
+ rels.append([(i, j, k), (i, j + 1, k)])
1293
+ if j < n - 1 and k > 0:
1294
+ if c == 'orange':
1295
+ rels.append([(i, j, k), (i, j + 1, k - 1)])
1296
+ if i < n - 1 and j > 0:
1297
+ if c == 'silver':
1298
+ rels.append([(i, j, k), (i + 1, j - 1, k)])
1299
+ if i < n - 1 and k > 0:
1300
+ if c == 'blue':
1301
+ rels.append([(i, j, k), (i + 1, j, k - 1)])
1302
+ return Poset([elem, rels], elem_labels)
1303
+
1304
+ # shard intersection order
1305
+ import sage.combinat.shard_order
1306
+ ShardPoset = staticmethod(sage.combinat.shard_order.shard_poset)
1307
+
1308
+ # Tamari lattices
1309
+ import sage.combinat.tamari_lattices
1310
+ TamariLattice = staticmethod(sage.combinat.tamari_lattices.TamariLattice)
1311
+ DexterSemilattice = staticmethod(sage.combinat.tamari_lattices.DexterSemilattice)
1312
+
1313
+ @staticmethod
1314
+ def CoxeterGroupAbsoluteOrderPoset(W, use_reduced_words=True):
1315
+ r"""
1316
+ Return the poset of elements of a Coxeter group with respect
1317
+ to absolute order.
1318
+
1319
+ INPUT:
1320
+
1321
+ - ``W`` -- a Coxeter group
1322
+ - ``use_reduced_words`` -- boolean (default: ``True``); if
1323
+ ``True``, then the elements are labeled by their lexicographically
1324
+ minimal reduced word
1325
+
1326
+ EXAMPLES::
1327
+
1328
+ sage: W = CoxeterGroup(['B', 3]) # needs sage.groups
1329
+ sage: posets.CoxeterGroupAbsoluteOrderPoset(W) # needs sage.groups
1330
+ Finite poset containing 48 elements
1331
+
1332
+ sage: W = WeylGroup(['B', 2], prefix='s') # needs sage.groups
1333
+ sage: posets.CoxeterGroupAbsoluteOrderPoset(W, False) # needs sage.groups
1334
+ Finite poset containing 8 elements
1335
+ """
1336
+ if use_reduced_words:
1337
+ element_labels = {s: tuple(s.reduced_word()) for s in W}
1338
+ return Poset({s: list(s.absolute_covers()) for s in W}, element_labels)
1339
+ return Poset({s: list(s.absolute_covers()) for s in W})
1340
+
1341
+ @staticmethod
1342
+ def NoncrossingPartitions(W):
1343
+ """
1344
+ Return the lattice of noncrossing partitions.
1345
+
1346
+ INPUT:
1347
+
1348
+ - ``W`` -- a finite Coxeter group or a Weyl group
1349
+
1350
+ EXAMPLES::
1351
+
1352
+ sage: W = CoxeterGroup(['A', 3]) # needs sage.groups
1353
+ sage: posets.NoncrossingPartitions(W) # needs sage.groups
1354
+ Finite lattice containing 14 elements
1355
+
1356
+ sage: W = WeylGroup(['B', 2], prefix='s') # needs sage.groups
1357
+ sage: posets.NoncrossingPartitions(W) # needs sage.groups
1358
+ Finite lattice containing 6 elements
1359
+ """
1360
+ return W.noncrossing_partition_lattice()
1361
+
1362
+ @staticmethod
1363
+ def SymmetricGroupAbsoluteOrderPoset(n, labels='permutations'):
1364
+ r"""
1365
+ Return the poset of permutations with respect to absolute order.
1366
+
1367
+ INPUT:
1368
+
1369
+ - ``n`` -- a positive integer
1370
+
1371
+ - ``label`` -- (default: ``'permutations'``) a label for the elements
1372
+ of the poset returned by the function; the options are
1373
+
1374
+ * ``'permutations'`` -- labels the elements by their
1375
+ one-line notation
1376
+ * ``'reduced_words'`` -- labels the elements by the
1377
+ lexicographically minimal reduced word
1378
+ * ``'cycles'`` -- labels the elements by their expression
1379
+ as a product of cycles
1380
+
1381
+ EXAMPLES::
1382
+
1383
+ sage: posets.SymmetricGroupAbsoluteOrderPoset(4) # needs sage.groups
1384
+ Finite poset containing 24 elements
1385
+ sage: posets.SymmetricGroupAbsoluteOrderPoset(3, labels='cycles') # needs sage.groups
1386
+ Finite poset containing 6 elements
1387
+ sage: posets.SymmetricGroupAbsoluteOrderPoset(3, labels='reduced_words') # needs sage.groups
1388
+ Finite poset containing 6 elements
1389
+ """
1390
+ from sage.groups.perm_gps.permgroup_named import SymmetricGroup
1391
+ W = SymmetricGroup(n)
1392
+ if labels == "permutations":
1393
+ element_labels = {s: s.tuple() for s in W}
1394
+ if labels == "reduced_words":
1395
+ element_labels = {s: tuple(s.reduced_word()) for s in W}
1396
+ if labels == "cycles":
1397
+ element_labels = {s: "".join(x for x in s.cycle_string() if x != ',')
1398
+ for s in W}
1399
+
1400
+ return Poset({s: list(s.absolute_covers()) for s in W}, element_labels)
1401
+
1402
+ @staticmethod
1403
+ def UpDownPoset(n, m=1):
1404
+ r"""
1405
+ Return the up-down poset on `n` elements where every `(m+1)`
1406
+ step is down and the rest are up.
1407
+
1408
+ The case where `m=1` is sometimes referred to as the zig-zag poset
1409
+ or the fence.
1410
+
1411
+ INPUT:
1412
+
1413
+ - ``n`` -- nonnegative integer; number of elements in the poset
1414
+ - ``m`` -- nonnegative integer (default: 1); how frequently down
1415
+ steps occur
1416
+
1417
+ OUTPUT:
1418
+
1419
+ The partially ordered set on `\{ 0, 1, \ldots, n-1 \}`
1420
+ where `i` covers `i+1` if `m` divides `i+1`, and `i+1` covers `i`
1421
+ otherwise.
1422
+
1423
+ EXAMPLES::
1424
+
1425
+ sage: P = posets.UpDownPoset(7, 2); P
1426
+ Finite poset containing 7 elements
1427
+ sage: sorted(P.cover_relations())
1428
+ [[0, 1], [1, 2], [3, 2], [3, 4], [4, 5], [6, 5]]
1429
+
1430
+ Fibonacci numbers as the number of antichains of a poset::
1431
+
1432
+ sage: [len(posets.UpDownPoset(n).antichains().list()) for n in range(6)]
1433
+ [1, 2, 3, 5, 8, 13]
1434
+
1435
+ TESTS::
1436
+
1437
+ sage: P = posets.UpDownPoset(0); P
1438
+ Finite poset containing 0 elements
1439
+ """
1440
+ n = check_int(n)
1441
+ try:
1442
+ m = Integer(m)
1443
+ except TypeError:
1444
+ raise TypeError(f"parameter m must be an integer, not {m}")
1445
+ if m < 1:
1446
+ raise ValueError(f"parameter m must be positive, not {m}")
1447
+
1448
+ covers = [[i, i + 1] if (i + 1) % (m + 1) else [i + 1, i]
1449
+ for i in range(n - 1)]
1450
+ return Poset((range(n), covers), cover_relations=True)
1451
+
1452
+ @staticmethod
1453
+ def YoungDiagramPoset(lam, dual=False):
1454
+ """
1455
+ Return the poset of cells in the Young diagram of a partition.
1456
+
1457
+ INPUT:
1458
+
1459
+ - ``lam`` -- a partition
1460
+ - ``dual`` -- boolean (default: ``False``); determines the orientation
1461
+ of the poset. If ``True``, then it is a join semilattice,
1462
+ otherwise it is a meet semilattice.
1463
+
1464
+ EXAMPLES::
1465
+
1466
+ sage: P = posets.YoungDiagramPoset(Partition([2, 2])); P
1467
+ Finite meet-semilattice containing 4 elements
1468
+
1469
+ sage: sorted(P.cover_relations())
1470
+ [[(0, 0), (0, 1)], [(0, 0), (1, 0)], [(0, 1), (1, 1)], [(1, 0), (1, 1)]]
1471
+
1472
+ sage: posets.YoungDiagramPoset([3, 2], dual=True)
1473
+ Finite join-semilattice containing 5 elements
1474
+ """
1475
+ from sage.combinat.partition import Partition
1476
+ lam = Partition(lam)
1477
+ if dual:
1478
+ def cell_geq(a, b):
1479
+ """
1480
+ Nested function that returns ``True`` if the cell `a` is to the
1481
+ right or below the cell `b` in the (English) Young diagram.
1482
+ """
1483
+ return ((a[0] == b[0] + 1 and a[1] == b[1]) or
1484
+ (a[1] == b[1] + 1 and a[0] == b[0]))
1485
+ return JoinSemilattice((lam.cells(), cell_geq), cover_relations=True)
1486
+
1487
+ def cell_leq(a, b):
1488
+ """
1489
+ Nested function that returns ``True`` if the cell `a` is
1490
+ to the left or above
1491
+ the cell `b` in the (English) Young diagram.
1492
+ """
1493
+ return ((a[0] == b[0] - 1 and a[1] == b[1]) or
1494
+ (a[1] == b[1] - 1 and a[0] == b[0]))
1495
+ return MeetSemilattice((lam.cells(), cell_leq), cover_relations=True)
1496
+
1497
+ @staticmethod
1498
+ def YoungsLattice(n):
1499
+ """
1500
+ Return Young's Lattice up to rank `n`.
1501
+
1502
+ In other words, the poset of partitions
1503
+ of size less than or equal to `n` ordered by inclusion.
1504
+
1505
+ INPUT:
1506
+
1507
+ - ``n`` -- positive integer
1508
+
1509
+ EXAMPLES::
1510
+
1511
+ sage: P = posets.YoungsLattice(3); P
1512
+ Finite meet-semilattice containing 7 elements
1513
+ sage: P.cover_relations()
1514
+ [[[], [1]],
1515
+ [[1], [1, 1]],
1516
+ [[1], [2]],
1517
+ [[1, 1], [1, 1, 1]],
1518
+ [[1, 1], [2, 1]],
1519
+ [[2], [2, 1]],
1520
+ [[2], [3]]]
1521
+ """
1522
+ from sage.combinat.partition import Partitions, Partition
1523
+ from sage.misc.flatten import flatten
1524
+ partitions = flatten([list(Partitions(i)) for i in range(n + 1)])
1525
+ return JoinSemilattice((partitions, Partition.contains)).dual()
1526
+
1527
+ @staticmethod
1528
+ def YoungsLatticePrincipalOrderIdeal(lam):
1529
+ """
1530
+ Return the principal order ideal of the
1531
+ partition `lam` in Young's Lattice.
1532
+
1533
+ INPUT:
1534
+
1535
+ - ``lam`` -- a partition
1536
+
1537
+ EXAMPLES::
1538
+
1539
+ sage: P = posets.YoungsLatticePrincipalOrderIdeal(Partition([2,2]))
1540
+ sage: P
1541
+ Finite lattice containing 6 elements
1542
+ sage: P.cover_relations()
1543
+ [[[], [1]],
1544
+ [[1], [1, 1]],
1545
+ [[1], [2]],
1546
+ [[1, 1], [2, 1]],
1547
+ [[2], [2, 1]],
1548
+ [[2, 1], [2, 2]]]
1549
+ """
1550
+ ideal = {}
1551
+ level = [lam]
1552
+ while level:
1553
+ new_level = set()
1554
+ for mu in level:
1555
+ down = mu.down_list()
1556
+ ideal[mu] = down
1557
+ new_level.update(down)
1558
+ level = new_level
1559
+
1560
+ H = DiGraph(ideal)
1561
+ return LatticePoset(H.reverse())
1562
+
1563
+ @staticmethod
1564
+ def YoungFibonacci(n):
1565
+ """
1566
+ Return the Young-Fibonacci lattice up to rank `n`.
1567
+
1568
+ Elements of the (infinite) lattice are words with letters '1'
1569
+ and '2'. The covers of a word are the words with another '1'
1570
+ added somewhere not after the first occurrence of an existing
1571
+ '1' and, additionally, the words where the first '1' is replaced by a
1572
+ '2'. The lattice is truncated to have rank `n`.
1573
+
1574
+ See :wikipedia:`Young-Fibonacci lattice`.
1575
+
1576
+ EXAMPLES::
1577
+
1578
+ sage: Y5 = posets.YoungFibonacci(5); Y5
1579
+ Finite meet-semilattice containing 20 elements
1580
+ sage: sorted(Y5.upper_covers(Word('211')))
1581
+ [word: 1211, word: 2111, word: 221]
1582
+
1583
+ TESTS::
1584
+
1585
+ sage: posets.YoungFibonacci(0)
1586
+ Finite meet-semilattice containing 1 elements
1587
+ sage: posets.YoungFibonacci(1)
1588
+ Finite meet-semilattice containing 2 elements
1589
+ """
1590
+ from sage.combinat.posets.lattices import FiniteMeetSemilattice
1591
+ from sage.categories.finite_posets import FinitePosets
1592
+ from sage.combinat.words.word import Word
1593
+
1594
+ n = check_int(n)
1595
+
1596
+ if n == 0:
1597
+ return MeetSemilattice({'': []})
1598
+
1599
+ covers = []
1600
+ current_level = ['']
1601
+ for _ in range(1, n + 1):
1602
+ new_level = set()
1603
+ for low in current_level:
1604
+ ind = low.find('1')
1605
+ if ind != -1: # = found a '1' -> change first '1' to '2'
1606
+ up = low[:ind] + '2' + low[ind + 1:]
1607
+ new_level.add(up)
1608
+ covers.append((low, up))
1609
+ else: # no '1' in low
1610
+ ind = len(low)
1611
+
1612
+ # add '1' to every position not after first existing '1'
1613
+ for j in range(ind + 1):
1614
+ up = '2' * j + '1' + low[j:len(low)]
1615
+ new_level.add(up)
1616
+ covers.append((low, up))
1617
+
1618
+ current_level = new_level
1619
+
1620
+ D = DiGraph([[], covers], format='vertices_and_edges')
1621
+ D.relabel(Word, inplace=True)
1622
+ return FiniteMeetSemilattice(hasse_diagram=D, category=FinitePosets())
1623
+
1624
+ @staticmethod
1625
+ def DoubleTailedDiamond(n):
1626
+ r"""
1627
+ Return a double-tailed diamond of `2n + 2` elements.
1628
+
1629
+ INPUT:
1630
+
1631
+ - ``n`` -- positive integer
1632
+
1633
+ EXAMPLES::
1634
+
1635
+ sage: P = posets.DoubleTailedDiamond(2); P
1636
+ Finite d-complete poset containing 6 elements
1637
+ sage: P.cover_relations()
1638
+ [[1, 2], [2, 3], [2, 4], [3, 5], [4, 5], [5, 6]]
1639
+ """
1640
+ n = check_int(n, 1)
1641
+
1642
+ edges = [(i, i + 1) for i in range(1, n)]
1643
+ edges.extend([(n, n + 1), (n, n + 2), (n + 1, n + 3), (n + 2, n + 3)])
1644
+ edges.extend((i, i + 1) for i in range(n + 3, 2 * n + 2))
1645
+ p = DiGraph([list(range(1, 2 * n + 3)), edges])
1646
+ return DCompletePoset(p)
1647
+
1648
+ @staticmethod
1649
+ def PermutationPattern(n):
1650
+ r"""
1651
+ Return the poset of permutations under pattern containment
1652
+ up to rank `n`.
1653
+
1654
+ INPUT:
1655
+
1656
+ - ``n`` -- positive integer
1657
+
1658
+ A permutation `u = u_1 \cdots u_n` contains the pattern
1659
+ `v = v_1 \cdots v_m` if there is a (not necessarily consecutive)
1660
+ subsequence of `u` of length `m` whose entries have the same
1661
+ relative order as `v`.
1662
+
1663
+ See :wikipedia:`Permutation_pattern`.
1664
+
1665
+ EXAMPLES::
1666
+
1667
+ sage: P4 = posets.PermutationPattern(4); P4
1668
+ Finite poset containing 33 elements
1669
+ sage: sorted(P4.lower_covers(Permutation([2,4,1,3])))
1670
+ [[1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2]]
1671
+
1672
+ .. SEEALSO::
1673
+
1674
+ :meth:`~sage.combinat.permutation.Permutation.has_pattern`
1675
+
1676
+ TESTS::
1677
+
1678
+ sage: posets.PermutationPattern(1)
1679
+ Finite poset containing 1 elements
1680
+ sage: posets.PermutationPattern(2)
1681
+ Finite poset containing 3 elements
1682
+ """
1683
+ n = check_int(n, 1)
1684
+ elem = []
1685
+ for i in range(1, n + 1):
1686
+ elem += Permutations(i)
1687
+ return Poset((elem, lambda a, b: b.has_pattern(a)))
1688
+
1689
+ @staticmethod
1690
+ def PermutationPatternInterval(bottom, top):
1691
+ r"""
1692
+ Return the poset consisting of an interval in the poset of permutations
1693
+ under pattern containment between ``bottom`` and ``top``.
1694
+
1695
+ INPUT:
1696
+
1697
+ - ``bottom``, ``top`` -- permutations where ``top`` contains
1698
+ ``bottom`` as a pattern
1699
+
1700
+ A permutation `u = u_1 \cdots u_n` contains the pattern
1701
+ `v = v_1 \cdots v_m` if there is a (not necessarily consecutive)
1702
+ subsequence of `u` of length `m` whose entries have the same
1703
+ relative order as `v`.
1704
+
1705
+ See :wikipedia:`Permutation_pattern`.
1706
+
1707
+ EXAMPLES::
1708
+
1709
+ sage: t = Permutation([2,3,1])
1710
+ sage: b = Permutation([4,6,2,3,5,1])
1711
+ sage: R = posets.PermutationPatternInterval(t, b); R
1712
+ Finite poset containing 14 elements
1713
+ sage: R.moebius_function(R.bottom(),R.top())
1714
+ -4
1715
+
1716
+ .. SEEALSO::
1717
+
1718
+ :meth:`~sage.combinat.permutation.Permutation.has_pattern`,
1719
+ :meth:`PermutationPattern`
1720
+
1721
+ TESTS::
1722
+
1723
+ sage: p = Permutation([1])
1724
+ sage: posets.PermutationPatternInterval(p, p)
1725
+ Finite poset containing 1 elements
1726
+ """
1727
+ P = Permutations()
1728
+ top = P(top)
1729
+ bottom = P(bottom)
1730
+ if not top.has_pattern(bottom):
1731
+ raise ValueError(f"{top} doesn't contain {bottom} as a pattern")
1732
+ # Make a list of lists of elements in the interval divided by rank.
1733
+ # List will be flattened at the end
1734
+ elem = [[top]]
1735
+ level = 0 # Consider the top element to be level 0, and then go down from there.
1736
+ rel = [] # List of covering relations to be fed into poset constructor.
1737
+ while len(top) - len(bottom) >= level + 1:
1738
+ elem.append([]) # Add a new empty level
1739
+ for upper in elem[level]:
1740
+ # Run through all permutations on current level
1741
+ # and find relations for which it is upper cover
1742
+ upper_perm = P(upper)
1743
+ for i in range(len(top) - level):
1744
+ # Try and remove the ith element from the permutation
1745
+ lower = list(upper)
1746
+ j = lower.pop(i)
1747
+ for k in range(len(top) - level - 1): # Standardize result
1748
+ if lower[k] > j:
1749
+ lower[k] = lower[k] - 1
1750
+ lower_perm = P(lower)
1751
+ if lower_perm.has_pattern(bottom): # Check to see if result is in interval
1752
+ rel += [[lower_perm, upper_perm]]
1753
+ if lower not in elem[level + 1]:
1754
+ elem[level + 1].append(lower_perm)
1755
+ level += 1
1756
+ elem = [item for sublist in elem for item in sublist]
1757
+ return Poset((elem, rel))
1758
+
1759
+ @staticmethod
1760
+ def PermutationPatternOccurrenceInterval(bottom, top, pos):
1761
+ r"""
1762
+ Return the poset consisting of an interval in the poset of
1763
+ permutations under pattern containment between ``bottom`` and
1764
+ ``top``, where a specified instance of ``bottom`` in ``top``
1765
+ must be maintained.
1766
+
1767
+ INPUT:
1768
+
1769
+ - ``bottom``, ``top`` -- permutations where ``top`` contains
1770
+ ``bottom`` as a pattern
1771
+ - ``pos`` -- list of indices indicating a distinguished copy of
1772
+ ``bottom`` inside ``top`` (indexed starting at 0)
1773
+
1774
+ For further information (and picture illustrating included example),
1775
+ see [ST2010]_ .
1776
+
1777
+ See :wikipedia:`Permutation_pattern`.
1778
+
1779
+ EXAMPLES::
1780
+
1781
+ sage: t = Permutation([3,2,1])
1782
+ sage: b = Permutation([6,3,4,5,2,1])
1783
+ sage: A = posets.PermutationPatternOccurrenceInterval(t, b, (0,2,4)); A
1784
+ Finite poset containing 8 elements
1785
+
1786
+ .. SEEALSO::
1787
+
1788
+ :meth:`~sage.combinat.permutation.Permutation.has_pattern`,
1789
+ :meth:`PermutationPattern`, :meth:`PermutationPatternInterval`
1790
+ """
1791
+ P = Permutations()
1792
+ top = P(top)
1793
+ bottom = P(bottom)
1794
+ if not to_standard([top[z] for z in pos]) == list(bottom): # check input
1795
+ raise ValueError("cannot find 'bottom' in 'top' given by 'pos'")
1796
+ elem = [[(top, pos)]]
1797
+ level = 0
1798
+ rel = []
1799
+ while len(top) - len(bottom) >= level + 1:
1800
+ elem.append([]) # Add a new empty level
1801
+ for upper in elem[level]:
1802
+ for i in range(len(top) - level):
1803
+ # Try and remove the ith element from the permutation
1804
+ if i in upper[1]:
1805
+ continue
1806
+ lower_perm = list(upper[0])
1807
+ j = lower_perm.pop(i)
1808
+ for e in range(len(top) - level - 1):
1809
+ if lower_perm[e] > j:
1810
+ lower_perm[e] = lower_perm[e] - 1
1811
+ lower_pos = list(upper[1])
1812
+ for f in range(len(upper[1])):
1813
+ if upper[1][f] > i:
1814
+ lower_pos[f] = upper[1][f] - 1
1815
+ rel += [[(P(lower_perm), tuple(lower_pos)),
1816
+ (P(upper[0]), upper[1])]]
1817
+ if (P(lower_perm), tuple(lower_pos)) not in elem[level + 1]:
1818
+ elem[level + 1].append((P(lower_perm), tuple(lower_pos)))
1819
+ level += 1
1820
+ elem = [item for sublist in elem for item in sublist]
1821
+ return Poset([elem, rel])
1822
+
1823
+ @staticmethod
1824
+ def RibbonPoset(n, descents):
1825
+ r"""
1826
+ Return a ribbon poset on ``n`` vertices with descents at ``descents``.
1827
+
1828
+ INPUT:
1829
+
1830
+ - ``n`` -- the number of vertices
1831
+ - ``descents`` -- an iterable; the indices on the ribbon where `y > x`
1832
+
1833
+ EXAMPLES::
1834
+
1835
+ sage: R = Posets.RibbonPoset(5, [1,2])
1836
+ sage: sorted(R.cover_relations())
1837
+ [[0, 1], [2, 1], [3, 2], [3, 4]]
1838
+ """
1839
+ n = check_int(n)
1840
+ return Mobile(DiGraph([list(range(n)),
1841
+ [(i + 1, i) if i in descents else (i, i + 1)
1842
+ for i in range(n - 1)]]))
1843
+
1844
+ @staticmethod
1845
+ def MobilePoset(ribbon, hangers, anchor=None):
1846
+ r"""
1847
+ Return a mobile poset with the ribbon ``ribbon`` and
1848
+ with hanging d-complete posets specified in ``hangers``
1849
+ and a d-complete poset attached above, specified in ``anchor``.
1850
+
1851
+ INPUT:
1852
+
1853
+ - ``ribbon`` -- a finite poset that is a ribbon
1854
+ - ``hangers`` -- dictionary mapping an element on the ribbon
1855
+ to a list of d-complete posets that it covers
1856
+ - ``anchor`` -- (optional) a ``tuple`` (``ribbon_elmt``,
1857
+ ``anchor_elmt``, ``anchor_poset``), where ``anchor_elmt`` covers
1858
+ ``ribbon_elmt``, and ``anchor_elmt`` is an acyclic element of
1859
+ ``anchor_poset``
1860
+
1861
+ EXAMPLES::
1862
+
1863
+ sage: R = Posets.RibbonPoset(5, [1,2])
1864
+ sage: H = Poset([[5, 6, 7], [(5, 6), (6,7)]])
1865
+ sage: M = Posets.MobilePoset(R, {3: [H]})
1866
+ sage: len(M.cover_relations())
1867
+ 7
1868
+
1869
+ sage: P = posets.MobilePoset(posets.RibbonPoset(7, [1,3]),
1870
+ ....: {1: [posets.YoungDiagramPoset([3, 2], dual=True)],
1871
+ ....: 3: [posets.DoubleTailedDiamond(6)]},
1872
+ ....: anchor=(4, 2, posets.ChainPoset(6)))
1873
+ sage: len(P.cover_relations())
1874
+ 33
1875
+ """
1876
+ elements = []
1877
+ cover_relations = []
1878
+
1879
+ cover_relations.extend(ribbon.cover_relations())
1880
+ elements.extend(ribbon._elements)
1881
+
1882
+ if anchor:
1883
+ cover_relations.extend(((anchor[0], cr[0]), (anchor[0], cr[1]))
1884
+ for cr in anchor[2].cover_relations())
1885
+ cover_relations.append((anchor[0], (anchor[0], anchor[1])))
1886
+
1887
+ elements.extend((anchor[0], elmt) for elmt in anchor[2]._elements)
1888
+
1889
+ for r, hangs in hangers.items():
1890
+ for i, h in enumerate(hangs):
1891
+ elements.extend((r, i, v) for v in h._elements)
1892
+ cover_relations.extend(((r, i, cr[0]), (r, i, cr[1]))
1893
+ for cr in h.cover_relations())
1894
+ cover_relations.append(((r, i, h.top()), r))
1895
+
1896
+ return Mobile(DiGraph([elements, cover_relations]))
1897
+
1898
+
1899
+ # RANDOM LATTICES
1900
+
1901
+ # Following are helper functions for random lattice generation.
1902
+ # There is no parameter checking, 0, 1, ..., n may or may not be a
1903
+ # linear extension, exact output type may vary, etc. Direct use is
1904
+ # discouraged. Use by posets.RandomLattice(..., properties=[...]).
1905
+
1906
+
1907
+ def _random_lattice(n, p):
1908
+ r"""
1909
+ Return a random lattice.
1910
+
1911
+ INPUT:
1912
+
1913
+ - ``n`` -- number of elements, a nonnegative integer
1914
+ - ``p`` -- a number at least zero and less than one; higher number
1915
+ means more covering relations
1916
+
1917
+ OUTPUT:
1918
+
1919
+ A list of lists. Interpreted as a list of lower covers
1920
+ for a poset, it is a lattice with ``0..n-1`` as a linear
1921
+ extension.
1922
+
1923
+ EXAMPLES::
1924
+
1925
+ sage: set_random_seed(42) # Results are reproducible
1926
+ sage: sage.combinat.posets.poset_examples._random_lattice(7, 0.4)
1927
+ [[], [0], [0], [1, 2], [1], [0], [3, 4, 5]]
1928
+
1929
+ ALGORITHM::
1930
+
1931
+ We add elements one by one. We check that adding a maximal
1932
+ element `e` to a meet-semilattice `L` with maximal elements
1933
+ `M` will create a semilattice by checking that there is a
1934
+ meet for `e, m` for all `m \in M`. We do that by keeping
1935
+ track of meet matrix and list of maximal elements.
1936
+ """
1937
+ from sage.arith.misc import integer_floor as floor
1938
+ from sage.misc.functional import sqrt
1939
+ from sage.misc.prandom import random
1940
+
1941
+ n = n - 1
1942
+ meets = [[None] * n for _ in range(n)]
1943
+ meets[0][0] = 0
1944
+ maxs = {0}
1945
+ lc_all = [[]] # No lower covers for the bottom element.
1946
+
1947
+ for i in range(1, n):
1948
+
1949
+ # Look for an admissible lower cover for the next element i
1950
+ while True:
1951
+ # Generate a random antichain
1952
+ lc_list = [i - 1 - floor(i * sqrt(random()))]
1953
+ while random() < p and 0 not in lc_list:
1954
+ new = i - 1 - floor(i * sqrt(random()))
1955
+ if any(meets[new][lc] in [new, lc] for lc in lc_list):
1956
+ continue
1957
+ lc_list.append(new)
1958
+ # Check whether it is admissible as a new lower cover
1959
+ if all(any(all(meets[m][meets[a][a1]] == meets[m][a1] for a1 in lc_list if a1 != a) for a in lc_list) for m in maxs):
1960
+ break
1961
+
1962
+ # We've found a suitable lower cover for i
1963
+ maxs.difference_update(lc_list)
1964
+
1965
+ # Now compute new row and column to meet matrix.
1966
+ meets[i][i] = i
1967
+ for lc in lc_list:
1968
+ meets[i][lc] = meets[lc][i] = lc
1969
+ for e in range(i):
1970
+ meets[i][e] = meets[e][i] = max(meets[e][lc] for lc in lc_list)
1971
+
1972
+ maxs.add(i)
1973
+ lc_all.append(lc_list)
1974
+
1975
+ lc_all.append(list(maxs)) # Add the top element.
1976
+ return lc_all
1977
+
1978
+
1979
+ def _random_dismantlable_lattice(n):
1980
+ r"""
1981
+ Return a random dismantlable lattice on `n` elements.
1982
+
1983
+ INPUT:
1984
+
1985
+ - ``n`` -- number of elements, a nonnegative integer
1986
+
1987
+ OUTPUT:
1988
+
1989
+ A digraph that can be interpreted as the Hasse diagram of a random
1990
+ dismantlable lattice. It has `0` as the bottom element and `n-1` as
1991
+ the top element, but otherwise `0, \ldots, n-1` *is not* usually a
1992
+ linear extension of the lattice.
1993
+
1994
+ EXAMPLES::
1995
+
1996
+ sage: set_random_seed(78) # Results are reproducible
1997
+ sage: D = sage.combinat.posets.poset_examples._random_dismantlable_lattice(10); D
1998
+ Digraph on 10 vertices
1999
+ sage: D.neighbors_in(8)
2000
+ [0]
2001
+
2002
+ ALGORITHM::
2003
+
2004
+ We add elements one by one by "de-dismantling", i.e. select
2005
+ a random pair of comparable elements and add a new element
2006
+ between them.
2007
+ """
2008
+ from sage.misc.prandom import randint
2009
+
2010
+ D = DiGraph({0: [n - 1]})
2011
+ for i in range(1, n - 1):
2012
+ a = randint(0, i // 2)
2013
+ b_ = list(D.depth_first_search(a))
2014
+ b = b_[randint(1, len(b_) - 1)]
2015
+ D.add_vertex(i)
2016
+ D.add_edge(a, i)
2017
+ D.add_edge(i, b)
2018
+ D.delete_edge(a, b)
2019
+ return D
2020
+
2021
+
2022
+ def _random_planar_lattice(n):
2023
+ r"""
2024
+ Return a random planar lattice on `n` elements.
2025
+
2026
+ INPUT:
2027
+
2028
+ - ``n`` -- number of elements, a nonnegative integer
2029
+
2030
+ OUTPUT:
2031
+
2032
+ A random planar lattice. It has `0` as the bottom
2033
+ element and `n-1` as the top element, but otherwise
2034
+ `0, \ldots, n-1` *is not* usually a linear extension of
2035
+ the lattice.
2036
+
2037
+ EXAMPLES::
2038
+
2039
+ sage: # needs planarity
2040
+ sage: set_random_seed(78) # Results are reproducible
2041
+ sage: D = sage.combinat.posets.poset_examples._random_planar_lattice(10); D
2042
+ Digraph on 10 vertices
2043
+ sage: D.neighbors_in(8)
2044
+ [1]
2045
+
2046
+ ALGORITHM::
2047
+
2048
+ Every planar lattice is dismantlable.
2049
+
2050
+ We add elements one by one like when generating
2051
+ dismantlable lattices, and after every addition
2052
+ check that we still have a planar lattice.
2053
+ """
2054
+ from sage.misc.prandom import randint
2055
+
2056
+ G = DiGraph({0: [n - 1]})
2057
+ while G.order() < n:
2058
+ i = G.order() - 1
2059
+ a = randint(0, i // 2)
2060
+ b_ = list(G.depth_first_search(a))
2061
+ b = b_[randint(1, len(b_) - 1)]
2062
+ G1 = G.copy()
2063
+ G.add_vertex(i)
2064
+ G.add_edge(a, i)
2065
+ G.add_edge(i, b)
2066
+ G.delete_edge(a, b)
2067
+ G2 = G.copy()
2068
+ G2.add_edge(n - 1, 0)
2069
+ if not G2.is_planar():
2070
+ G = G1.copy()
2071
+ return G
2072
+
2073
+
2074
+ def _random_distributive_lattice(n):
2075
+ """
2076
+ Return a random poset that has `n` antichains.
2077
+
2078
+ INPUT:
2079
+
2080
+ - ``n`` -- number of elements, a nonnegative integer
2081
+
2082
+ OUTPUT:
2083
+
2084
+ A random poset (as DiGraph) that has `n` antichains; i.e. a poset
2085
+ that's order ideals lattice has `n` elements.
2086
+
2087
+ EXAMPLES::
2088
+
2089
+ sage: g = sage.combinat.posets.poset_examples._random_distributive_lattice(10)
2090
+ sage: Poset(g).order_ideals_lattice(as_ideals=False).cardinality()
2091
+ 10
2092
+
2093
+ ALGORITHM:
2094
+
2095
+ Add elements until there are at least `n` antichains.
2096
+ Remove elements until there are at most `n` antichains.
2097
+ Repeat.
2098
+ """
2099
+ from sage.combinat.posets.hasse_diagram import HasseDiagram
2100
+ from copy import copy
2101
+ from sage.combinat.subset import Subsets
2102
+ from sage.graphs.digraph_generators import digraphs
2103
+
2104
+ if n < 4:
2105
+ return digraphs.Path(n - 1)
2106
+
2107
+ H = HasseDiagram({0: []})
2108
+ while sum(1 for _ in H.antichains_iterator()) < n:
2109
+ D = copy(H)
2110
+ newcover = Subsets(H).random_element()
2111
+ new_element = H.order()
2112
+ D.add_vertex(new_element)
2113
+ for e in newcover:
2114
+ D.add_edge(e, new_element)
2115
+
2116
+ D = D.transitive_reduction()
2117
+ H = HasseDiagram(D)
2118
+
2119
+ while sum(1 for _ in H.antichains_iterator()) > n:
2120
+ D = copy(H)
2121
+ to_delete = H.random_vertex()
2122
+ for a in D.neighbors_in(to_delete):
2123
+ for b in D.neighbors_out(to_delete):
2124
+ D.add_edge(a, b)
2125
+ D.delete_vertex(to_delete)
2126
+ D.relabel({z: z - 1 for z in range(to_delete + 1, D.order() + 1)})
2127
+ H = HasseDiagram(D)
2128
+ return D
2129
+
2130
+
2131
+ def _random_stone_lattice(n):
2132
+ """
2133
+ Return a random Stone lattice on `n` elements.
2134
+
2135
+ INPUT:
2136
+
2137
+ - ``n`` -- number of elements, a nonnegative integer
2138
+
2139
+ OUTPUT:
2140
+
2141
+ A random lattice (as a digraph) of `n` elements.
2142
+
2143
+ EXAMPLES::
2144
+
2145
+ sage: g = sage.combinat.posets.poset_examples._random_stone_lattice(10)
2146
+ sage: LatticePoset(g).is_stone()
2147
+ True
2148
+
2149
+ ALGORITHM:
2150
+
2151
+ Randomly split `n` to some factors. For every factor `p` generate
2152
+ a random distributive lattice on `p-1` elements and add a new bottom
2153
+ element to it. Compute the cartesian product of those lattices.
2154
+ """
2155
+ from sage.arith.misc import factor
2156
+ from sage.combinat.partition import Partitions
2157
+ from sage.misc.misc_c import prod
2158
+ from copy import copy
2159
+
2160
+ factors = sum([[f[0]] * f[1] for f in factor(n)], [])
2161
+ sage.misc.prandom.shuffle(factors)
2162
+
2163
+ part_lengths = list(Partitions(len(factors)).random_element())
2164
+ parts = []
2165
+ while part_lengths:
2166
+ x = part_lengths.pop()
2167
+ parts.append(prod(factors[:x]))
2168
+ factors = factors[x:]
2169
+
2170
+ result = DiGraph(1)
2171
+ for p in parts:
2172
+ g = _random_distributive_lattice(p - 1)
2173
+ g = copy(Poset(g).order_ideals_lattice(as_ideals=False)._hasse_diagram)
2174
+ g.add_edge(-1, 0)
2175
+ result = result.cartesian_product(g)
2176
+ result.relabel()
2177
+
2178
+ return result
2179
+
2180
+
2181
+ posets = Posets