Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement Specht modules for diagrams #35036

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/doc/en/reference/combinat/module_list.rst
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,7 @@ Comprehensive Module List
sage/combinat/species/structure
sage/combinat/species/subset_species
sage/combinat/species/sum_species
sage/combinat/specht_module
sage/combinat/subset
sage/combinat/subsets_hereditary
sage/combinat/subsets_pairwise
Expand Down
1 change: 1 addition & 0 deletions src/sage/combinat/algebraic_combinatorics.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
- :ref:`sage.combinat.cluster_algebra_quiver.all`
- :class:`~sage.combinat.kazhdan_lusztig.KazhdanLusztigPolynomial`
- :class:`~sage.combinat.symmetric_group_representations.SymmetricGroupRepresentation`
- :class:`~sage.combinat.specht_module.SpechtModule`
- :ref:`sage.combinat.yang_baxter_graph`
- :ref:`sage.combinat.hall_polynomial`
- :ref:`sage.combinat.key_polynomial`
Expand Down
42 changes: 42 additions & 0 deletions src/sage/combinat/composition.py
Original file line number Diff line number Diff line change
Expand Up @@ -1386,6 +1386,48 @@ def count(self, n):
"""
return sum(i == n for i in self)

def specht_module(self, base_ring=None):
r"""
Return the Specht module corresponding to ``self``.

EXAMPLES::

sage: SM = Composition([1,2,2]).specht_module(QQ)
sage: SM
Specht module of [(0, 0), (1, 0), (1, 1), (2, 0), (2, 1)] over Rational Field
sage: s = SymmetricFunctions(QQ).s()
sage: s(SM.frobenius_image())
s[2, 2, 1]
"""
from sage.combinat.specht_module import SpechtModule
from sage.combinat.symmetric_group_algebra import SymmetricGroupAlgebra
if base_ring is None:
from sage.rings.rational_field import QQ
base_ring = QQ
R = SymmetricGroupAlgebra(base_ring, sum(self))
cells = []
for i, row in enumerate(self):
for j in range(row):
cells.append((i, j))
return SpechtModule(R, cells)

def specht_module_dimension(self, base_ring=None):
r"""
Return the dimension of the Specht module corresponding to ``self``.

INPUT:

- ``base_ring`` -- (default: `\QQ`) the base ring

EXAMPLES::

sage: Composition([1,2,2]).specht_module_dimension()
5
sage: Composition([1,2,2]).specht_module_dimension(GF(2))
5
"""
from sage.combinat.specht_module import specht_module_rank
return specht_module_rank(self, base_ring)

Sequence.register(Composition)
##############################################################
Expand Down
40 changes: 40 additions & 0 deletions src/sage/combinat/diagram.py
Original file line number Diff line number Diff line change
Expand Up @@ -490,6 +490,46 @@ def check(self):
if not all(all(list(i in NN for i in c)) for c in self._cells):
raise ValueError("Diagrams must be indexed by non-negative integers")

def specht_module(self, base_ring=None):
r"""
Return the Specht module corresponding to ``self``.

EXAMPLES::

sage: from sage.combinat.diagram import Diagram
sage: D = Diagram([(0,0), (1,1), (2,2), (2,3)])
sage: SM = D.specht_module(QQ)
sage: s = SymmetricFunctions(QQ).s()
sage: s(SM.frobenius_image())
s[2, 1, 1] + s[2, 2] + 2*s[3, 1] + s[4]
"""
from sage.combinat.specht_module import SpechtModule
from sage.combinat.symmetric_group_algebra import SymmetricGroupAlgebra
if base_ring is None:
from sage.rings.rational_field import QQ
base_ring = QQ
R = SymmetricGroupAlgebra(base_ring, len(self))
return SpechtModule(R, self)

def specht_module_dimension(self, base_ring=None):
r"""
Return the dimension of the Specht module corresponding to ``self``.

INPUT:

- ``base_ring`` -- (default: `\QQ`) the base ring

EXAMPLES::

sage: from sage.combinat.diagram import Diagram
sage: D = Diagram([(0,0), (1,1), (2,2), (2,3)])
sage: D.specht_module_dimension()
12
sage: D.specht_module(QQ).dimension()
12
"""
from sage.combinat.specht_module import specht_module_rank
return specht_module_rank(self, base_ring)

class Diagrams(UniqueRepresentation, Parent):
r"""
Expand Down
39 changes: 39 additions & 0 deletions src/sage/combinat/integer_vector.py
Original file line number Diff line number Diff line change
Expand Up @@ -511,6 +511,45 @@ def trim(self):
v = v[:-1]
return P.element_class(P, v, check=False)

