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.
- passagemath_graphs-10.6.1rc1.dist-info/METADATA +292 -0
- passagemath_graphs-10.6.1rc1.dist-info/RECORD +260 -0
- passagemath_graphs-10.6.1rc1.dist-info/WHEEL +5 -0
- passagemath_graphs-10.6.1rc1.dist-info/top_level.txt +2 -0
- passagemath_graphs.libs/libgcc_s-69c45f16.so.1 +0 -0
- passagemath_graphs.libs/libgmp-8e78bd9b.so.10.5.0 +0 -0
- passagemath_graphs.libs/libstdc++-1f1a71be.so.6.0.33 +0 -0
- sage/all__sagemath_graphs.py +39 -0
- sage/combinat/abstract_tree.py +2723 -0
- sage/combinat/all__sagemath_graphs.py +34 -0
- sage/combinat/binary_tree.py +5306 -0
- sage/combinat/cluster_algebra_quiver/all.py +22 -0
- sage/combinat/cluster_algebra_quiver/cluster_seed.py +5208 -0
- sage/combinat/cluster_algebra_quiver/interact.py +124 -0
- sage/combinat/cluster_algebra_quiver/mutation_class.py +625 -0
- sage/combinat/cluster_algebra_quiver/mutation_type.py +1555 -0
- sage/combinat/cluster_algebra_quiver/quiver.py +2290 -0
- sage/combinat/cluster_algebra_quiver/quiver_mutation_type.py +2468 -0
- sage/combinat/designs/MOLS_handbook_data.py +570 -0
- sage/combinat/designs/all.py +58 -0
- sage/combinat/designs/bibd.py +1655 -0
- sage/combinat/designs/block_design.py +1071 -0
- sage/combinat/designs/covering_array.py +269 -0
- sage/combinat/designs/covering_design.py +530 -0
- sage/combinat/designs/database.py +5615 -0
- sage/combinat/designs/design_catalog.py +122 -0
- sage/combinat/designs/designs_pyx.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/combinat/designs/designs_pyx.pxd +21 -0
- sage/combinat/designs/designs_pyx.pyx +993 -0
- sage/combinat/designs/difference_family.py +3951 -0
- sage/combinat/designs/difference_matrices.py +279 -0
- sage/combinat/designs/evenly_distributed_sets.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/combinat/designs/evenly_distributed_sets.pyx +661 -0
- sage/combinat/designs/ext_rep.py +1064 -0
- sage/combinat/designs/gen_quadrangles_with_spread.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/combinat/designs/gen_quadrangles_with_spread.pyx +339 -0
- sage/combinat/designs/group_divisible_designs.py +361 -0
- sage/combinat/designs/incidence_structures.py +2357 -0
- sage/combinat/designs/latin_squares.py +581 -0
- sage/combinat/designs/orthogonal_arrays.py +2244 -0
- sage/combinat/designs/orthogonal_arrays_build_recursive.py +1780 -0
- sage/combinat/designs/orthogonal_arrays_find_recursive.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/combinat/designs/orthogonal_arrays_find_recursive.pyx +967 -0
- sage/combinat/designs/resolvable_bibd.py +815 -0
- sage/combinat/designs/steiner_quadruple_systems.py +1306 -0
- sage/combinat/designs/subhypergraph_search.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/combinat/designs/subhypergraph_search.pyx +530 -0
- sage/combinat/designs/twographs.py +306 -0
- sage/combinat/finite_state_machine.py +14874 -0
- sage/combinat/finite_state_machine_generators.py +2006 -0
- sage/combinat/graph_path.py +448 -0
- sage/combinat/interval_posets.py +3908 -0
- sage/combinat/nu_tamari_lattice.py +269 -0
- sage/combinat/ordered_tree.py +1446 -0
- sage/combinat/posets/all.py +46 -0
- sage/combinat/posets/bubble_shuffle.py +247 -0
- sage/combinat/posets/cartesian_product.py +493 -0
- sage/combinat/posets/d_complete.py +182 -0
- sage/combinat/posets/elements.py +273 -0
- sage/combinat/posets/forest.py +30 -0
- sage/combinat/posets/hasse_cython.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/combinat/posets/hasse_cython.pyx +174 -0
- sage/combinat/posets/hasse_diagram.py +3672 -0
- sage/combinat/posets/hochschild_lattice.py +158 -0
- sage/combinat/posets/incidence_algebras.py +794 -0
- sage/combinat/posets/lattices.py +5117 -0
- sage/combinat/posets/linear_extension_iterator.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/combinat/posets/linear_extension_iterator.pyx +292 -0
- sage/combinat/posets/linear_extensions.py +1037 -0
- sage/combinat/posets/mobile.py +275 -0
- sage/combinat/posets/moebius_algebra.py +776 -0
- sage/combinat/posets/poset_examples.py +2178 -0
- sage/combinat/posets/posets.py +9360 -0
- sage/combinat/rooted_tree.py +1070 -0
- sage/combinat/shard_order.py +239 -0
- sage/combinat/tamari_lattices.py +384 -0
- sage/combinat/yang_baxter_graph.py +923 -0
- sage/databases/all__sagemath_graphs.py +1 -0
- sage/databases/knotinfo_db.py +1231 -0
- sage/ext_data/all__sagemath_graphs.py +1 -0
- sage/ext_data/graphs/graph_plot_js.html +330 -0
- sage/ext_data/kenzo/CP2.txt +45 -0
- sage/ext_data/kenzo/CP3.txt +349 -0
- sage/ext_data/kenzo/CP4.txt +4774 -0
- sage/ext_data/kenzo/README.txt +49 -0
- sage/ext_data/kenzo/S4.txt +20 -0
- sage/graphs/all.py +42 -0
- sage/graphs/asteroidal_triples.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/asteroidal_triples.pyx +320 -0
- sage/graphs/base/all.py +1 -0
- sage/graphs/base/boost_graph.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/base/boost_graph.pxd +106 -0
- sage/graphs/base/boost_graph.pyx +3045 -0
- sage/graphs/base/c_graph.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/base/c_graph.pxd +106 -0
- sage/graphs/base/c_graph.pyx +5096 -0
- sage/graphs/base/dense_graph.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/base/dense_graph.pxd +28 -0
- sage/graphs/base/dense_graph.pyx +801 -0
- sage/graphs/base/graph_backends.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/base/graph_backends.pxd +5 -0
- sage/graphs/base/graph_backends.pyx +797 -0
- sage/graphs/base/overview.py +85 -0
- sage/graphs/base/sparse_graph.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/base/sparse_graph.pxd +90 -0
- sage/graphs/base/sparse_graph.pyx +1653 -0
- sage/graphs/base/static_dense_graph.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/base/static_dense_graph.pxd +5 -0
- sage/graphs/base/static_dense_graph.pyx +1032 -0
- sage/graphs/base/static_sparse_backend.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/base/static_sparse_backend.pxd +27 -0
- sage/graphs/base/static_sparse_backend.pyx +1583 -0
- sage/graphs/base/static_sparse_graph.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/base/static_sparse_graph.pxd +37 -0
- sage/graphs/base/static_sparse_graph.pyx +1375 -0
- sage/graphs/bipartite_graph.py +2732 -0
- sage/graphs/centrality.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/centrality.pyx +1038 -0
- sage/graphs/cographs.py +519 -0
- sage/graphs/comparability.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/comparability.pyx +851 -0
- sage/graphs/connectivity.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/connectivity.pxd +157 -0
- sage/graphs/connectivity.pyx +4813 -0
- sage/graphs/convexity_properties.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/convexity_properties.pxd +16 -0
- sage/graphs/convexity_properties.pyx +870 -0
- sage/graphs/digraph.py +4754 -0
- sage/graphs/digraph_generators.py +1993 -0
- sage/graphs/distances_all_pairs.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/distances_all_pairs.pxd +12 -0
- sage/graphs/distances_all_pairs.pyx +2938 -0
- sage/graphs/domination.py +1363 -0
- sage/graphs/dot2tex_utils.py +100 -0
- sage/graphs/edge_connectivity.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/edge_connectivity.pyx +1215 -0
- sage/graphs/generators/all.py +1 -0
- sage/graphs/generators/basic.py +1769 -0
- sage/graphs/generators/chessboard.py +538 -0
- sage/graphs/generators/classical_geometries.py +1611 -0
- sage/graphs/generators/degree_sequence.py +235 -0
- sage/graphs/generators/distance_regular.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/generators/distance_regular.pyx +2846 -0
- sage/graphs/generators/families.py +4759 -0
- sage/graphs/generators/intersection.py +565 -0
- sage/graphs/generators/platonic_solids.py +262 -0
- sage/graphs/generators/random.py +2623 -0
- sage/graphs/generators/smallgraphs.py +5741 -0
- sage/graphs/generators/world_map.py +724 -0
- sage/graphs/generic_graph.py +26867 -0
- sage/graphs/generic_graph_pyx.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/generic_graph_pyx.pxd +34 -0
- sage/graphs/generic_graph_pyx.pyx +1673 -0
- sage/graphs/genus.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/genus.pyx +622 -0
- sage/graphs/graph.py +9645 -0
- sage/graphs/graph_coloring.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_coloring.pyx +2284 -0
- sage/graphs/graph_database.py +1177 -0
- sage/graphs/graph_decompositions/all.py +1 -0
- sage/graphs/graph_decompositions/bandwidth.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_decompositions/bandwidth.pyx +428 -0
- sage/graphs/graph_decompositions/clique_separators.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_decompositions/clique_separators.pyx +616 -0
- sage/graphs/graph_decompositions/cutwidth.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_decompositions/cutwidth.pyx +753 -0
- sage/graphs/graph_decompositions/fast_digraph.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_decompositions/fast_digraph.pxd +13 -0
- sage/graphs/graph_decompositions/fast_digraph.pyx +212 -0
- sage/graphs/graph_decompositions/graph_products.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_decompositions/graph_products.pyx +508 -0
- sage/graphs/graph_decompositions/modular_decomposition.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_decompositions/modular_decomposition.pxd +27 -0
- sage/graphs/graph_decompositions/modular_decomposition.pyx +1536 -0
- sage/graphs/graph_decompositions/slice_decomposition.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_decompositions/slice_decomposition.pxd +18 -0
- sage/graphs/graph_decompositions/slice_decomposition.pyx +1106 -0
- sage/graphs/graph_decompositions/tree_decomposition.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_decompositions/tree_decomposition.pxd +17 -0
- sage/graphs/graph_decompositions/tree_decomposition.pyx +1996 -0
- sage/graphs/graph_decompositions/vertex_separation.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_decompositions/vertex_separation.pxd +5 -0
- sage/graphs/graph_decompositions/vertex_separation.pyx +1963 -0
- sage/graphs/graph_editor.py +82 -0
- sage/graphs/graph_generators.py +3314 -0
- sage/graphs/graph_generators_pyx.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/graph_generators_pyx.pyx +95 -0
- sage/graphs/graph_input.py +812 -0
- sage/graphs/graph_latex.py +2064 -0
- sage/graphs/graph_list.py +410 -0
- sage/graphs/graph_plot.py +1756 -0
- sage/graphs/graph_plot_js.py +338 -0
- sage/graphs/hyperbolicity.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/hyperbolicity.pyx +1704 -0
- sage/graphs/hypergraph_generators.py +364 -0
- sage/graphs/independent_sets.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/independent_sets.pxd +13 -0
- sage/graphs/independent_sets.pyx +402 -0
- sage/graphs/isgci.py +1033 -0
- sage/graphs/isoperimetric_inequalities.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/isoperimetric_inequalities.pyx +489 -0
- sage/graphs/line_graph.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/line_graph.pyx +743 -0
- sage/graphs/lovasz_theta.py +77 -0
- sage/graphs/matching.py +1633 -0
- sage/graphs/matching_covered_graph.py +3590 -0
- sage/graphs/orientations.py +1489 -0
- sage/graphs/partial_cube.py +459 -0
- sage/graphs/path_enumeration.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/path_enumeration.pyx +2040 -0
- sage/graphs/pq_trees.py +1129 -0
- sage/graphs/print_graphs.py +201 -0
- sage/graphs/schnyder.py +865 -0
- sage/graphs/spanning_tree.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/spanning_tree.pyx +1457 -0
- sage/graphs/strongly_regular_db.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/strongly_regular_db.pyx +3340 -0
- sage/graphs/traversals.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/traversals.pxd +9 -0
- sage/graphs/traversals.pyx +1872 -0
- sage/graphs/trees.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/trees.pxd +15 -0
- sage/graphs/trees.pyx +310 -0
- sage/graphs/tutte_polynomial.py +713 -0
- sage/graphs/views.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/views.pyx +794 -0
- sage/graphs/weakly_chordal.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/graphs/weakly_chordal.pyx +604 -0
- sage/groups/all__sagemath_graphs.py +1 -0
- sage/groups/perm_gps/all__sagemath_graphs.py +1 -0
- sage/groups/perm_gps/partn_ref/all__sagemath_graphs.py +1 -0
- sage/groups/perm_gps/partn_ref/refinement_graphs.cpython-310-aarch64-linux-gnu.so +0 -0
- sage/groups/perm_gps/partn_ref/refinement_graphs.pxd +38 -0
- sage/groups/perm_gps/partn_ref/refinement_graphs.pyx +1666 -0
- sage/knots/all.py +6 -0
- sage/knots/free_knotinfo_monoid.py +507 -0
- sage/knots/gauss_code.py +291 -0
- sage/knots/knot.py +682 -0
- sage/knots/knot_table.py +284 -0
- sage/knots/knotinfo.py +2900 -0
- sage/knots/link.py +4715 -0
- sage/sandpiles/all.py +13 -0
- sage/sandpiles/examples.py +225 -0
- sage/sandpiles/sandpile.py +6365 -0
- sage/topology/all.py +22 -0
- sage/topology/cell_complex.py +1214 -0
- sage/topology/cubical_complex.py +1976 -0
- sage/topology/delta_complex.py +1806 -0
- sage/topology/filtered_simplicial_complex.py +744 -0
- sage/topology/moment_angle_complex.py +823 -0
- sage/topology/simplicial_complex.py +5160 -0
- sage/topology/simplicial_complex_catalog.py +92 -0
- sage/topology/simplicial_complex_examples.py +1680 -0
- sage/topology/simplicial_complex_homset.py +205 -0
- sage/topology/simplicial_complex_morphism.py +836 -0
- sage/topology/simplicial_set.py +4102 -0
- sage/topology/simplicial_set_catalog.py +55 -0
- sage/topology/simplicial_set_constructions.py +2954 -0
- sage/topology/simplicial_set_examples.py +865 -0
- 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
|