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