def specht_module(self, base_ring=None):
r"""
Return the Specht module corresponding to ``self``.

EXAMPLES::

sage: SM = IntegerVectors()([2,0,1,0,2]).specht_module(QQ)
sage: SM
Specht module of [(0, 0), (0, 1), (2, 0), (4, 0), (4, 1)] over Rational Field
sage: s = SymmetricFunctions(QQ).s()
sage: s(SM.frobenius_image())
s[2, 2, 1]
"""
from sage.combinat.specht_module import SpechtModule
from sage.combinat.symmetric_group_algebra import SymmetricGroupAlgebra
if base_ring is None:
from sage.rings.rational_field import QQ
base_ring = QQ
R = SymmetricGroupAlgebra(base_ring, sum(self))
return SpechtModule(R, self)

def specht_module_dimension(self, base_ring=None):
r"""
Return the dimension of the Specht module corresponding to ``self``.

INPUT:

- ``BR`` -- (default: `\QQ`) the base ring

EXAMPLES::

sage: IntegerVectors()([2,0,1,0,2]).specht_module_dimension()
5
sage: IntegerVectors()([2,0,1,0,2]).specht_module_dimension(GF(2))
5
"""
from sage.combinat.specht_module import specht_module_rank
return specht_module_rank(self, base_ring)


class IntegerVectors(Parent, metaclass=ClasscallMetaclass):
"""
Expand Down
46 changes: 46 additions & 0 deletions src/sage/combinat/partition.py
Original file line number Diff line number Diff line change
Expand Up @@ -5483,6 +5483,52 @@ def coloring(i):
immutable=True, multiedges=True)
return self.dual_equivalence_graph(directed, coloring)

def specht_module(self, base_ring=None):
r"""
Return the Specht module corresponding to ``self``.

EXAMPLES::

sage: SM = Partition([2,2,1]).specht_module(QQ)
sage: SM
Specht module of [(0, 0), (0, 1), (1, 0), (1, 1), (2, 0)] over Rational Field
sage: s = SymmetricFunctions(QQ).s()
sage: s(SM.frobenius_image())
s[2, 2, 1]
"""
from sage.combinat.specht_module import SpechtModule
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe factor out a function specht_module_builder that takes a ring, a size and cells ? Instead of doing these double imports everywhere ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't really see the benefit. To me, it adds more indirection and complexity to save on just doing one import at each point of the code instead of two (as the second import is still done). To me, it is equivalent to having

class Bar:
    def __init__(self, x):
        self._x = x

def foo(x):
    from above import Bar
    return Bar(x)

which I would want to just call Bar(x) within my code.

from sage.combinat.symmetric_group_algebra import SymmetricGroupAlgebra
if base_ring is None:
from sage.rings.rational_field import QQ
base_ring = QQ
R = SymmetricGroupAlgebra(base_ring, sum(self))
return SpechtModule(R, self)

def specht_module_dimension(self, base_ring=None):
r"""
Return the dimension of the Specht module corresponding to ``self``.

This is equal to the number of standard tableaux of shape ``self`` when
over a field of characteristic `0`.

INPUT:

- ``BR`` -- (default: `\QQ`) the base ring

EXAMPLES::

sage: Partition([2,2,1]).specht_module_dimension()
5
sage: Partition([2,2,1]).specht_module_dimension(GF(2))
5
"""
from sage.categories.fields import Fields
if base_ring is None or (base_ring in Fields() and base_ring.characteristic() == 0):
from sage.combinat.tableau import StandardTableaux
return StandardTableaux(self).cardinality()
from sage.combinat.specht_module import specht_module_rank
return specht_module_rank(self, base_ring)


##############
# Partitions #
Expand Down
34 changes: 28 additions & 6 deletions src/sage/combinat/permutation.py
Original file line number Diff line number Diff line change
Expand Up @@ -269,8 +269,9 @@
from sage.structure.global_options import GlobalOptions
from sage.structure.list_clone import ClonableArray
from sage.structure.parent import Parent
from sage.structure.element import Element, get_coercion_model
from sage.structure.unique_representation import UniqueRepresentation

import operator

class Permutation(CombinatorialElement):
r"""
Expand Down Expand Up @@ -1242,7 +1243,23 @@ def to_alternating_sign_matrix(self):
from sage.combinat.alternating_sign_matrix import AlternatingSignMatrix
return AlternatingSignMatrix(self.to_matrix().rows())

