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,1037 @@
|
|
1
|
+
# sage_setup: distribution = sagemath-graphs
|
2
|
+
r"""
|
3
|
+
Linear extensions of posets
|
4
|
+
"""
|
5
|
+
# ****************************************************************************
|
6
|
+
# Copyright (C) 2012 Anne Schilling <anne at math.ucdavis.edu>
|
7
|
+
#
|
8
|
+
# Distributed under the terms of the GNU General Public License (GPL)
|
9
|
+
#
|
10
|
+
# This code is distributed in the hope that it will be useful,
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
13
|
+
# General Public License for more details.
|
14
|
+
#
|
15
|
+
# The full text of the GPL is available at:
|
16
|
+
#
|
17
|
+
# https://www.gnu.org/licenses/
|
18
|
+
# ***************************************************************************
|
19
|
+
|
20
|
+
from sage.misc.lazy_import import lazy_import
|
21
|
+
from sage.rings.rational_field import QQ
|
22
|
+
from sage.structure.unique_representation import UniqueRepresentation
|
23
|
+
from sage.structure.parent import Parent
|
24
|
+
from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets
|
25
|
+
from sage.graphs.digraph import DiGraph
|
26
|
+
from sage.misc.inherit_comparison import InheritComparisonClasscallMetaclass
|
27
|
+
from sage.graphs.dot2tex_utils import have_dot2tex
|
28
|
+
from sage.structure.list_clone import ClonableArray
|
29
|
+
from sage.arith.misc import factorial
|
30
|
+
|
31
|
+
lazy_import('sage.matrix.constructor', 'matrix')
|
32
|
+
|
33
|
+
|
34
|
+
class LinearExtensionOfPoset(ClonableArray,
|
35
|
+
metaclass=InheritComparisonClasscallMetaclass):
|
36
|
+
r"""
|
37
|
+
A linear extension of a finite poset `P` of size `n` is a total
|
38
|
+
ordering `\pi := \pi_0 \pi_1 \ldots \pi_{n-1}` of its elements
|
39
|
+
such that `i<j` whenever `\pi_i < \pi_j` in the poset `P`.
|
40
|
+
|
41
|
+
When the elements of `P` are indexed by `\{1,2,\ldots,n\}`, `\pi`
|
42
|
+
denotes a permutation of the elements of `P` in one-line notation.
|
43
|
+
|
44
|
+
INPUT:
|
45
|
+
|
46
|
+
- ``linear_extension`` -- list of the elements of `P`
|
47
|
+
- ``poset`` -- the underlying poset `P`
|
48
|
+
|
49
|
+
.. SEEALSO:: :class:`~sage.combinat.posets.posets.Poset`, :class:`LinearExtensionsOfPoset`
|
50
|
+
|
51
|
+
EXAMPLES::
|
52
|
+
|
53
|
+
sage: P = Poset(([1,2,3,4], [[1,3],[1,4],[2,3]]),
|
54
|
+
....: linear_extension=True, facade=False)
|
55
|
+
sage: p = P.linear_extension([1,4,2,3]); p
|
56
|
+
[1, 4, 2, 3]
|
57
|
+
sage: p.parent()
|
58
|
+
The set of all linear extensions of
|
59
|
+
Finite poset containing 4 elements with distinguished linear extension
|
60
|
+
sage: p[0], p[1], p[2], p[3]
|
61
|
+
(1, 4, 2, 3)
|
62
|
+
|
63
|
+
Following Schützenberger and later Haiman and
|
64
|
+
Malvenuto-Reutenauer, Stanley [Stan2009]_ defined a promotion
|
65
|
+
and evacuation operator on any finite poset `P` using operators
|
66
|
+
`\tau_i` on the linear extensions of `P`::
|
67
|
+
|
68
|
+
sage: p.promotion()
|
69
|
+
[1, 2, 3, 4]
|
70
|
+
sage: Q = p.promotion().to_poset()
|
71
|
+
sage: Q.cover_relations()
|
72
|
+
[[1, 3], [1, 4], [2, 3]]
|
73
|
+
sage: Q == P
|
74
|
+
True
|
75
|
+
|
76
|
+
sage: p.promotion(3)
|
77
|
+
[1, 4, 2, 3]
|
78
|
+
sage: Q = p.promotion(3).to_poset()
|
79
|
+
sage: Q == P
|
80
|
+
False
|
81
|
+
sage: Q.cover_relations()
|
82
|
+
[[1, 2], [1, 4], [3, 4]]
|
83
|
+
"""
|
84
|
+
@staticmethod
|
85
|
+
def __classcall_private__(cls, linear_extension, poset):
|
86
|
+
r"""
|
87
|
+
Implement the shortcut ``LinearExtensionOfPoset(linear_extension, poset)``
|
88
|
+
to ``LinearExtensionsOfPoset(poset)(linear_extension)``.
|
89
|
+
|
90
|
+
INPUT:
|
91
|
+
|
92
|
+
- ``linear_extension`` -- list of elements of ``poset``
|
93
|
+
- ``poset`` -- a finite poset
|
94
|
+
|
95
|
+
.. TODO:: check whether this method is still useful
|
96
|
+
|
97
|
+
TESTS::
|
98
|
+
|
99
|
+
sage: from sage.combinat.posets.linear_extensions import LinearExtensionOfPoset
|
100
|
+
sage: P = Poset(([1,2,3,4], [[1,3],[1,4],[2,3]]))
|
101
|
+
sage: p = LinearExtensionOfPoset([1,4,2,3], P)
|
102
|
+
sage: p.parent()
|
103
|
+
The set of all linear extensions of Finite poset containing 4 elements
|
104
|
+
sage: type(p)
|
105
|
+
<class 'sage.combinat.posets.linear_extensions.LinearExtensionsOfPoset_with_category.element_class'>
|
106
|
+
sage: p.poset()
|
107
|
+
Finite poset containing 4 elements
|
108
|
+
sage: TestSuite(p).run()
|
109
|
+
|
110
|
+
TESTS::
|
111
|
+
|
112
|
+
sage: LinearExtensionOfPoset([4,3,2,1], P)
|
113
|
+
Traceback (most recent call last):
|
114
|
+
...
|
115
|
+
ValueError: [4, 3, 2, 1] is not a linear extension of Finite poset containing 4 elements
|
116
|
+
|
117
|
+
sage: p is LinearExtensionOfPoset(p, P)
|
118
|
+
True
|
119
|
+
"""
|
120
|
+
if isinstance(linear_extension, cls):
|
121
|
+
return linear_extension
|
122
|
+
return LinearExtensionsOfPoset(poset)(linear_extension)
|
123
|
+
|
124
|
+
def check(self) -> None:
|
125
|
+
r"""
|
126
|
+
Check whether ``self`` is indeed a linear extension of the underlying poset.
|
127
|
+
|
128
|
+
TESTS::
|
129
|
+
|
130
|
+
sage: P = Poset(([1,2,3,4], [[1,3],[1,4],[2,3]]))
|
131
|
+
sage: P.linear_extension([1,4,2,3])
|
132
|
+
[1, 4, 2, 3]
|
133
|
+
sage: P.linear_extension([4,3,2,1])
|
134
|
+
Traceback (most recent call last):
|
135
|
+
...
|
136
|
+
ValueError: [4, 3, 2, 1] is not a linear extension of Finite poset containing 4 elements
|
137
|
+
"""
|
138
|
+
P = self.parent().poset()
|
139
|
+
if not P.is_linear_extension(self):
|
140
|
+
raise ValueError(f"{self} is not a linear extension of {P}")
|
141
|
+
|
142
|
+
def poset(self):
|
143
|
+
r"""
|
144
|
+
Return the underlying original poset.
|
145
|
+
|
146
|
+
EXAMPLES::
|
147
|
+
|
148
|
+
sage: P = Poset(([1,2,3,4], [[1,2],[2,3],[1,4]]))
|
149
|
+
sage: p = P.linear_extension([1,2,4,3])
|
150
|
+
sage: p.poset()
|
151
|
+
Finite poset containing 4 elements
|
152
|
+
"""
|
153
|
+
return self.parent().poset()
|
154
|
+
|
155
|
+
def _latex_(self) -> str:
|
156
|
+
r"""
|
157
|
+
Return the latex string for ``self``.
|
158
|
+
|
159
|
+
EXAMPLES::
|
160
|
+
|
161
|
+
sage: P = Poset(([1,2,3,4], [[1,3],[1,4],[2,3]]))
|
162
|
+
sage: p = P.linear_extension([1,2,3,4])
|
163
|
+
sage: p._latex_()
|
164
|
+
'\\mathtt{(1, 2, 3, 4)}'
|
165
|
+
"""
|
166
|
+
return "\\mathtt{" + str(tuple(self)) + "}"
|
167
|
+
|
168
|
+
def to_poset(self):
|
169
|
+
r"""
|
170
|
+
Return the poset associated to the linear extension ``self``.
|
171
|
+
|
172
|
+
This method returns the poset obtained from the original poset
|
173
|
+
`P` by relabelling the `i`-th element of ``self`` to the
|
174
|
+
`i`-th element of the original poset, while keeping the linear
|
175
|
+
extension of the original poset.
|
176
|
+
|
177
|
+
For a poset with default linear extension `1,\dots,n`,
|
178
|
+
``self`` can be interpreted as a permutation, and the
|
179
|
+
relabelling is done according to the inverse of this
|
180
|
+
permutation.
|
181
|
+
|
182
|
+
EXAMPLES::
|
183
|
+
|
184
|
+
sage: P = Poset(([1,2,3,4], [[1,2],[1,3],[3,4]]), linear_extension=True, facade=False)
|
185
|
+
sage: p = P.linear_extension([1,3,4,2])
|
186
|
+
sage: Q = p.to_poset(); Q
|
187
|
+
Finite poset containing 4 elements with distinguished linear extension
|
188
|
+
sage: P == Q
|
189
|
+
False
|
190
|
+
|
191
|
+
The default linear extension remains the same::
|
192
|
+
|
193
|
+
sage: list(P)
|
194
|
+
[1, 2, 3, 4]
|
195
|
+
sage: list(Q)
|
196
|
+
[1, 2, 3, 4]
|
197
|
+
|
198
|
+
But the relabelling can be seen on cover relations::
|
199
|
+
|
200
|
+
sage: P.cover_relations()
|
201
|
+
[[1, 2], [1, 3], [3, 4]]
|
202
|
+
sage: Q.cover_relations()
|
203
|
+
[[1, 2], [1, 4], [2, 3]]
|
204
|
+
|
205
|
+
sage: p = P.linear_extension([1,2,3,4])
|
206
|
+
sage: Q = p.to_poset()
|
207
|
+
sage: P == Q
|
208
|
+
True
|
209
|
+
"""
|
210
|
+
P = self.parent().poset()
|
211
|
+
old = (P.unwrap(x) for x in self)
|
212
|
+
new = [P.unwrap(x) for x in P]
|
213
|
+
relabelling = dict(zip(old, new))
|
214
|
+
return P.relabel(relabelling).with_linear_extension(new)
|
215
|
+
|
216
|
+
def is_greedy(self) -> bool:
|
217
|
+
r"""
|
218
|
+
Return ``True`` if the linear extension is greedy.
|
219
|
+
|
220
|
+
A linear extension `[e_1, e_2, \ldots, e_n]` is *greedy* if for
|
221
|
+
every `i` either `e_{i+1}` covers `e_i` or all upper covers
|
222
|
+
of `e_i` have at least one lower cover that is not in
|
223
|
+
`[e_1, e_2, \ldots, e_i]`.
|
224
|
+
|
225
|
+
Informally said a linear extension is greedy if it "always
|
226
|
+
goes up when possible" and so has no unnecessary jumps.
|
227
|
+
|
228
|
+
EXAMPLES::
|
229
|
+
|
230
|
+
sage: P = posets.PentagonPoset() # needs sage.modules
|
231
|
+
sage: for l in P.linear_extensions(): # needs sage.modules
|
232
|
+
....: if not l.is_greedy():
|
233
|
+
....: print(l)
|
234
|
+
[0, 2, 1, 3, 4]
|
235
|
+
|
236
|
+
TESTS::
|
237
|
+
|
238
|
+
sage: E = Poset()
|
239
|
+
sage: E.linear_extensions()[0].is_greedy()
|
240
|
+
True
|
241
|
+
"""
|
242
|
+
P = self.poset()
|
243
|
+
for i in range(len(self) - 1):
|
244
|
+
if not P.covers(self[i], self[i + 1]):
|
245
|
+
for u in P.upper_covers(self[i]):
|
246
|
+
if all(l in self[:i + 1] for l in P.lower_covers(u)):
|
247
|
+
return False
|
248
|
+
return True
|
249
|
+
|
250
|
+
def is_supergreedy(self) -> bool:
|
251
|
+
r"""
|
252
|
+
Return ``True`` if the linear extension is supergreedy.
|
253
|
+
|
254
|
+
A linear extension of a poset `P` with elements `\{x_1,x_2,...,x_t\}`
|
255
|
+
is *super greedy*, if it can be obtained using the following
|
256
|
+
algorithm: choose `x_1` to be a minimal element of `P`;
|
257
|
+
suppose `X = \{x_1,...,x_i\}` have been chosen; let `M` be
|
258
|
+
the set of minimal elements of `P\setminus X`. If there is an element
|
259
|
+
of `M` which covers an element `x_j` in `X`, then let `x_{i+1}`
|
260
|
+
be one of these such that `j` is maximal; otherwise, choose `x_{i+1}`
|
261
|
+
to be any element of `M`.
|
262
|
+
|
263
|
+
Informally, a linear extension is supergreedy if it "always
|
264
|
+
goes up and receedes the least"; in other words, supergreedy
|
265
|
+
linear extensions are depth-first linear extensions.
|
266
|
+
For more details see [KTZ1987]_.
|
267
|
+
|
268
|
+
EXAMPLES::
|
269
|
+
|
270
|
+
sage: X = [0,1,2,3,4,5,6]
|
271
|
+
sage: Y = [[0,5],[1,4],[1,5],[3,6],[4,3],[5,6],[6,2]]
|
272
|
+
sage: P = Poset((X,Y), cover_relations=True, facade=False)
|
273
|
+
sage: for l in P.linear_extensions(): # needs sage.modules
|
274
|
+
....: if l.is_supergreedy():
|
275
|
+
....: print(l)
|
276
|
+
[1, 4, 3, 0, 5, 6, 2]
|
277
|
+
[0, 1, 4, 3, 5, 6, 2]
|
278
|
+
[0, 1, 5, 4, 3, 6, 2]
|
279
|
+
|
280
|
+
sage: Q = posets.PentagonPoset() # needs sage.modules
|
281
|
+
sage: for l in Q.linear_extensions(): # needs sage.modules sage.rings.finite_rings
|
282
|
+
....: if not l.is_supergreedy():
|
283
|
+
....: print(l)
|
284
|
+
[0, 2, 1, 3, 4]
|
285
|
+
|
286
|
+
TESTS::
|
287
|
+
|
288
|
+
sage: T = Poset()
|
289
|
+
sage: T.linear_extensions()[0].is_supergreedy()
|
290
|
+
True
|
291
|
+
"""
|
292
|
+
H = self.poset().hasse_diagram()
|
293
|
+
L = sources = H.sources()
|
294
|
+
linext = []
|
295
|
+
for e in self:
|
296
|
+
if e not in L:
|
297
|
+
return False
|
298
|
+
linext.append(e)
|
299
|
+
for y in reversed(linext):
|
300
|
+
L = [x for x in H.neighbor_out_iterator(y)
|
301
|
+
if x not in linext
|
302
|
+
and all(low in linext for low in H.neighbor_in_iterator(x))]
|
303
|
+
if L:
|
304
|
+
break
|
305
|
+
else:
|
306
|
+
L = sources = [x for x in sources if x not in linext]
|
307
|
+
return True
|
308
|
+
|
309
|
+
def tau(self, i):
|
310
|
+
r"""
|
311
|
+
Return the operator `\tau_i` on linear extensions ``self`` of a poset.
|
312
|
+
|
313
|
+
INPUT:
|
314
|
+
|
315
|
+
- ``i`` -- integer between `1` and `n-1`, where `n` is the
|
316
|
+
cardinality of the poset
|
317
|
+
|
318
|
+
The operator `\tau_i` on a linear extension `\pi` of a poset
|
319
|
+
`P` interchanges positions `i` and `i+1` if the result is
|
320
|
+
again a linear extension of `P`, and otherwise acts
|
321
|
+
trivially. For more details, see [Stan2009]_.
|
322
|
+
|
323
|
+
EXAMPLES::
|
324
|
+
|
325
|
+
sage: P = Poset(([1,2,3,4], [[1,3],[1,4],[2,3]]), linear_extension=True)
|
326
|
+
sage: L = P.linear_extensions()
|
327
|
+
sage: l = L.an_element(); l
|
328
|
+
[1, 2, 3, 4]
|
329
|
+
sage: l.tau(1)
|
330
|
+
[2, 1, 3, 4]
|
331
|
+
sage: for p in L: # needs sage.modules
|
332
|
+
....: for i in range(1,4):
|
333
|
+
....: print("{} {} {}".format(i, p, p.tau(i)))
|
334
|
+
1 [1, 2, 3, 4] [2, 1, 3, 4]
|
335
|
+
2 [1, 2, 3, 4] [1, 2, 3, 4]
|
336
|
+
3 [1, 2, 3, 4] [1, 2, 4, 3]
|
337
|
+
1 [2, 1, 3, 4] [1, 2, 3, 4]
|
338
|
+
2 [2, 1, 3, 4] [2, 1, 3, 4]
|
339
|
+
3 [2, 1, 3, 4] [2, 1, 4, 3]
|
340
|
+
1 [2, 1, 4, 3] [1, 2, 4, 3]
|
341
|
+
2 [2, 1, 4, 3] [2, 1, 4, 3]
|
342
|
+
3 [2, 1, 4, 3] [2, 1, 3, 4]
|
343
|
+
1 [1, 4, 2, 3] [1, 4, 2, 3]
|
344
|
+
2 [1, 4, 2, 3] [1, 2, 4, 3]
|
345
|
+
3 [1, 4, 2, 3] [1, 4, 2, 3]
|
346
|
+
1 [1, 2, 4, 3] [2, 1, 4, 3]
|
347
|
+
2 [1, 2, 4, 3] [1, 4, 2, 3]
|
348
|
+
3 [1, 2, 4, 3] [1, 2, 3, 4]
|
349
|
+
|
350
|
+
TESTS::
|
351
|
+
|
352
|
+
sage: type(l.tau(1))
|
353
|
+
<class 'sage.combinat.posets.linear_extensions.LinearExtensionsOfPoset_with_category.element_class'>
|
354
|
+
sage: l.tau(2) == l
|
355
|
+
True
|
356
|
+
"""
|
357
|
+
P = self.poset()
|
358
|
+
a = self[i - 1]
|
359
|
+
b = self[i]
|
360
|
+
if P.lt(a, b) or P.lt(b, a):
|
361
|
+
return self
|
362
|
+
with self.clone() as q:
|
363
|
+
q[i - 1] = b
|
364
|
+
q[i] = a
|
365
|
+
return q
|
366
|
+
|
367
|
+
def promotion(self, i=1):
|
368
|
+
r"""
|
369
|
+
Compute the (generalized) promotion on the linear extension of a poset.
|
370
|
+
|
371
|
+
INPUT:
|
372
|
+
|
373
|
+
- ``i`` -- (default: `1`) an integer between `1` and `n-1`,
|
374
|
+
where `n` is the cardinality of the poset
|
375
|
+
|
376
|
+
The `i`-th generalized promotion operator `\partial_i` on a linear
|
377
|
+
extension `\pi` is defined as `\pi \tau_i \tau_{i+1} \cdots \tau_{n-1}`,
|
378
|
+
where `n` is the size of the linear extension (or size of the
|
379
|
+
underlying poset).
|
380
|
+
|
381
|
+
For more details see [Stan2009]_.
|
382
|
+
|
383
|
+
.. SEEALSO:: :meth:`tau`, :meth:`evacuation`
|
384
|
+
|
385
|
+
EXAMPLES::
|
386
|
+
|
387
|
+
sage: P = Poset(([1,2,3,4,5,6,7], [[1,2],[1,4],[2,3],[2,5],[3,6],[4,7],[5,6]]))
|
388
|
+
sage: p = P.linear_extension([1,2,3,4,5,6,7])
|
389
|
+
sage: q = p.promotion(4); q
|
390
|
+
[1, 2, 3, 5, 6, 4, 7]
|
391
|
+
sage: p.to_poset() == q.to_poset()
|
392
|
+
False
|
393
|
+
sage: p.to_poset().is_isomorphic(q.to_poset())
|
394
|
+
True
|
395
|
+
"""
|
396
|
+
for j in range(i, len(self)):
|
397
|
+
self = self.tau(j)
|
398
|
+
return self
|
399
|
+
|
400
|
+
def evacuation(self):
|
401
|
+
r"""
|
402
|
+
Compute evacuation on the linear extension of a poset.
|
403
|
+
|
404
|
+
Evacuation on a linear extension `\pi` of length `n` is defined as
|
405
|
+
`\pi (\tau_1 \cdots \tau_{n-1}) (\tau_1 \cdots \tau_{n-2}) \cdots (\tau_1)`.
|
406
|
+
For more details see [Stan2009]_.
|
407
|
+
|
408
|
+
.. SEEALSO:: :meth:`tau`, :meth:`promotion`
|
409
|
+
|
410
|
+
EXAMPLES::
|
411
|
+
|
412
|
+
sage: P = Poset(([1,2,3,4,5,6,7], [[1,2],[1,4],[2,3],[2,5],[3,6],[4,7],[5,6]]))
|
413
|
+
sage: p = P.linear_extension([1,2,3,4,5,6,7])
|
414
|
+
sage: p.evacuation()
|
415
|
+
[1, 4, 2, 3, 7, 5, 6]
|
416
|
+
sage: p.evacuation().evacuation() == p
|
417
|
+
True
|
418
|
+
"""
|
419
|
+
for i in reversed(range(1, len(self) + 1)):
|
420
|
+
for j in range(1, i):
|
421
|
+
self = self.tau(j)
|
422
|
+
return self
|
423
|
+
|
424
|
+
def jump_count(self) -> int:
|
425
|
+
r"""
|
426
|
+
Return the number of jumps in the linear extension.
|
427
|
+
|
428
|
+
A *jump* in a linear extension `[e_1, e_2, \ldots, e_n]`
|
429
|
+
is a pair `(e_i, e_{i+1})` such that `e_{i+1}` does not
|
430
|
+
cover `e_i`.
|
431
|
+
|
432
|
+
.. SEEALSO::
|
433
|
+
|
434
|
+
- :meth:`sage.combinat.posets.posets.FinitePoset.jump_number()`
|
435
|
+
|
436
|
+
EXAMPLES::
|
437
|
+
|
438
|
+
sage: B3 = posets.BooleanLattice(3)
|
439
|
+
sage: l1 = B3.linear_extension((0, 1, 2, 3, 4, 5, 6, 7))
|
440
|
+
sage: l1.jump_count()
|
441
|
+
3
|
442
|
+
sage: l2 = B3.linear_extension((0, 1, 2, 4, 3, 5, 6, 7))
|
443
|
+
sage: l2.jump_count()
|
444
|
+
5
|
445
|
+
|
446
|
+
TESTS::
|
447
|
+
|
448
|
+
sage: E = Poset()
|
449
|
+
sage: E.linear_extensions()[0].jump_count()
|
450
|
+
0
|
451
|
+
sage: C4 = posets.ChainPoset(4)
|
452
|
+
sage: C4.linear_extensions()[0].jump_count()
|
453
|
+
0
|
454
|
+
sage: A4 = posets.AntichainPoset(4)
|
455
|
+
sage: A4.linear_extensions()[0].jump_count()
|
456
|
+
3
|
457
|
+
"""
|
458
|
+
P = self.poset()
|
459
|
+
n = 0
|
460
|
+
for i in range(len(self) - 1):
|
461
|
+
if not P.covers(self[i], self[i + 1]):
|
462
|
+
n += 1
|
463
|
+
return n
|
464
|
+
|
465
|
+
|
466
|
+
class LinearExtensionsOfPoset(UniqueRepresentation, Parent):
|
467
|
+
"""
|
468
|
+
The set of all linear extensions of a finite poset.
|
469
|
+
|
470
|
+
INPUT:
|
471
|
+
|
472
|
+
- ``poset`` -- a poset `P` of size `n`
|
473
|
+
- ``facade`` -- boolean (default: ``False``)
|
474
|
+
|
475
|
+
.. SEEALSO::
|
476
|
+
|
477
|
+
- :meth:`sage.combinat.posets.posets.FinitePoset.linear_extensions`
|
478
|
+
|
479
|
+
EXAMPLES::
|
480
|
+
|
481
|
+
sage: elms = [1,2,3,4]
|
482
|
+
sage: rels = [[1,3],[1,4],[2,3]]
|
483
|
+
sage: P = Poset((elms, rels), linear_extension=True)
|
484
|
+
sage: L = P.linear_extensions(); L
|
485
|
+
The set of all linear extensions of
|
486
|
+
Finite poset containing 4 elements with distinguished linear extension
|
487
|
+
sage: L.cardinality()
|
488
|
+
5
|
489
|
+
sage: L.list() # needs sage.modules
|
490
|
+
[[1, 2, 3, 4], [2, 1, 3, 4], [2, 1, 4, 3], [1, 4, 2, 3], [1, 2, 4, 3]]
|
491
|
+
sage: L.an_element()
|
492
|
+
[1, 2, 3, 4]
|
493
|
+
sage: L.poset()
|
494
|
+
Finite poset containing 4 elements with distinguished linear extension
|
495
|
+
"""
|
496
|
+
|
497
|
+
@staticmethod
|
498
|
+
def __classcall_private__(cls, poset, facade=False):
|
499
|
+
r"""
|
500
|
+
Straighten arguments before unique representation.
|
501
|
+
|
502
|
+
TESTS::
|
503
|
+
|
504
|
+
sage: from sage.combinat.posets.linear_extensions import LinearExtensionsOfPoset
|
505
|
+
sage: P = Poset(([1,2],[[1,2]]))
|
506
|
+
sage: L = LinearExtensionsOfPoset(P)
|
507
|
+
sage: type(L)
|
508
|
+
<class 'sage.combinat.posets.linear_extensions.LinearExtensionsOfPoset_with_category'>
|
509
|
+
sage: L is LinearExtensionsOfPoset(P,facade=False)
|
510
|
+
True
|
511
|
+
"""
|
512
|
+
return super().__classcall__(cls, poset, facade=facade)
|
513
|
+
|
514
|
+
def __init__(self, poset, facade) -> None:
|
515
|
+
"""
|
516
|
+
TESTS::
|
517
|
+
|
518
|
+
sage: from sage.combinat.posets.linear_extensions import LinearExtensionsOfPoset
|
519
|
+
sage: P = Poset(([1,2,3],[[1,2],[1,3]]))
|
520
|
+
sage: L = P.linear_extensions()
|
521
|
+
sage: L is LinearExtensionsOfPoset(P)
|
522
|
+
True
|
523
|
+
sage: L._poset is P
|
524
|
+
True
|
525
|
+
sage: TestSuite(L).run() # needs sage.modules
|
526
|
+
|
527
|
+
sage: P = Poset((divisors(15), attrcall("divides")))
|
528
|
+
sage: L = P.linear_extensions()
|
529
|
+
sage: TestSuite(L).run() # needs sage.modules
|
530
|
+
|
531
|
+
sage: P = Poset((divisors(15), attrcall("divides")), facade=True)
|
532
|
+
sage: L = P.linear_extensions()
|
533
|
+
sage: TestSuite(L).run() # needs sage.modules
|
534
|
+
|
535
|
+
sage: L = P.linear_extensions(facade=True)
|
536
|
+
sage: TestSuite(L).run(skip='_test_an_element') # needs sage.modules
|
537
|
+
"""
|
538
|
+
self._poset = poset
|
539
|
+
self._is_facade = facade
|
540
|
+
if facade:
|
541
|
+
facade = (list,)
|
542
|
+
Parent.__init__(self, category=FiniteEnumeratedSets(), facade=facade)
|
543
|
+
|
544
|
+
def _repr_(self) -> str:
|
545
|
+
"""
|
546
|
+
TESTS::
|
547
|
+
|
548
|
+
sage: P = Poset(([1,2,3],[[1,2],[1,3]]))
|
549
|
+
sage: P.linear_extensions()
|
550
|
+
The set of all linear extensions of Finite poset containing 3 elements
|
551
|
+
"""
|
552
|
+
return "The set of all linear extensions of %s" % (self._poset)
|
553
|
+
|
554
|
+
def poset(self):
|
555
|
+
r"""
|
556
|
+
Return the underlying original poset.
|
557
|
+
|
558
|
+
EXAMPLES::
|
559
|
+
|
560
|
+
sage: P = Poset(([1,2,3,4], [[1,2],[2,3],[1,4]]))
|
561
|
+
sage: L = P.linear_extensions()
|
562
|
+
sage: L.poset()
|
563
|
+
Finite poset containing 4 elements
|
564
|
+
"""
|
565
|
+
return self._poset
|
566
|
+
|
567
|
+
def cardinality(self):
|
568
|
+
"""
|
569
|
+
Return the number of linear extensions.
|
570
|
+
|
571
|
+
EXAMPLES::
|
572
|
+
|
573
|
+
sage: N = Poset({0: [2, 3], 1: [3]})
|
574
|
+
sage: N.linear_extensions().cardinality()
|
575
|
+
5
|
576
|
+
|
577
|
+
TESTS::
|
578
|
+
|
579
|
+
sage: Poset().linear_extensions().cardinality()
|
580
|
+
1
|
581
|
+
sage: posets.ChainPoset(1).linear_extensions().cardinality()
|
582
|
+
1
|
583
|
+
sage: posets.BooleanLattice(4).linear_extensions().cardinality()
|
584
|
+
1680384
|
585
|
+
"""
|
586
|
+
from sage.rings.integer import Integer
|
587
|
+
|
588
|
+
n = len(self._poset)
|
589
|
+
if not n:
|
590
|
+
return Integer(1)
|
591
|
+
|
592
|
+
up = self._poset._hasse_diagram.to_dictionary()
|
593
|
+
# Convert to the Hasse diagram so our poset can be realized on
|
594
|
+
# the set {0,...,n-1} with a nice dictionary of edges
|
595
|
+
|
596
|
+
for i in range(n):
|
597
|
+
up[n - 1 - i] = sorted(set(up[n - 1 - i] +
|
598
|
+
[item for x in up[n - 1 - i]
|
599
|
+
for item in up[x]]))
|
600
|
+
# Compute the principal order filter for each element.
|
601
|
+
|
602
|
+
Jup = {1: []}
|
603
|
+
# Jup will be a dictionary giving up edges in J(P)
|
604
|
+
|
605
|
+
# We will perform a loop where after k loops, we will have a
|
606
|
+
# list of up edges for the lattice of order ideals for P
|
607
|
+
# restricted to entries 0,...,k.
|
608
|
+
loc = [1] * n
|
609
|
+
|
610
|
+
# This list will be indexed by entries in P. After k loops,
|
611
|
+
# the entry loc[i] will correspond to the element of J(P) that
|
612
|
+
# is the principal order ideal of i, restricted to the
|
613
|
+
# elements 0,...,k .
|
614
|
+
|
615
|
+
m = 1
|
616
|
+
# m keeps track of how many elements we currently have in J(P).
|
617
|
+
# We start with just the empty order ideal, and no relations.
|
618
|
+
for x in range(n):
|
619
|
+
# Use the existing Jup table to compute all covering
|
620
|
+
# relations in J(P) for things that are above loc(x).
|
621
|
+
K0 = [[loc[x]]]
|
622
|
+
j = 0
|
623
|
+
while K0[j]:
|
624
|
+
K0.append([b for a in K0[j] for b in Jup[a]])
|
625
|
+
j += 1
|
626
|
+
K = sorted({item for sublist in K0 for item in sublist})
|
627
|
+
for j in range(len(K)):
|
628
|
+
i = m + j + 1
|
629
|
+
Jup[i] = [m + K.index(a) + 1 for a in Jup[K[j]]]
|
630
|
+
# These are copies of the covering relations with
|
631
|
+
# elements from K, but now with the underlying
|
632
|
+
# elements containing x.
|
633
|
+
Jup[K[j]] = Jup[K[j]] + [i]
|
634
|
+
# There are the new covering relations we get between
|
635
|
+
# ideals that don't contain x and those that do.
|
636
|
+
for y in up[x]:
|
637
|
+
loc[y] = K.index(loc[y]) + m + 1
|
638
|
+
# Updates loc[y] if y is above x.
|
639
|
+
m += len(K)
|
640
|
+
# Now we have a dictionary of covering relations for J(P). The
|
641
|
+
# following shortcut works to count maximal chains, since we
|
642
|
+
# made J(P) naturally labelled, and J(P) has a unique maximal
|
643
|
+
# element and minimum element.
|
644
|
+
|
645
|
+
Jup[m] = Integer(1)
|
646
|
+
while m > 1:
|
647
|
+
m -= 1
|
648
|
+
ct = Integer(0)
|
649
|
+
for j in Jup[m]:
|
650
|
+
ct += Jup[j]
|
651
|
+
Jup[m] = ct
|
652
|
+
return ct
|
653
|
+
|
654
|
+
def __iter__(self):
|
655
|
+
r"""
|
656
|
+
Iterate through the linear extensions of the underlying poset.
|
657
|
+
|
658
|
+
EXAMPLES::
|
659
|
+
|
660
|
+
sage: elms = [1,2,3,4]
|
661
|
+
sage: rels = [[1,3],[1,4],[2,3]]
|
662
|
+
sage: P = Poset((elms, rels), linear_extension=True)
|
663
|
+
sage: L = P.linear_extensions()
|
664
|
+
sage: list(L) # needs sage.modules
|
665
|
+
[[1, 2, 3, 4], [2, 1, 3, 4], [2, 1, 4, 3], [1, 4, 2, 3], [1, 2, 4, 3]]
|
666
|
+
"""
|
667
|
+
from sage.combinat.posets.linear_extension_iterator import linear_extension_iterator
|
668
|
+
vertex_to_element = self._poset._vertex_to_element
|
669
|
+
for lin_ext in linear_extension_iterator(self._poset._hasse_diagram):
|
670
|
+
yield self._element_constructor_([vertex_to_element(_) for _ in lin_ext])
|
671
|
+
|
672
|
+
def __contains__(self, obj) -> bool:
|
673
|
+
"""
|
674
|
+
Membership testing
|
675
|
+
|
676
|
+
EXAMPLES::
|
677
|
+
|
678
|
+
sage: P = Poset((divisors(12), attrcall("divides")), facade=True, linear_extension=True)
|
679
|
+
sage: P.list()
|
680
|
+
[1, 2, 3, 4, 6, 12]
|
681
|
+
sage: L = P.linear_extensions()
|
682
|
+
sage: L([1, 2, 4, 3, 6, 12]) in L
|
683
|
+
True
|
684
|
+
sage: [1, 2, 4, 3, 6, 12] in L
|
685
|
+
False
|
686
|
+
|
687
|
+
sage: L = P.linear_extensions(facade=True)
|
688
|
+
sage: [1, 2, 4, 3, 6, 12] in L
|
689
|
+
True
|
690
|
+
sage: [1, 3, 2, 6, 4, 12] in L
|
691
|
+
True
|
692
|
+
sage: [1, 3, 6, 2, 4, 12] in L
|
693
|
+
False
|
694
|
+
|
695
|
+
sage: [p for p in Permutations(list(P)) if list(p) in L]
|
696
|
+
[[1, 2, 3, 4, 6, 12], [1, 2, 3, 6, 4, 12], [1, 2, 4, 3, 6, 12], [1, 3, 2, 4, 6, 12], [1, 3, 2, 6, 4, 12]]
|
697
|
+
"""
|
698
|
+
if not self._is_facade:
|
699
|
+
return super().__contains__(obj)
|
700
|
+
return (isinstance(obj, (list, tuple)) and
|
701
|
+
self.poset().is_linear_extension(obj))
|
702
|
+
|
703
|
+
def markov_chain_digraph(self, action='promotion', labeling='identity') -> DiGraph:
|
704
|
+
r"""
|
705
|
+
Return the digraph of the action of generalized promotion or tau on ``self``.
|
706
|
+
|
707
|
+
INPUT:
|
708
|
+
|
709
|
+
- ``action`` -- 'promotion' or 'tau' (default: ``'promotion'``)
|
710
|
+
- ``labeling`` -- 'identity' or 'source' (default: ``'identity'``)
|
711
|
+
|
712
|
+
.. TODO::
|
713
|
+
|
714
|
+
- generalize this feature by accepting a family of operators as input
|
715
|
+
- move up in some appropriate category
|
716
|
+
|
717
|
+
This method creates a graph with vertices being the linear extensions of a given finite
|
718
|
+
poset and an edge from `\pi` to `\pi'` if `\pi' = \pi \partial_i` where `\partial_i` is
|
719
|
+
the promotion operator (see :meth:`promotion`) if ``action`` is set to ``promotion``
|
720
|
+
and `\tau_i` (see :meth:`tau`) if ``action`` is set to ``tau``. The label of the edge
|
721
|
+
is `i` (resp. `\pi_i`) if ``labeling`` is set to ``identity`` (resp. ``source``).
|
722
|
+
|
723
|
+
EXAMPLES::
|
724
|
+
|
725
|
+
sage: # needs sage.modules
|
726
|
+
sage: P = Poset(([1,2,3,4], [[1,3],[1,4],[2,3]]), linear_extension=True)
|
727
|
+
sage: L = P.linear_extensions()
|
728
|
+
sage: G = L.markov_chain_digraph(); G
|
729
|
+
Looped multi-digraph on 5 vertices
|
730
|
+
sage: G.vertices(sort=True, key=repr)
|
731
|
+
[[1, 2, 3, 4], [1, 2, 4, 3], [1, 4, 2, 3], [2, 1, 3, 4], [2, 1, 4, 3]]
|
732
|
+
sage: G.edges(sort=True, key=repr)
|
733
|
+
[([1, 2, 3, 4], [1, 2, 3, 4], 4), ([1, 2, 3, 4], [1, 2, 4, 3], 2), ([1, 2, 3, 4], [1, 2, 4, 3], 3),
|
734
|
+
([1, 2, 3, 4], [2, 1, 4, 3], 1), ([1, 2, 4, 3], [1, 2, 3, 4], 3), ([1, 2, 4, 3], [1, 2, 4, 3], 4),
|
735
|
+
([1, 2, 4, 3], [1, 4, 2, 3], 2), ([1, 2, 4, 3], [2, 1, 3, 4], 1), ([1, 4, 2, 3], [1, 2, 3, 4], 1),
|
736
|
+
([1, 4, 2, 3], [1, 2, 3, 4], 2), ([1, 4, 2, 3], [1, 4, 2, 3], 3), ([1, 4, 2, 3], [1, 4, 2, 3], 4),
|
737
|
+
([2, 1, 3, 4], [1, 2, 4, 3], 1), ([2, 1, 3, 4], [2, 1, 3, 4], 4), ([2, 1, 3, 4], [2, 1, 4, 3], 2),
|
738
|
+
([2, 1, 3, 4], [2, 1, 4, 3], 3), ([2, 1, 4, 3], [1, 4, 2, 3], 1), ([2, 1, 4, 3], [2, 1, 3, 4], 2),
|
739
|
+
([2, 1, 4, 3], [2, 1, 3, 4], 3), ([2, 1, 4, 3], [2, 1, 4, 3], 4)]
|
740
|
+
sage: G = L.markov_chain_digraph(labeling='source')
|
741
|
+
sage: G.vertices(sort=True, key=repr)
|
742
|
+
[[1, 2, 3, 4], [1, 2, 4, 3], [1, 4, 2, 3], [2, 1, 3, 4], [2, 1, 4, 3]]
|
743
|
+
sage: G.edges(sort=True, key=repr)
|
744
|
+
[([1, 2, 3, 4], [1, 2, 3, 4], 4), ([1, 2, 3, 4], [1, 2, 4, 3], 2), ([1, 2, 3, 4], [1, 2, 4, 3], 3),
|
745
|
+
([1, 2, 3, 4], [2, 1, 4, 3], 1), ([1, 2, 4, 3], [1, 2, 3, 4], 4), ([1, 2, 4, 3], [1, 2, 4, 3], 3),
|
746
|
+
([1, 2, 4, 3], [1, 4, 2, 3], 2), ([1, 2, 4, 3], [2, 1, 3, 4], 1), ([1, 4, 2, 3], [1, 2, 3, 4], 1),
|
747
|
+
([1, 4, 2, 3], [1, 2, 3, 4], 4), ([1, 4, 2, 3], [1, 4, 2, 3], 2), ([1, 4, 2, 3], [1, 4, 2, 3], 3),
|
748
|
+
([2, 1, 3, 4], [1, 2, 4, 3], 2), ([2, 1, 3, 4], [2, 1, 3, 4], 4), ([2, 1, 3, 4], [2, 1, 4, 3], 1),
|
749
|
+
([2, 1, 3, 4], [2, 1, 4, 3], 3), ([2, 1, 4, 3], [1, 4, 2, 3], 2), ([2, 1, 4, 3], [2, 1, 3, 4], 1),
|
750
|
+
([2, 1, 4, 3], [2, 1, 3, 4], 4), ([2, 1, 4, 3], [2, 1, 4, 3], 3)]
|
751
|
+
|
752
|
+
The edges of the graph are by default colored using blue for
|
753
|
+
edge 1, red for edge 2, green for edge 3, and yellow for edge 4::
|
754
|
+
|
755
|
+
sage: view(G) # optional - dot2tex graphviz, not tested (opens external window)
|
756
|
+
|
757
|
+
Alternatively, one may get the graph of the action of the ``tau`` operator::
|
758
|
+
|
759
|
+
sage: G = L.markov_chain_digraph(action='tau'); G
|
760
|
+
Looped multi-digraph on 5 vertices
|
761
|
+
sage: G.vertices(sort=True, key=repr)
|
762
|
+
[[1, 2, 3, 4], [1, 2, 4, 3], [1, 4, 2, 3], [2, 1, 3, 4], [2, 1, 4, 3]]
|
763
|
+
sage: G.edges(sort=True, key=repr)
|
764
|
+
[([1, 2, 3, 4], [1, 2, 3, 4], 2), ([1, 2, 3, 4], [1, 2, 4, 3], 3), ([1, 2, 3, 4], [2, 1, 3, 4], 1),
|
765
|
+
([1, 2, 4, 3], [1, 2, 3, 4], 3), ([1, 2, 4, 3], [1, 4, 2, 3], 2), ([1, 2, 4, 3], [2, 1, 4, 3], 1),
|
766
|
+
([1, 4, 2, 3], [1, 2, 4, 3], 2), ([1, 4, 2, 3], [1, 4, 2, 3], 1), ([1, 4, 2, 3], [1, 4, 2, 3], 3),
|
767
|
+
([2, 1, 3, 4], [1, 2, 3, 4], 1), ([2, 1, 3, 4], [2, 1, 3, 4], 2), ([2, 1, 3, 4], [2, 1, 4, 3], 3),
|
768
|
+
([2, 1, 4, 3], [1, 2, 4, 3], 1), ([2, 1, 4, 3], [2, 1, 3, 4], 3), ([2, 1, 4, 3], [2, 1, 4, 3], 2)]
|
769
|
+
sage: view(G) # optional - dot2tex graphviz, not tested (opens external window)
|
770
|
+
|
771
|
+
.. SEEALSO:: :meth:`markov_chain_transition_matrix`, :meth:`promotion`, :meth:`tau`
|
772
|
+
|
773
|
+
TESTS::
|
774
|
+
|
775
|
+
sage: P = Poset(([1,2,3,4], [[1,3],[1,4],[2,3]]), linear_extension=True, facade=True)
|
776
|
+
sage: L = P.linear_extensions()
|
777
|
+
sage: G = L.markov_chain_digraph(labeling='source'); G
|
778
|
+
Looped multi-digraph on 5 vertices
|
779
|
+
"""
|
780
|
+
L = sorted(self)
|
781
|
+
d = {x: {y: [] for y in L} for x in L}
|
782
|
+
if action == 'promotion':
|
783
|
+
R = list(range(self.poset().cardinality()))
|
784
|
+
else:
|
785
|
+
R = list(range(self.poset().cardinality() - 1))
|
786
|
+
if labeling == 'source':
|
787
|
+
for x in L:
|
788
|
+
for i in R:
|
789
|
+
child = getattr(x, action)(i + 1)
|
790
|
+
d[x][child] += [self.poset().unwrap(x[i])]
|
791
|
+
else:
|
792
|
+
for x in L:
|
793
|
+
for i in R:
|
794
|
+
child = getattr(x, action)(i + 1)
|
795
|
+
d[x][child] += [i + 1]
|
796
|
+
G = DiGraph(d, format='dict_of_dicts')
|
797
|
+
if have_dot2tex():
|
798
|
+
G.set_latex_options(format='dot2tex', edge_labels=True,
|
799
|
+
color_by_label={1: "blue", 2: "red",
|
800
|
+
3: "green", 4: "yellow"})
|
801
|
+
return G
|
802
|
+
|
803
|
+
def markov_chain_transition_matrix(self, action='promotion', labeling='identity'):
|
804
|
+
r"""
|
805
|
+
Return the transition matrix of the Markov chain for the action of
|
806
|
+
generalized promotion or tau on ``self``.
|
807
|
+
|
808
|
+
INPUT:
|
809
|
+
|
810
|
+
- ``action`` -- ``'promotion'`` or ``'tau'`` (default: ``'promotion'``)
|
811
|
+
- ``labeling`` -- ``'identity'`` or ``'source'`` (default: ``'identity'``)
|
812
|
+
|
813
|
+
This method yields the transition matrix of the Markov chain defined by
|
814
|
+
the action of the generalized promotion operator `\partial_i` (resp.
|
815
|
+
`\tau_i`) on the set of linear extensions of a finite poset. Here the
|
816
|
+
transition from the linear extension `\pi` to `\pi'`, where
|
817
|
+
`\pi' = \pi \partial_i` (resp. `\pi'= \pi \tau_i`) is counted with
|
818
|
+
weight `x_i` (resp. `x_{\pi_i}` if ``labeling`` is set to ``source``).
|
819
|
+
|
820
|
+
EXAMPLES::
|
821
|
+
|
822
|
+
sage: P = Poset(([1,2,3,4], [[1,3],[1,4],[2,3]]), linear_extension=True)
|
823
|
+
sage: L = P.linear_extensions()
|
824
|
+
sage: L.markov_chain_transition_matrix() # needs sage.modules
|
825
|
+
[-x0 - x1 - x2 x2 x0 + x1 0 0]
|
826
|
+
[ x1 + x2 -x0 - x1 - x2 0 x0 0]
|
827
|
+
[ 0 x1 -x0 - x1 0 x0]
|
828
|
+
[ 0 x0 0 -x0 - x1 - x2 x1 + x2]
|
829
|
+
[ x0 0 0 x1 + x2 -x0 - x1 - x2]
|
830
|
+
|
831
|
+
sage: L.markov_chain_transition_matrix(labeling='source') # needs sage.modules
|
832
|
+
[-x0 - x1 - x2 x3 x0 + x3 0 0]
|
833
|
+
[ x1 + x2 -x0 - x1 - x3 0 x1 0]
|
834
|
+
[ 0 x1 -x0 - x3 0 x1]
|
835
|
+
[ 0 x0 0 -x0 - x1 - x2 x0 + x3]
|
836
|
+
[ x0 0 0 x0 + x2 -x0 - x1 - x3]
|
837
|
+
|
838
|
+
sage: L.markov_chain_transition_matrix(action='tau') # needs sage.modules
|
839
|
+
[ -x0 - x2 x2 0 x0 0]
|
840
|
+
[ x2 -x0 - x1 - x2 x1 0 x0]
|
841
|
+
[ 0 x1 -x1 0 0]
|
842
|
+
[ x0 0 0 -x0 - x2 x2]
|
843
|
+
[ 0 x0 0 x2 -x0 - x2]
|
844
|
+
|
845
|
+
sage: L.markov_chain_transition_matrix(action='tau', labeling='source') # needs sage.modules
|
846
|
+
[ -x0 - x2 x3 0 x1 0]
|
847
|
+
[ x2 -x0 - x1 - x3 x3 0 x1]
|
848
|
+
[ 0 x1 -x3 0 0]
|
849
|
+
[ x0 0 0 -x1 - x2 x3]
|
850
|
+
[ 0 x0 0 x2 -x1 - x3]
|
851
|
+
|
852
|
+
.. SEEALSO:: :meth:`markov_chain_digraph`, :meth:`promotion`, :meth:`tau`
|
853
|
+
"""
|
854
|
+
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
|
855
|
+
from sage.matrix.constructor import matrix
|
856
|
+
L = sorted(self.list())
|
857
|
+
n = self.poset().cardinality()
|
858
|
+
R = PolynomialRing(QQ, 'x', n)
|
859
|
+
x = [R.gen(i) for i in range(n)]
|
860
|
+
l = self.cardinality()
|
861
|
+
M = {(i, j): 0 for i in range(l) for j in range(l)}
|
862
|
+
if labeling == 'source':
|
863
|
+
for i in range(l):
|
864
|
+
perm = [self.poset().unwrap(k) for k in L[i]]
|
865
|
+
for j in range(n - 1):
|
866
|
+
p = getattr(L[i], action)(j + 1)
|
867
|
+
M[(L.index(p), i)] += x[perm[j] - 1]
|
868
|
+
else:
|
869
|
+
for i in range(l):
|
870
|
+
for j in range(n - 1):
|
871
|
+
p = getattr(L[i], action)(j + 1)
|
872
|
+
M[(L.index(p), i)] += x[j]
|
873
|
+
for i in range(l):
|
874
|
+
M[(i, i)] += -sum(M[(j, i)] for j in range(l))
|
875
|
+
return matrix(l, l, lambda x, y: M[(x, y)])
|
876
|
+
|
877
|
+
def _element_constructor_(self, lst, check=True):
|
878
|
+
r"""
|
879
|
+
Constructor for elements of this class.
|
880
|
+
|
881
|
+
TESTS::
|
882
|
+
|
883
|
+
sage: P = Poset(([1,2,3,4], [[1,2],[1,4],[2,3]]))
|
884
|
+
sage: L = P.linear_extensions()
|
885
|
+
sage: x = L._element_constructor_([1,2,4,3]); x
|
886
|
+
[1, 2, 4, 3]
|
887
|
+
sage: x.parent() is L
|
888
|
+
True
|
889
|
+
|
890
|
+
sage: L._element_constructor_([4,3,2,1])
|
891
|
+
Traceback (most recent call last):
|
892
|
+
...
|
893
|
+
ValueError: [4, 3, 2, 1] is not a linear extension of Finite poset containing 4 elements
|
894
|
+
sage: L._element_constructor_([4,3,2,1],check=False)
|
895
|
+
[4, 3, 2, 1]
|
896
|
+
"""
|
897
|
+
if isinstance(lst, LinearExtensionOfPoset):
|
898
|
+
lst = list(lst)
|
899
|
+
if not isinstance(lst, (list, tuple)):
|
900
|
+
raise TypeError("input should be a list or tuple")
|
901
|
+
lst = [self._poset(e) for e in lst]
|
902
|
+
if self._is_facade:
|
903
|
+
return lst
|
904
|
+
return self.element_class(self, lst, check)
|
905
|
+
|
906
|
+
Element = LinearExtensionOfPoset
|
907
|
+
|
908
|
+
|
909
|
+
class LinearExtensionsOfPosetWithHooks(LinearExtensionsOfPoset):
|
910
|
+
r"""
|
911
|
+
Linear extensions such that the poset has well-defined
|
912
|
+
hook lengths (i.e., d-complete).
|
913
|
+
"""
|
914
|
+
|
915
|
+
def cardinality(self):
|
916
|
+
r"""
|
917
|
+
Count the number of linear extensions using a hook-length formula.
|
918
|
+
|
919
|
+
EXAMPLES::
|
920
|
+
|
921
|
+
sage: from sage.combinat.posets.poset_examples import Posets
|
922
|
+
sage: P = Posets.YoungDiagramPoset(Partition([3,2]), dual=True) # needs sage.combinat sage.modules
|
923
|
+
sage: P.linear_extensions().cardinality() # needs sage.combinat sage.modules
|
924
|
+
5
|
925
|
+
"""
|
926
|
+
num_elmts = self._poset.cardinality()
|
927
|
+
|
928
|
+
if num_elmts == 0:
|
929
|
+
return 1
|
930
|
+
|
931
|
+
hook_product = self._poset.hook_product()
|
932
|
+
return factorial(num_elmts) // hook_product
|
933
|
+
|
934
|
+
|
935
|
+
class LinearExtensionsOfForest(LinearExtensionsOfPoset):
|
936
|
+
r"""
|
937
|
+
Linear extensions such that the poset is a forest.
|
938
|
+
"""
|
939
|
+
|
940
|
+
def cardinality(self):
|
941
|
+
r"""
|
942
|
+
Use Atkinson's algorithm to compute the number of linear extensions.
|
943
|
+
|
944
|
+
EXAMPLES::
|
945
|
+
|
946
|
+
sage: from sage.combinat.posets.forest import ForestPoset
|
947
|
+
sage: from sage.combinat.posets.poset_examples import Posets
|
948
|
+
sage: P = Poset({0: [2], 1: [2], 2: [3, 4], 3: [], 4: []})
|
949
|
+
sage: P.linear_extensions().cardinality() # needs sage.modules
|
950
|
+
4
|
951
|
+
|
952
|
+
sage: Q = Poset({0: [1], 1: [2, 3], 2: [], 3: [], 4: [5, 6], 5: [], 6: []})
|
953
|
+
sage: Q.linear_extensions().cardinality() # needs sage.modules
|
954
|
+
140
|
955
|
+
"""
|
956
|
+
return sum(self.atkinson(self._elements[0]))
|
957
|
+
|
958
|
+
|
959
|
+
class LinearExtensionsOfMobile(LinearExtensionsOfPoset):
|
960
|
+
r"""
|
961
|
+
Linear extensions for a mobile poset.
|
962
|
+
"""
|
963
|
+
|
964
|
+
def cardinality(self):
|
965
|
+
r"""
|
966
|
+
Return the number of linear extensions by using the determinant
|
967
|
+
formula for counting linear extensions of mobiles.
|
968
|
+
|
969
|
+
EXAMPLES::
|
970
|
+
|
971
|
+
sage: from sage.combinat.posets.mobile import MobilePoset
|
972
|
+
sage: M = MobilePoset(DiGraph([[0,1,2,3,4,5,6,7,8], [(1,0),(3,0),(2,1),(2,3),(4,
|
973
|
+
....: 3), (5,4),(5,6),(7,4),(7,8)]]))
|
974
|
+
sage: M.linear_extensions().cardinality() # needs sage.modules
|
975
|
+
1098
|
976
|
+
|
977
|
+
sage: M1 = posets.RibbonPoset(6, [1,3])
|
978
|
+
sage: M1.linear_extensions().cardinality() # needs sage.modules
|
979
|
+
61
|
980
|
+
|
981
|
+
sage: P = posets.MobilePoset(posets.RibbonPoset(7, [1,3]), # needs sage.combinat sage.modules
|
982
|
+
....: {1: [posets.YoungDiagramPoset([3, 2], dual=True)],
|
983
|
+
....: 3: [posets.DoubleTailedDiamond(6)]},
|
984
|
+
....: anchor=(4, 2, posets.ChainPoset(6)))
|
985
|
+
sage: P.linear_extensions().cardinality() # needs sage.combinat sage.modules
|
986
|
+
361628701868606400
|
987
|
+
"""
|
988
|
+
import sage.combinat.posets.d_complete as dc
|
989
|
+
# Find folds
|
990
|
+
if self._poset._anchor:
|
991
|
+
anchor_index = self._poset._ribbon.index(self._poset._anchor[0])
|
992
|
+
else:
|
993
|
+
anchor_index = len(self._poset._ribbon)
|
994
|
+
|
995
|
+
folds_up = []
|
996
|
+
folds_down = []
|
997
|
+
|
998
|
+
for ind, r in enumerate(self._poset._ribbon[:-1]):
|
999
|
+
if ind < anchor_index and self._poset.is_greater_than(r, self._poset._ribbon[ind + 1]):
|
1000
|
+
folds_up.append((self._poset._ribbon[ind + 1], r))
|
1001
|
+
elif ind >= anchor_index and self._poset.is_less_than(r, self._poset._ribbon[ind + 1]):
|
1002
|
+
folds_down.append((r, self._poset._ribbon[ind + 1]))
|
1003
|
+
|
1004
|
+
if not folds_up and not folds_down:
|
1005
|
+
return dc.DCompletePoset(self._poset).linear_extensions().cardinality()
|
1006
|
+
|
1007
|
+
# Get ordered connected components
|
1008
|
+
cr = self._poset.cover_relations()
|
1009
|
+
foldless_cr = [tuple(c) for c in cr if tuple(c) not in folds_up and tuple(c) not in folds_down]
|
1010
|
+
|
1011
|
+
elmts = list(self._poset._elements)
|
1012
|
+
poset_components = DiGraph([elmts, foldless_cr])
|
1013
|
+
ordered_poset_components = [poset_components.connected_component_containing_vertex(f[1], sort=False)
|
1014
|
+
for f in folds_up]
|
1015
|
+
ordered_poset_components.extend(poset_components.connected_component_containing_vertex(f[0], sort=False)
|
1016
|
+
for f in folds_down)
|
1017
|
+
ordered_poset_components.append(poset_components.connected_component_containing_vertex(
|
1018
|
+
folds_down[-1][1] if folds_down else folds_up[-1][0], sort=False))
|
1019
|
+
|
1020
|
+
# Return determinant
|
1021
|
+
|
1022
|
+
# Consoludate the folds lists
|
1023
|
+
folds = folds_up
|
1024
|
+
folds.extend(folds_down)
|
1025
|
+
|
1026
|
+
mat = []
|
1027
|
+
for i in range(len(folds) + 1):
|
1028
|
+
mat_poset = dc.DCompletePoset(self._poset.subposet(ordered_poset_components[i]))
|
1029
|
+
row = [0] * (i - 1 if i - 1 > 0 else 0) + [1] * (1 if i >= 1 else 0)
|
1030
|
+
row.append(1 / mat_poset.hook_product())
|
1031
|
+
for j, f in enumerate(folds[i:]):
|
1032
|
+
next_poset = self._poset.subposet(ordered_poset_components[j + i + 1])
|
1033
|
+
mat_poset = dc.DCompletePoset(next_poset.slant_sum(mat_poset, f[0], f[1]))
|
1034
|
+
row.append(1 / mat_poset.hook_product())
|
1035
|
+
|
1036
|
+
mat.append(row)
|
1037
|
+
return matrix(QQ, mat).determinant() * factorial(self._poset.cardinality())
|