Partition shifting algebras - Combinatorics

Skip to content
Back to top
View this page
Edit this page

# Partition shifting algebras

This module contains families of operators that act on partitions or, more generally, integer sequences. In particular, this includes Young’s raising operators \(R_{ij}\), which act on integer sequences by adding \(1\) to the \(i\)-th entry and subtracting \(1\) to the \(j\)-th entry. A special case is acting on partitions.

AUTHORS:

- Matthew Lancellotti, George H. Seelinger (2018): initial version

class sage.combinat.partition_shifting_algebras.ShiftingOperatorAlgebra(base_ring=Univariate Polynomial Ring in t over Rational Field, prefix='S')

  Bases: `CombinatorialFreeModule`

  An algebra of shifting operators.

  Let \(R\) be a commutative ring. The algebra of shifting operators is isomorphic as an \(R\)-algebra to the Laurent polynomial ring \(R[x_1^\pm, x_2^\pm, x_3^\pm, \ldots]\). Moreover, the monomials of the shifting operator algebra act on any integer sequence \(\lambda = (\lambda_1, \lambda_2, \ldots, \lambda_{\ell})\) as follows. Let \(S\) be our algebra of shifting operators. Then, for any monomial \(s = x_1^{a_1}x_2^{a_2} \cdots x_r^{a_r} \in S\) where \(a_i \in \ZZ\) and \(r \geq \ell\), we get that \(s.\lambda = (\lambda_1 + a_1, \lambda_2 + a_2,\ldots,\lambda_r+a_r)\) where we pad \(\lambda\) with \(r-\ell\) zeros. In particular, we can recover Young’s raising operator, \(R_{ij}\), for \(i < j\), acting on partitions by having \(\frac{x_i}{x_j}\) act on a partition \(\lambda\).

  One can extend the action of these shifting operators to a basis of symmetric functions, but at the expense of no longer actually having a well-defined operator. Formally, to extend the action of the shifting operators on a symmetric function basis \(B = \{b_{\lambda}\}_{\lambda}\), we define an \(R\)-module homomorphism \(\phi : R[x_1^\pm, x_2^\pm, \ldots] \to B\). Then we compute \(x_1^{a_1} \cdots x_r^{a_r}.b_\lambda\) by first computing \((x_1^{a_1} \cdots x_r^{a_r})x_1^{\lambda_1} \cdots x_\ell^{\lambda_\ell}\) and then applying \(\phi\) to the result. For examples of what this looks like with specific bases, see below.

  This implementation is consistent with how many references work formally with raising operators. For instance, see exposition surrounding [BMPS2018] Equation (4.1).

  We follow the following convention for creating elements: `S(1, 0, -1, 2)` is the shifting operator that raises the first part by \(1\), lowers the third part by \(1\), and raises the fourth part by \(2\).

  In addition to acting on partitions (or any integer sequence), the shifting operators can also act on symmetric functions in a basis \(B\) when a conversion to \(B\) has been registered, preferably using `build_and_register_conversion()`.

  For a definition of raising operators, see [BMPS2018] Definition 2.1. See `ij()` to create operators using the notation in [BMPS2018].

  INPUT:

  - `base_ring` – (default: `QQ['t']`) the base ring

  - `prefix` – (default: `'S'`) the label for the shifting operators

  EXAMPLES:

  Sage

      sage: S = ShiftingOperatorAlgebra()

      sage: elm = S[1, -1, 2]; elm
      S(1, -1, 2)
      sage: elm([5, 4])
      [([6, 3, 2], 1)]

  Python

      >>> from sage.all import *
      >>> S = ShiftingOperatorAlgebra()

      >>> elm = S[Integer(1), -Integer(1), Integer(2)]; elm
      S(1, -1, 2)
      >>> elm([Integer(5), Integer(4)])
      [([6, 3, 2], 1)]

  The shifting operator monomials can act on a complete homogeneous symmetric function or a Schur function:

  Sage

      sage: s = SymmetricFunctions(QQ['t']).s()
      sage: h = SymmetricFunctions(QQ['t']).h()

      sage: elm(s[5, 4])
      s[6, 3, 2]
      sage: elm(h[5, 4])
      h[6, 3, 2]

      sage: S[1, -1](s[5, 4])
      s[6, 3]
      sage: S[1, -1](h[5, 4])
      h[6, 3]

  [Python]

      >>> from sage.all import *
      >>> s = SymmetricFunctions(QQ['t']).s()
      >>> h = SymmetricFunctions(QQ['t']).h()

      >>> elm(s[Integer(5), Integer(4)])
      s[6, 3, 2]
      >>> elm(h[Integer(5), Integer(4)])
      h[6, 3, 2]

      >>> S[Integer(1), -Integer(1)](s[Integer(5), Integer(4)])
      s[6, 3]
      >>> S[Integer(1), -Integer(1)](h[Integer(5), Integer(4)])
      h[6, 3]

  In fact, we can extend this action by linearity:

  Sage

      sage: elm = (1 - S[1,-1]) * (1 - S[4])
      sage: elm == S([]) - S([1, -1]) - S([4]) + S([5, -1])
      True
      sage: elm(s[2, 2, 1])
      s[2, 2, 1] - s[3, 1, 1] - s[6, 2, 1] + s[7, 1, 1]

      sage: elm = (1 - S[1,-1]) * (1 - S[0,1,-1])
      sage: elm == 1 - S[0,1,-1] - S[1,-1] + S[1,0,-1]
      True
      sage: elm(s[2, 2, 1])
      s[2, 2, 1] - s[3, 1, 1] + s[3, 2]

  Python

      >>> from sage.all import *
      >>> elm = (Integer(1) - S[Integer(1),-Integer(1)]) * (Integer(1) - S[Integer(4)])
      >>> elm == S([]) - S([Integer(1), -Integer(1)]) - S([Integer(4)]) + S([Integer(5), -Integer(1)])
      True
      >>> elm(s[Integer(2), Integer(2), Integer(1)])
      s[2, 2, 1] - s[3, 1, 1] - s[6, 2, 1] + s[7, 1, 1]

      >>> elm = (Integer(1) - S[Integer(1),-Integer(1)]) * (Integer(1) - S[Integer(0),Integer(1),-Integer(1)])
      >>> elm == Integer(1) - S[Integer(0),Integer(1),-Integer(1)] - S[Integer(1),-Integer(1)] + S[Integer(1),Integer(0),-Integer(1)]
      True
      >>> elm(s[Integer(2), Integer(2), Integer(1)])
      s[2, 2, 1] - s[3, 1, 1] + s[3, 2]

  The algebra also comes equipped with homomorphisms to various symmetric function bases; these homomorphisms are how the action of `S` on the specific symmetric function bases is implemented:

  Sage

      sage: elm = S([3,1,2]); elm
      S(3, 1, 2)
      sage: h(elm)
      h[3, 2, 1]
      sage: s(elm)
      0

  [Python]

      >>> from sage.all import *
      >>> elm = S([Integer(3),Integer(1),Integer(2)]); elm
      S(3, 1, 2)
      >>> h(elm)
      h[3, 2, 1]
      >>> s(elm)
      0

  However, not all homomorphisms are equivalent, so the action is basis dependent:

  Sage

      sage: elm = S([3,2,1]); elm
      S(3, 2, 1)
      sage: h(elm)
      h[3, 2, 1]
      sage: s(elm)
      s[3, 2, 1]
      sage: s(elm) == s(h(elm))
      False

  Python

      >>> from sage.all import *
      >>> elm = S([Integer(3),Integer(2),Integer(1)]); elm
      S(3, 2, 1)
      >>> h(elm)
      h[3, 2, 1]
      >>> s(elm)
      s[3, 2, 1]
      >>> s(elm) == s(h(elm))
      False

  We can also use raising operators to implement the Jacobi-Trudi identity:

  Sage

      sage: op = (1-S[(1,-1)]) * (1-S[(1,0,-1)]) * (1-S[(0,1,-1)])
      sage: s(op(h[3,2,1]))
      s[3, 2, 1]

  [Python]

      >>> from sage.all import *
      >>> op = (Integer(1)-S[(Integer(1),-Integer(1))]) * (Integer(1)-S[(Integer(1),Integer(0),-Integer(1))]) * (Integer(1)-S[(Integer(0),Integer(1),-Integer(1))])
      >>> s(op(h[Integer(3),Integer(2),Integer(1)]))
      s[3, 2, 1]

  class Element

    Bases: `IndexedFreeModuleElement`

    An element of a `ShiftingOperatorAlgebra`.

  build_and_register_conversion(support_map, codomain)

    Build a module homomorphism from a map sending integer sequences to `codomain` and registers the result into Sage’s conversion model.

    The intended use is to define a morphism from `self` to a basis \(B\) of symmetric functions that will be used by `ShiftingOperatorAlgebra` to define the action of the operators on \(B\).

    Note

    The actions on the complete homogeneous symmetric functions and on the Schur functions by morphisms are already registered.

    Warning

    Because `ShiftingOperatorAlgebra` inherits from `UniqueRepresentation`, once you register a conversion, this will apply to all instances of `ShiftingOperatorAlgebra` over the same base ring with the same prefix.

    INPUT:

    - `support_map` – a map from integer sequences to `codomain`

    - `codomain` – the codomain of `support_map`, usually a basis of symmetric functions

    EXAMPLES:

    Sage

        sage: S = ShiftingOperatorAlgebra(QQ)
        sage: sym = SymmetricFunctions(QQ)
        sage: p = sym.p()
        sage: zero_map = lambda part: p.zero()
        sage: S.build_and_register_conversion(zero_map, p)
        sage: p(2*S([1,0,-1]) + S([2,1,0]) - 3*S([0,1,3]))
        0
        sage: op = S((1, -1))
        sage: op(2*p[4,3] + 5*p[2,2] + 7*p[2]) == p.zero()
        True

    Python

        >>> from sage.all import *
        >>> S = ShiftingOperatorAlgebra(QQ)
        >>> sym = SymmetricFunctions(QQ)
        >>> p = sym.p()
        >>> zero_map = lambda part: p.zero()
        >>> S.build_and_register_conversion(zero_map, p)
        >>> p(Integer(2)*S([Integer(1),Integer(0),-Integer(1)]) + S([Integer(2),Integer(1),Integer(0)]) - Integer(3)*S([Integer(0),Integer(1),Integer(3)]))
        0
        >>> op = S((Integer(1), -Integer(1)))
        >>> op(Integer(2)*p[Integer(4),Integer(3)] + Integer(5)*p[Integer(2),Integer(2)] + Integer(7)*p[Integer(2)]) == p.zero()
        True

    For a more illustrative example, we can implement a simple (but not mathematically justified!) conversion on the monomial basis:

    Sage

        sage: S = ShiftingOperatorAlgebra(QQ)
        sage: sym = SymmetricFunctions(QQ)
        sage: m = sym.m()
        sage: def supp_map(gamma):
        ....:     gsort = sorted(gamma, reverse=True)
        ....:     return m(gsort) if gsort in Partitions() else m.zero()
        sage: S.build_and_register_conversion(supp_map, m)
        sage: op = S.ij(0, 1)
        sage: op(2*m[4,3] + 5*m[2,2] + 7*m[2]) == 2*m[5, 2] + 5*m[3, 1]
        True

    [Python]

        >>> from sage.all import *
        >>> S = ShiftingOperatorAlgebra(QQ)
        >>> sym = SymmetricFunctions(QQ)
        >>> m = sym.m()
        >>> def supp_map(gamma):
        ...     gsort = sorted(gamma, reverse=True)
        ...     return m(gsort) if gsort in Partitions() else m.zero()
        >>> S.build_and_register_conversion(supp_map, m)
        >>> op = S.ij(Integer(0), Integer(1))
        >>> op(Integer(2)*m[Integer(4),Integer(3)] + Integer(5)*m[Integer(2),Integer(2)] + Integer(7)*m[Integer(2)]) == Integer(2)*m[Integer(5), Integer(2)] + Integer(5)*m[Integer(3), Integer(1)]
        True

  ij(i, j)

    Return the raising operator \(R_{ij}\) as notated in [BMPS2018] Definition 2.1.

    Shorthand element constructor that allows you to create raising operators using the familiar \(R_{ij}\) notation found in [BMPS2018] Definition 2.1, with the exception that indices here are 0-based, not 1-based.

    EXAMPLES:

    Create the raising operator which raises part 0 and lowers part 2 (indices are 0-based):

    Sage

        sage: R = ShiftingOperatorAlgebra()
        sage: R.ij(0, 2)
        S(1, 0, -1)

    Python

        >>> from sage.all import *
        >>> R = ShiftingOperatorAlgebra()
        >>> R.ij(Integer(0), Integer(2))
        S(1, 0, -1)

  one_basis()

    Return the index of the basis element for \(1\).

    EXAMPLES:

    Sage

        sage: S = ShiftingOperatorAlgebra()
        sage: S.one_basis()
        ()

    Python

        >>> from sage.all import *
        >>> S = ShiftingOperatorAlgebra()
        >>> S.one_basis()
        ()

  product_on_basis(x, y)

    Return the product of basis elements indexed by `x` and `y`.

    EXAMPLES:

    Sage

        sage: S = ShiftingOperatorAlgebra()
        sage: S.product_on_basis((0, 5, 2), (3, 2, -2, 5))
        S(3, 7, 0, 5)
        sage: S.product_on_basis((1, -2, 0, 3, -6), (-1, 2, 2))
        S(0, 0, 2, 3, -6)
        sage: S.product_on_basis((1, -2, -2), (-1, 2, 2))
        S()

    Python

        >>> from sage.all import *
        >>> S = ShiftingOperatorAlgebra()
        >>> S.product_on_basis((Integer(0), Integer(5), Integer(2)), (Integer(3), Integer(2), -Integer(2), Integer(5)))
        S(3, 7, 0, 5)
        >>> S.product_on_basis((Integer(1), -Integer(2), Integer(0), Integer(3), -Integer(6)), (-Integer(1), Integer(2), Integer(2)))
        S(0, 0, 2, 3, -6)
        >>> S.product_on_basis((Integer(1), -Integer(2), -Integer(2)), (-Integer(1), Integer(2), Integer(2)))
        S()