def __mul__(self, rp) -> Permutation:
def __mul__(self, rp):
"""
TESTS::

sage: SGA = SymmetricGroupAlgebra(QQ, 3)
sage: SM = SGA.specht_module([2,1])
sage: p213 = Permutations(3)([2,1,3])
sage: p213 * SGA.an_element()
3*[1, 2, 3] + [1, 3, 2] + [2, 1, 3] + 2*[3, 1, 2]
sage: p213 * SM.an_element()
2*B[0] - 4*B[1]
"""
if not isinstance(rp, Permutation) and isinstance(rp, Element):
return get_coercion_model().bin_op(self, rp, operator.mul)
return Permutation._mul_(self, rp)

def _mul_(self, rp) -> Permutation:
"""
TESTS::

Expand All @@ -1261,8 +1278,6 @@ def __mul__(self, rp) -> Permutation:
else:
return self._left_to_right_multiply_on_left(rp)

_mul_ = __mul__ # For ``prod()``

def __rmul__(self, lp) -> Permutation:
"""
TESTS::
Expand All @@ -1276,7 +1291,13 @@ def __rmul__(self, lp) -> Permutation:
sage: p213*p312
[3, 2, 1]
sage: Permutations.options.mult='l2r'

sage: SGA = SymmetricGroupAlgebra(QQ, 3)
sage: SGA.an_element() * Permutations(3)(p213)
3*[1, 2, 3] + [2, 1, 3] + 2*[2, 3, 1] + [3, 2, 1]
"""
if not isinstance(lp, Permutation) and isinstance(lp, Element):
return get_coercion_model().bin_op(lp, self, operator.mul)
if self.parent().options.mult == 'l2r':
return self._left_to_right_multiply_on_left(lp)
else:
Expand Down Expand Up @@ -7328,9 +7349,10 @@ def __mul__(self, other):
"""
if not isinstance(other, StandardPermutations_n.Element):
return Permutation.__mul__(self, other)
if other.parent() is not self.parent():
P = self.parent()
if other.parent() is not P:
# They have different parents (but both are (like) Permutations of n)
mul_order = self.parent().options.mult
mul_order = P.options.mult
if mul_order == 'l2r':
p = right_action_product(self._list, other._list)
elif mul_order == 'r2l':
Expand Down
57 changes: 57 additions & 0 deletions src/sage/combinat/skew_partition.py
Original file line number Diff line number Diff line change
Expand Up @@ -1275,6 +1275,63 @@ def outside_corners(self):
"""
return self.outer().outside_corners()

def specht_module(self, base_ring=None):
r"""
Return the Specht module corresponding to ``self``.

EXAMPLES::

sage: mu = SkewPartition([[3,2,1], [2]])
sage: SM = mu.specht_module(QQ)
sage: s = SymmetricFunctions(QQ).s()
sage: s(SM.frobenius_image())
s[2, 1, 1] + s[2, 2] + s[3, 1]

We verify that the Frobenius image is the corresponding
skew Schur function::

sage: s[3,2,1].skew_by(s[2])
s[2, 1, 1] + s[2, 2] + s[3, 1]

::

sage: mu = SkewPartition([[4,2,1], [2,1]])
sage: SM = mu.specht_module(QQ)
sage: s(SM.frobenius_image())
s[2, 1, 1] + s[2, 2] + 2*s[3, 1] + s[4]
sage: s(mu)
s[2, 1, 1] + s[2, 2] + 2*s[3, 1] + s[4]
"""
from sage.combinat.specht_module import SpechtModule
from sage.combinat.symmetric_group_algebra import SymmetricGroupAlgebra
if base_ring is None:
from sage.rings.rational_field import QQ
base_ring = QQ
R = SymmetricGroupAlgebra(base_ring, self.size())
return SpechtModule(R, self.cells())

def specht_module_dimension(self, base_ring=None):
r"""
Return the dimension of the Specht module corresponding to ``self``.

This is equal to the number of standard (skew) tableaux of
shape ``self``.

EXAMPLES::

sage: mu = SkewPartition([[3,2,1], [2]])
sage: mu.specht_module_dimension()
8
sage: mu.specht_module_dimension(GF(2))
8
"""
from sage.categories.fields import Fields
if base_ring is None or (base_ring in Fields() and base_ring.characteristic() == 0):
from sage.combinat.skew_tableau import StandardSkewTableaux
return StandardSkewTableaux(self).cardinality()
from sage.combinat.specht_module import specht_module_rank
return specht_module_rank(self, base_ring)


def row_lengths_aux(skp):
"""
Expand Down
Loading