diff --git a/src/sage/categories/category_with_axiom.py b/src/sage/categories/category_with_axiom.py index 6d7fa75fbf6..2c76e30c529 100644 --- a/src/sage/categories/category_with_axiom.py +++ b/src/sage/categories/category_with_axiom.py @@ -1691,7 +1691,7 @@ class ``Sets.Finite``), or in a separate file (typically in a class "Inverse", "Unital", "Division", "NoZeroDivisors", "Cellular", "AdditiveCommutative", "AdditiveAssociative", "AdditiveInverse", "AdditiveUnital", "Extremal", "Trim", "Semidistributive", "CongruenceUniform", - "Distributive", "Stone", + "Graded", "Distributive", "Stone", "Endset", "Pointed", "Stratified" diff --git a/src/sage/categories/finite_complex_reflection_groups.py b/src/sage/categories/finite_complex_reflection_groups.py index 7bb9fda5a81..dad8ffa941f 100644 --- a/src/sage/categories/finite_complex_reflection_groups.py +++ b/src/sage/categories/finite_complex_reflection_groups.py @@ -17,6 +17,7 @@ from sage.misc.cachefunc import cached_method from sage.categories.category_with_axiom import CategoryWithAxiom from sage.categories.coxeter_groups import CoxeterGroups +from sage.categories.finite_lattice_posets import FiniteLatticePosets class FiniteComplexReflectionGroups(CategoryWithAxiom): @@ -866,7 +867,7 @@ def absolute_order_ideal(self, gens=None, 14 sage: W = CoxeterGroup(['A', 2]) # needs sage.combinat sage.groups - sage: for (w, l) in W.absolute_order_ideal(return_lengths=True): # needs sage.combinat sage.groups + sage: for w, l in W.absolute_order_ideal(return_lengths=True): # needs sage.combinat sage.groups ....: print(w.reduced_word(), l) [1, 2] 2 [1, 2, 1] 1 @@ -967,7 +968,7 @@ def noncrossing_partition_lattice(self, c=None, L=None, L = [(pi, pi.reflection_length()) for pi in L] rels = [] ref_lens = dict(L) - for (pi, l) in L: + for pi, l in L: for t in R: tau = pi * t if tau in ref_lens and l + 1 == ref_lens[tau]: @@ -975,7 +976,8 @@ def noncrossing_partition_lattice(self, c=None, L=None, P = Poset(([], rels), cover_relations=True, facade=True) if P.is_lattice(): - P = LatticePoset(P) + P = LatticePoset(P, + category=FiniteLatticePosets().Graded()) return P def generalized_noncrossing_partitions(self, m, c=None, positive=False): diff --git a/src/sage/categories/finite_coxeter_groups.py b/src/sage/categories/finite_coxeter_groups.py index 9abc05fde03..654a21604df 100644 --- a/src/sage/categories/finite_coxeter_groups.py +++ b/src/sage/categories/finite_coxeter_groups.py @@ -17,6 +17,7 @@ from sage.misc.lazy_attribute import lazy_attribute from sage.categories.category_with_axiom import CategoryWithAxiom from sage.categories.coxeter_groups import CoxeterGroups +from sage.categories.finite_lattice_posets import FiniteLatticePosets class FiniteCoxeterGroups(CategoryWithAxiom): @@ -483,8 +484,9 @@ def weak_poset(self, side='right', facade=False): return Poset((self, covers), cover_relations=True, facade=facade) covers = tuple([u, v] for u in self for v in u.upper_covers(side=side)) + cat = FiniteLatticePosets().Graded() return LatticePoset((self, covers), cover_relations=True, - facade=facade) + facade=facade, category=cat) weak_lattice = weak_poset diff --git a/src/sage/categories/lattice_posets.py b/src/sage/categories/lattice_posets.py index 6f094efdc3b..a1cffd38af1 100644 --- a/src/sage/categories/lattice_posets.py +++ b/src/sage/categories/lattice_posets.py @@ -91,6 +91,18 @@ def join(self, x, y): """ class SubcategoryMethods: + def Graded(self): + r""" + A lattice is graded if all maximal chains have the same length. + + EXAMPLES:: + + sage: P = posets.DivisorLattice(24) + sage: P in FiniteLatticePosets().Graded() + True + """ + return self._with_axiom("Graded") + def Stone(self): r""" A Stone lattice `(L, \vee, \wedge)` is a pseudo-complemented @@ -115,6 +127,8 @@ def Distributive(self): From duality in lattices, it follows that then also join distributes over meet. + A distributive lattice is always graded. + See :wikipedia:`Distributive lattice`. EXAMPLES:: @@ -247,6 +261,18 @@ def extra_super_categories(self): """ return [LatticePosets().Extremal()] + class SubcategoryMethods: + def Graded(self): + r""" + A trim and graded lattice is distributive. + + EXAMPLES:: + + sage: FiniteLatticePosets().Trim().Graded() + Category of finite distributive lattice posets + """ + return self._with_axiom("Distributive") + class ParentMethods: def is_trim(self): """ @@ -350,7 +376,8 @@ def extra_super_categories(self): Category of distributive lattice posets] """ return [LatticePosets().Trim(), - LatticePosets().CongruenceUniform()] + LatticePosets().CongruenceUniform(), + LatticePosets().Graded()] class ParentMethods: def is_distributive(self): @@ -404,3 +431,28 @@ def is_stone(self): True """ return True + + class Graded(CategoryWithAxiom): + """ + The category of graded lattices. + + EXAMPLES:: + + sage: cat = FiniteLatticePosets().Graded(); cat + Category of finite graded lattice posets + + sage: cat.super_categories() + [Category of finite lattice posets, + Category of graded lattice posets] + """ + class ParentMethods: + def is_graded(self): + """ + Return whether ``self`` is a graded lattice. + + EXAMPLES:: + + sage: posets.DivisorLattice(12).is_graded() + True + """ + return True diff --git a/src/sage/combinat/alternating_sign_matrix.py b/src/sage/combinat/alternating_sign_matrix.py index 20b20056cc1..925ff63839e 100644 --- a/src/sage/combinat/alternating_sign_matrix.py +++ b/src/sage/combinat/alternating_sign_matrix.py @@ -41,6 +41,7 @@ from sage.structure.element import Element from sage.structure.richcmp import richcmp from sage.categories.finite_enumerated_sets import FiniteEnumeratedSets +from sage.categories.finite_lattice_posets import FiniteLatticePosets from sage.matrix.matrix_space import MatrixSpace from sage.matrix.constructor import matrix from sage.modules.free_module_element import zero_vector @@ -60,8 +61,8 @@ def _inplace_height_function_gyration(hf): k = hf.nrows() - 1 - for i in range(1,k): - for j in range(1,k): + for i in range(1, k): + for j in range(1, k): if (i+j) % 2 == 0 \ and hf[i-1,j] == hf[i+1,j] == hf[i,j+1] == hf[i,j-1]: if hf[i,j] < hf[i+1,j]: @@ -800,11 +801,11 @@ def ASM_compatible_smaller(self): N = len(output) for c in range(N): d = copy.copy(output[c]) - output[c][sign[b][0],sign[b][1]] = -output[c][sign[b][0], sign[b][1]]+1 - d[sign[b][0],sign[b][1]] = -d[sign[b][0], sign[b][1]]-3 + output[c][sign[b][0], sign[b][1]] = -output[c][sign[b][0], sign[b][1]]+1 + d[sign[b][0], sign[b][1]] = -d[sign[b][0], sign[b][1]]-3 output.append(d) for k in range(len(output)): - output[k] = M.from_height_function((output[k]-matrix.ones(n,n))/2) + output[k] = M.from_height_function((output[k]-matrix.ones(n, n))/2) return output @combinatorial_map(name='to Dyck word') @@ -1043,10 +1044,10 @@ class AlternatingSignMatrices(UniqueRepresentation, Parent): sage: L Finite lattice containing 7 elements sage: L.category() - Category of facade finite enumerated lattice posets + Category of facade finite enumerated distributive lattice posets """ - def __init__(self, n): + def __init__(self, n) -> None: r""" Initialize ``self``. @@ -1059,7 +1060,7 @@ def __init__(self, n): self._matrix_space = MatrixSpace(ZZ, n) Parent.__init__(self, category=FiniteEnumeratedSets()) - def _repr_(self): + def _repr_(self) -> str: r""" Return a string representation of ``self``. @@ -1084,7 +1085,7 @@ def _repr_option(self, key): """ return self._matrix_space._repr_option(key) - def __contains__(self, asm): + def __contains__(self, asm) -> bool: """ Check if ``asm`` is in ``self``. @@ -1559,8 +1560,9 @@ def lattice(self): sage: L Finite lattice containing 7 elements """ + cat = FiniteLatticePosets().Distributive() return LatticePoset(self._lattice_initializer(), cover_relations=True, - check=False) + check=False, category=cat) @cached_method def gyration_orbits(self): diff --git a/src/sage/combinat/posets/bubble_shuffle.py b/src/sage/combinat/posets/bubble_shuffle.py index 92dd66c72fa..dbe57eeac7f 100644 --- a/src/sage/combinat/posets/bubble_shuffle.py +++ b/src/sage/combinat/posets/bubble_shuffle.py @@ -201,7 +201,8 @@ def ShufflePoset(m, n) -> LatticePoset: dg = DiGraph([(x, y) for x in bubbles for y in bubble_coverings(m, n, x, transpose=False)]) # here we just have the cover relations - return LatticePoset(dg, cover_relations=True) + cat = FiniteLatticePosets().Graded() + return LatticePoset(dg, cover_relations=True, check=False, category=cat) def noncrossing_bipartite_complex(m, n): diff --git a/src/sage/combinat/posets/lattices.py b/src/sage/combinat/posets/lattices.py index e06fb09627f..d891b15e9c5 100644 --- a/src/sage/combinat/posets/lattices.py +++ b/src/sage/combinat/posets/lattices.py @@ -156,7 +156,7 @@ from sage.combinat.posets.hasse_diagram import LatticeError -#################################################################################### +############################################################################ def MeetSemilattice(data=None, *args, **options): r""" @@ -481,7 +481,7 @@ def pseudocomplement(self, element): return None return self._vertex_to_element(e) -#################################################################################### +############################################################################ def JoinSemilattice(data=None, *args, **options): diff --git a/src/sage/combinat/posets/poset_examples.py b/src/sage/combinat/posets/poset_examples.py index d8bb880d360..d9b77e60ea6 100644 --- a/src/sage/combinat/posets/poset_examples.py +++ b/src/sage/combinat/posets/poset_examples.py @@ -440,7 +440,7 @@ def DiamondPoset(n, facade=None): c[0] = list(range(1, n - 1)) c[n - 1] = [] D = DiGraph({v: c[v] for v in range(n)}, format='dict_of_lists') - cat = FiniteLatticePosets() + cat = FiniteLatticePosets().Graded() if n <= 4: cat = cat.Stone() return FiniteLatticePoset(hasse_diagram=D, category=cat, @@ -1182,14 +1182,14 @@ def SymmetricGroupWeakOrderPoset(n, labels='permutations', side='right'): EXAMPLES:: sage: posets.SymmetricGroupWeakOrderPoset(4) - Finite poset containing 24 elements + Finite lattice containing 24 elements """ if n < 10 and labels == "permutations": - element_labels = dict([[s, "".join(map(str, s))] - for s in Permutations(n)]) + element_labels = {s: "".join(map(str, s)) + for s in Permutations(n)} if n < 10 and labels == "reduced_words": - element_labels = dict([[s, "".join(map(str, s.reduced_word_lexmin()))] - for s in Permutations(n)]) + element_labels = {s: "".join(map(str, s.reduced_word_lexmin())) + for s in Permutations(n)} if side == "left": def weak_covers(s): @@ -1200,6 +1200,7 @@ def weak_covers(s): return [v for v in s.bruhat_succ() if s.length() + (s.inverse().right_action_product(v)).length() == v.length()] else: + def weak_covers(s): r""" Nested function for computing the covers of elements in the @@ -1207,8 +1208,11 @@ def weak_covers(s): """ return [v for v in s.bruhat_succ() if s.length() + (s.inverse().left_action_product(v)).length() == v.length()] - return Poset(dict([[s, weak_covers(s)] for s in Permutations(n)]), - element_labels) + return LatticePoset( + {s: weak_covers(s) for s in Permutations(n)}, + element_labels, check=False, + category=FiniteLatticePosets().Graded().Semidistributive() + ) @staticmethod def TetrahedralPoset(n, *colors, **labels): @@ -2125,7 +2129,7 @@ def _random_distributive_lattice(n): return D -def _random_stone_lattice(n): +def _random_stone_lattice(n) -> DiGraph: """ Return a random Stone lattice on `n` elements.