class sage.combinat.partition_shifting_algebras.ShiftingSequenceSpace

  Bases: `Singleton`, `Parent`

  A helper for `ShiftingOperatorAlgebra` that contains all tuples with entries in \(\ZZ\) of finite support with no trailing \(0\)’s.

  EXAMPLES:

  Sage

      sage: from sage.combinat.partition_shifting_algebras import ShiftingSequenceSpace
      sage: S = ShiftingSequenceSpace()
      sage: (1, -1) in S
      True
      sage: (1, -1, 0, 9) in S
      True
      sage: [1, -1] in S
      False
      sage: (0.5, 1) in S
      False

  Python

      >>> from sage.all import *
      >>> from sage.combinat.partition_shifting_algebras import ShiftingSequenceSpace
      >>> S = ShiftingSequenceSpace()
      >>> (Integer(1), -Integer(1)) in S
      True
      >>> (Integer(1), -Integer(1), Integer(0), Integer(9)) in S
      True
      >>> [Integer(1), -Integer(1)] in S
      False
      >>> (RealNumber('0.5'), Integer(1)) in S
      False

  check(seq)

    Verify that `seq` is a valid shifting sequence.

    If it is not, raise a `ValueError`.

    EXAMPLES:

    Sage

        sage: from sage.combinat.partition_shifting_algebras import ShiftingSequenceSpace
        sage: S = ShiftingSequenceSpace()
        sage: S.check((1, -1))
        sage: S.check((1, -1, 0, 9))
        sage: S.check([1, -1])
        Traceback (most recent call last):
        ...
        ValueError: invalid index [1, -1]
        sage: S.check((0.5, 1))
        Traceback (most recent call last):
        ...
        ValueError: invalid index (0.500000000000000, 1)

    Python

        >>> from sage.all import *
        >>> from sage.combinat.partition_shifting_algebras import ShiftingSequenceSpace
        >>> S = ShiftingSequenceSpace()
        >>> S.check((Integer(1), -Integer(1)))
        >>> S.check((Integer(1), -Integer(1), Integer(0), Integer(9)))
        >>> S.check([Integer(1), -Integer(1)])
        Traceback (most recent call last):
        ...
        ValueError: invalid index [1, -1]
        >>> S.check((RealNumber('0.5'), Integer(1)))
        Traceback (most recent call last):
        ...
        ValueError: invalid index (0.500000000000000, 1)