# Symmetric functions, with their multiple realizations#

class sage.combinat.sf.sf.SymmetricFunctions(R)#

The abstract algebra of commutative symmetric functions

Symmetric Functions in Sage

Author: Jason Bandlow, Anne Schilling, Nicolas M. Thiery, Mike Zabrocki

This document is an introduction to working with symmetric function theory in Sage. It is not intended to be an introduction to the theory of symmetric functions ([MAC] and [STA], Chapter 7, are two excellent references.) The reader is also expected to be familiar with Sage.

The algebra of symmetric functions

The algebra of symmetric functions is the unique free commutative graded connected algebra over the given ring, with one generator in each degree. It can also be thought of as the inverse limit (in the category of graded algebras) of the algebra of symmetric polynomials in $$n$$ variables as $$n \rightarrow \infty$$. Sage allows us to construct the algebra of symmetric functions over any ring. We will use a base ring of rational numbers in these first examples:

sage: Sym = SymmetricFunctions(QQ)
sage: Sym
Symmetric Functions over Rational Field


sage: Sym.category()
Join of Category of hopf algebras over Rational Field
and Category of unique factorization domains
and Category of graded algebras over Rational Field
and Category of commutative algebras over Rational Field
and Category of monoids with realizations
and Category of graded coalgebras over Rational Field
and Category of coalgebras over Rational Field with realizations
and Category of cocommutative coalgebras over Rational Field


Notice that Sym is an abstract algebra. This reflects the fact that there are multiple natural bases. To work with specific elements, we need a realization of this algebra. In practice, this means we need to specify a basis.

An example basis - power sums

Here is an example of how one might use the power sum realization:

sage: p = Sym.powersum()
sage: p
Symmetric Functions over Rational Field in the powersum basis


p now represents the realization of the symmetric function algebra on the power sum basis. The basis itself is accessible through:

sage: p.basis()
Lazy family (Term map from Partitions to Symmetric Functions over Rational Field in the powersum basis(i))_{i in Partitions}
sage: p.basis().keys()
Partitions


This last line means that p.basis() is an association between the set of Partitions and the basis elements of the algebra p. To construct a specific element one can therefore do:

sage: p.basis()[Partition([2,1,1])]
p[2, 1, 1]


As this is rather cumbersome, realizations of the symmetric function algebra allow for the following abuses of notation:

sage: p[Partition([2, 1, 1])]
p[2, 1, 1]
sage: p[[2, 1, 1]]
p[2, 1, 1]
sage: p[2, 1, 1]
p[2, 1, 1]


or even:

sage: p[(i for i in [2, 1, 1])]
p[2, 1, 1]


In the special case of the empty partition, due to a limitation in Python syntax, one cannot use:

sage: p[]       # todo: not implemented


sage: p[[]]
p[]


Note

When elements are constructed using the p[something ] syntax , an error will be raised if the input cannot be interpreted as a partition. This is not the case when p.basis() is used:

sage: p['something']
Traceback (most recent call last):
...
ValueError: all parts of 'something' should be nonnegative integers
sage: p.basis()['something']
p'something'


Elements of p are linear combinations of such compositions:

sage: p.an_element()
2*p[] + 2*p[1] + 3*p[2]


Algebra structure

Algebraic combinations of basis elements can be entered in a natural way:

sage: p[2,1,1] + 2 * p[1] * (p[4] + p[2,1])
3*p[2, 1, 1] + 2*p[4, 1]


Let us explore the other operations of p. We can ask for the mathematical properties of p:

sage: p.categories()
[Category of graded bases of Symmetric Functions over Rational Field,
Category of filtered bases of Symmetric Functions over Rational Field,
Category of bases of Symmetric Functions over Rational Field,
Category of graded hopf algebras with basis over Rational Field,
...]


To start with, p is a graded algebra, the grading being induced by the size of the partitions. Due to this, the one is the basis element indexed by the empty partition:

sage: p.one()
p[]


The p basis is multiplicative; that is, multiplication is induced by linearity from the (nonincreasingly sorted) concatenation of partitions:

sage: p[3,1] * p[2,1]
p[3, 2, 1, 1]

sage: (p.one() + 2 * p[3,1]) * p[4, 2]
p[4, 2] + 2*p[4, 3, 2, 1]


The classical bases

In addition to the power sum basis, other classical bases of the symmetric function algebra include the elementary, complete homogeneous, monomial, and Schur bases:

sage: e = Sym.elementary()
sage: h = Sym.homogeneous()
sage: m = Sym.monomial()
sage: s = Sym.schur()


These and others can be defined all at once with the single command:

sage: Sym.inject_shorthands()
Defining e as shorthand for Symmetric Functions over Rational Field in the elementary basis
Defining f as shorthand for Symmetric Functions over Rational Field in the forgotten basis
Defining h as shorthand for Symmetric Functions over Rational Field in the homogeneous basis
Defining m as shorthand for Symmetric Functions over Rational Field in the monomial basis
Defining p as shorthand for Symmetric Functions over Rational Field in the powersum basis
Defining s as shorthand for Symmetric Functions over Rational Field in the Schur basis


We can then do conversions from one basis to another:

sage: s(p[2,1])
-s[1, 1, 1] + s[3]

sage: m(p[3])
m[3]
sage: m(p[3,2])
m[3, 2] + m[5]


For computations which mix bases, Sage will return a result with respect to a single (not necessarily predictable) basis:

sage: p[2] * s[2] - m[4]
1/2*p[2, 1, 1] + 1/2*p[2, 2] - p[4]

sage: p( m[1] * ( e[3]*s[2] + 1 ))
p[1] + 1/12*p[1, 1, 1, 1, 1, 1] - 1/6*p[2, 1, 1, 1, 1] - 1/4*p[2, 2, 1, 1] + 1/6*p[3, 1, 1, 1] + 1/6*p[3, 2, 1]


The one for different bases such as the power sum and Schur function is the same:

sage: s.one() == p.one()
True


Basic computations

In this section, we explore some of the many methods that can be applied to an arbitrary symmetric function:

sage: f = s[2]^2; f
s[2, 2] + s[3, 1] + s[4]


For more methods than discussed here, create a symmetric function as above, and use f.<tab>.

Representation theory of the symmetric group

The Schur functions $$s_\lambda$$ can also be interpreted as irreducible characters of the symmetric group $$S_n$$, where $$n$$ is the size of the partition $$\lambda$$. Since the Schur functions of degree $$n$$ form a basis of the symmetric functions of degree $$n$$, it follows that an arbitrary symmetric function (homogeneous of degree $$n$$) may be interpreted as a function on the symmetric group. In this interpretation the power sum symmetric function $$p_\lambda$$ is the characteristic function of the conjugacy class with shape $$\lambda$$, multiplied by the order of the centralizer of an element. Hence the irreducible characters can be computed as follows:

sage: Sym = SymmetricFunctions(QQ)
sage: s = Sym.schur()
sage: p = Sym.power()
sage: P = Partitions(5).list()
sage: P = [P[i] for i in range(len(P)-1,-1,-1)]
sage: M = matrix([[s[P[i]].scalar(p[P[j]]) for j in range(len(P))] for i in range(len(P))])
sage: M
[ 1 -1  1  1 -1 -1  1]
[ 4 -2  0  1  1  0 -1]
[ 5 -1  1 -1 -1  1  0]
[ 6  0 -2  0  0  0  1]
[ 5  1  1 -1  1 -1  0]
[ 4  2  0  1 -1  0 -1]
[ 1  1  1  1  1  1  1]


We can indeed check that this agrees with the character table of $$S_5$$:

sage: SymmetricGroup(5).character_table() == M
True


In this interpretation of symmetric functions as characters on the symmetric group, the multiplication and comultiplication are interpreted as induction (from $$S_n\times S_m$$ to $$S_{n+m}$$) and restriction, respectively. The Schur functions can also be interpreted as characters of $$GL_n$$, see Partitions and Schur functions.

The omega involution

The $$\omega$$ involution is the linear extension of the map which sends $$e_\lambda$$ to $$h_{\lambda}$$:

sage: h(f)
h[2, 2]
sage: e(f.omega())
e[2, 2]


The Hall scalar product

The Hall scalar product on the algebra of symmetric functions makes the Schur functions into an orthonormal basis:

sage: f.scalar(f)
3


Skewing

Skewing is the adjoint operation to multiplication with respect to this scalar product:

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


In general, s[la].skew_by(s[mu]) is the symmetric function typically denoted $$s_{\lambda \setminus \mu}$$ or $$s_{\lambda / \mu}$$.

Expanding into variables

We can expand a symmetric function into a symmetric polynomial in a specified number of variables:

sage: f.expand(2)
x0^4 + 2*x0^3*x1 + 3*x0^2*x1^2 + 2*x0*x1^3 + x1^4


See the documentation for expand for more examples.

The Kronecker product

As in the section on the Representation theory of the symmetric group, a symmetric function may be considered as a class function on the symmetric group where the elements $$p_\mu/z_\mu$$ are the indicators of a permutation having cycle structure $$\mu$$. The Kronecker product of two symmetric functions corresponds to the pointwise product of these class functions.

Since the Schur functions are the irreducible characters of the symmetric group under this identification, the Kronecker product of two Schur functions corresponds to the internal tensor product of two irreducible symmetric group representations.

Under this identification, the Kronecker product of $$p_\mu/z_\mu$$ and $$p_\nu/z_\nu$$ is $$p_\mu/z_\mu$$ if $$\mu=\nu$$, and the result is equal to $$0$$ otherwise.

internal_product, kronecker_product, inner_tensor and itensor are different names for the same function.

sage: f.kronecker_product(f)
s[1, 1, 1, 1] + 3*s[2, 1, 1] + 4*s[2, 2] + 5*s[3, 1] + 3*s[4]


Plethysm

The plethysm of symmetric functions is the operation corresponding to composition of representations of the general linear group. See [STA] Chapter 7, Appendix 2 for details.

sage: s[2].plethysm(s[2])
s[2, 2] + s[4]


Plethysm can also be written as a composition of functions:

sage: s[2]( s[2] )
s[2, 2] + s[4]


If the coefficient ring contains degree 1 elements, these are handled properly by plethysm:

sage: R.<t> = QQ[]; s = SymmetricFunctions(R).schur()
sage: s[2]( (1-t)*s[1] )
(t^2-t)*s[1, 1] + (-t+1)*s[2]


See the documentation for plethysm for more information.

Inner plethysm

The operation of inner plethysm f.inner_plethysm(g) models the composition of the $$S_n$$ representation represented by $$g$$ with the $$GL_m$$ representation whose character is $$f$$. See the documentation of inner_plethysm, [ST94] or [STA], exercise 7.74 solutions for more information:

sage: s = SymmetricFunctions(QQ).schur()
sage: f = s[2]^2
sage: f.inner_plethysm(s[2])
s[2]


Hopf algebra structure

The ring of symmetric functions is further endowed with a coalgebra structure. The coproduct is an algebra morphism, and therefore determined by its values on the generators; the power sum generators are primitive:

sage: p[1].coproduct()
p[] # p[1] + p[1] # p[]
sage: p[2].coproduct()
p[] # p[2] + p[2] # p[]


The coproduct, being cocommutative on the generators, is cocommutative everywhere:

sage: p[2, 1].coproduct()
p[] # p[2, 1] + p[1] # p[2] + p[2] # p[1] + p[2, 1] # p[]


This coproduct, along with the counit which sends every symmetric function to its $$0$$-th homogeneous component, makes the ring of symmetric functions into a graded connected bialgebra. It is known that every graded connected bialgebra has an antipode. For the ring of symmetric functions, the antipode can be characterized explicitly: The antipode is an anti-algebra morphism (thus an algebra morphism, since our algebra is commutative) which sends $$p_{\lambda}$$ to $$(-1)^{\mathrm{length}(\lambda)} p_{\lambda}$$ for every partition $$\lambda$$. Thus, in particular, it sends the generators on the p basis to their opposites:

sage: p[3].antipode()
-p[3]
sage: p[3,2,1].antipode()
-p[3, 2, 1]


The graded connected bialgebra of symmetric functions over a $$\QQ$$-algebra has a rather simply-understood structure: It is (isomorphic to) the symmetric algebra of its space of primitives (which is spanned by the power-sum symmetric functions).

Here are further examples:

sage: f = s[2]^2
sage: f.antipode()
s[1, 1, 1, 1] + s[2, 1, 1] + s[2, 2]
sage: f.coproduct()
s[] # s[2, 2] + s[] # s[3, 1] + s[] # s[4] + 2*s[1] # s[2, 1] + 2*s[1] # s[3] + s[1, 1] # s[1, 1]
+ s[1, 1] # s[2] + s[2] # s[1, 1] + 3*s[2] # s[2] + 2*s[2, 1] # s[1] + s[2, 2] # s[] + 2*s[3] # s[1]
+ s[3, 1] # s[] + s[4] # s[]
sage: f.coproduct().apply_multilinear_morphism( lambda x,y: x*y.antipode() )
0


Transformations of symmetric functions

There are many methods in Sage which make it easy to manipulate symmetric functions. For example, if we have some function which acts on partitions (say, conjugation), it is a simple matter to apply it to the support of a symmetric function. Here is an example:

sage: conj = lambda mu: mu.conjugate()
sage: f = h[4] + 2*h[3,1]
sage: f.map_support(conj)
h[1, 1, 1, 1] + 2*h[2, 1, 1]


We can also easily modify the coefficients:

sage: def foo(mu, coeff): return mu.conjugate(), -coeff
sage: f.map_item(foo)
-h[1, 1, 1, 1] - 2*h[2, 1, 1]


See also map_coefficients.

There are also methods for building functions directly:

sage: s.sum_of_monomials(mu for mu in Partitions(3))
s[1, 1, 1] + s[2, 1] + s[3]
sage: s.sum_of_monomials(Partitions(3))
s[1, 1, 1] + s[2, 1] + s[3]
sage: s.sum_of_terms( (mu, mu[0]) for mu in Partitions(3))
s[1, 1, 1] + 2*s[2, 1] + 3*s[3]


These are the preferred way to build elements within a program; the result will usually be faster than using sum(). It also guarantees that empty sums yields the zero of s (see also s.sum).

Note also that it is a good idea to use:

sage: s.one()
s[]
sage: s.zero()
0


instead of s(1) and s(0) within programs where speed is important, in order to prevent unnecessary coercions.

Different base rings

Depending on the base ring, the different realizations of the symmetric function algebra may not span the same space:

sage: SZ = SymmetricFunctions(ZZ)
sage: p = SZ.power(); s = SZ.schur()
sage: p(s[1,1,1])
Traceback (most recent call last):
...
TypeError: no conversion of this rational to integer


Because of this, some functions may not behave as expected when working over the integers, even though they make mathematical sense:

sage: s[1,1,1].plethysm(s[1,1,1])
Traceback (most recent call last):
...
TypeError: no conversion of this rational to integer


It is possible to work over different base rings simultaneously:

sage: s = SymmetricFunctions(QQ).schur()
sage: p = SymmetricFunctions(QQ).power()
sage: sz = SymmetricFunctions(ZZ).schur(); sz._prefix = 'sz'
sage: pz = SymmetricFunctions(ZZ).power(); pz._prefix = 'pz'
sage: p(sz[1,1,1])
1/6*p[1, 1, 1] - 1/2*p[2, 1] + 1/3*p[3]
sage: sz( 1/6*p[1, 1, 1] - 1/2*p[2, 1] + 1/3*p[3] )
sz[1, 1, 1]


As shown in this example, if you are working over multiple base rings simultaneously, it is a good idea to change the prefix in some cases, so that you can tell from the output which realization your result is in.

Let us change the notation back for the remainder of this tutorial:

sage: sz._prefix = 's'
sage: pz._prefix = 'p'


One can also use the Sage standard renaming idiom to get shorter outputs:

sage: Sym = SymmetricFunctions(QQ)
sage: Sym.rename("Sym")
sage: Sym
Sym
sage: Sym.rename()


And we name it back:

sage: Sym.rename("Symmetric Functions over Rational Field"); Sym
Symmetric Functions over Rational Field


Other bases

There are two additional basis of the symmetric functions which are not considered as classical bases:

• forgotten basis

• Witt basis

The forgotten basis is the dual basis of the elementary symmetric functions basis with respect to the Hall scalar product. The Witt basis can be constructed by

$\prod_{d=1}^{\infty} (1 - w_d t^d)^{-1} = \sum_{n=0}^{\infty} h_n t^n$

where $$t$$ is a formal variable.

There are further bases of the ring of symmetric functions, in general over fields with parameters such as $$q$$ and $$t$$:

• Hall-Littlewood bases

• Jack bases

• Macdonald bases

• $$k$$-Schur functions

• Hecke character basis

We briefly demonstrate how to access these bases. For more information, see the documentation of the individual bases.

The Jack polynomials can be obtained as:

sage: Sym = SymmetricFunctions(FractionField(QQ['t']))
sage: Jack = Sym.jack()
sage: P = Jack.P(); J = Jack.J(); Q = Jack.Q()
sage: J(P[2,1])
(1/(t+2))*JackJ[2, 1]


The parameter $$t$$ can be specialized as follows:

sage: Sym = SymmetricFunctions(QQ)
sage: Jack = Sym.jack(t = 1)
sage: P = Jack.P(); J = Jack.J(); Q = Jack.Q()
sage: J(P[2,1])
1/3*JackJ[2, 1]


Similarly one can access the Hall-Littlewood and Macdonald polynomials, etc:

sage: Sym = SymmetricFunctions(FractionField(QQ['q','t']))
sage: Mcd = Sym.macdonald()
sage: P = Mcd.P(); J = Mcd.J(); Q = Mcd.Q()
sage: J(P[2,1])
(1/(-q*t^4+2*q*t^3-q*t^2+t^2-2*t+1))*McdJ[2, 1]


We can also construct the $$\bar{q}$$ basis that can be used to determine character tables for Hecke algebras (with quadratic relation $$T_i^2 = (1-q) T_i + q$$):

sage: Sym = SymmetricFunctions(ZZ['q'].fraction_field())
sage: qbar = Sym.hecke_character()
sage: s = Sym.s()
sage: s(qbar[2,1])
-s[1, 1, 1] + (q-1)*s[2, 1] + q*s[3]


$$k$$-Schur functions

The $$k$$-Schur functions live in the $$k$$-bounded subspace of the ring of symmetric functions. It is possible to compute in the $$k$$-bounded subspace directly:

sage: Sym = SymmetricFunctions(QQ)
sage: ks = Sym.kschur(3,1)
sage: f = ks[2,1]*ks[2,1]; f
ks3[2, 2, 1, 1] + ks3[2, 2, 2] + ks3[3, 1, 1, 1]


or to lift to the ring of symmetric functions:

sage: f.lift()
s[2, 2, 1, 1] + s[2, 2, 2] + s[3, 1, 1, 1] + 2*s[3, 2, 1] + s[3, 3] + s[4, 1, 1] + s[4, 2]


However, it is not always possible to convert a symmetric function to the $$k$$-bounded subspace:

sage: s = Sym.schur()
sage: ks(s[2,1,1])
Traceback (most recent call last):
...
ValueError: s[2, 1, 1] is not in the image


The $$k$$-Schur functions are more generally defined with a parameter $$t$$ and they are a basis of the subspace spanned by the Hall-Littlewood Qp symmetric functions indexed by partitions whose first part is less than or equal to $$k$$:

sage: Sym = SymmetricFunctions(QQ['t'].fraction_field())
sage: SymS3 = Sym.kBoundedSubspace(3) # default t='t'
sage: ks = SymS3.kschur()
sage: Qp = Sym.hall_littlewood().Qp()
sage: ks(Qp[2,1,1,1])
ks3[2, 1, 1, 1] + (t^2+t)*ks3[2, 2, 1] + (t^3+t^2)*ks3[3, 1, 1] + t^4*ks3[3, 2]


The subspace spanned by the $$k$$-Schur functions with a parameter $$t$$ are not known to form a natural algebra. However it is known that the product of a $$k$$-Schur function and an $$\ell$$-Schur function is in the linear span of the $$k+\ell$$-Schur functions:

sage: ks(ks[2,1]*ks[1,1])
Traceback (most recent call last):
...
ValueError: s[2, 1, 1, 1] + s[2, 2, 1] + s[3, 1, 1] + s[3, 2] is not in the image
sage: ks[2,1]*ks[1,1]
s[2, 1, 1, 1] + s[2, 2, 1] + s[3, 1, 1] + s[3, 2]
sage: ks6 = Sym.kBoundedSubspace(6).kschur()
sage: ks6(ks[3,1,1]*ks[3])
ks6[3, 3, 1, 1] + ks6[4, 2, 1, 1] + (t+1)*ks6[4, 3, 1] + t*ks6[4, 4]
+ ks6[5, 1, 1, 1] + ks6[5, 2, 1] + t*ks6[5, 3] + ks6[6, 1, 1]


The $$k$$-split basis is a second basis of the ring spanned by the $$k$$-Schur functions with a parameter $$t$$. The $$k$$-split basis has the property that $$Q'_\lambda[X;t]$$ expands positively in the $$k$$-split basis and the $$k$$-split basis conjecturally expands positively in the $$k$$-Schur functions. The definition can be found in [LLMSSZ] p. 81.:

sage: ksp3 = SymS3.ksplit()
sage: ksp3(Qp[2,1,1,1])
ksp3[2, 1, 1, 1] + t^2*ksp3[2, 2, 1] + (t^3+t^2)*ksp3[3, 1, 1] + t^4*ksp3[3, 2]
sage: [ks(ksp3(la)) for la in sorted(ksp3(Qp[2,1,1,1]).support())]
[ks3[2, 1, 1, 1] + t*ks3[2, 2, 1], ks3[2, 2, 1], ks3[3, 1, 1], ks3[3, 2]]


dual $$k$$-Schur functions

The dual space to the subspace spanned by the $$k$$-Schur functions is most naturally realized as a quotient of the ring of symmetric functions by an ideal. When $$t=1$$ the ideal is generated by the monomial symmetric functions indexed by partitions whose first part is greater than $$k$$.:

sage: Sym = SymmetricFunctions(QQ)
sage: SymQ3 = Sym.kBoundedQuotient(3,t=1)
sage: km = SymQ3.kmonomial()
sage: km[2,1]*km[2,1]
4*m3[2, 2, 1, 1] + 6*m3[2, 2, 2] + 2*m3[3, 2, 1] + 2*m3[3, 3]
sage: F = SymQ3.affineSchur()
sage: F[2,1]*F[2,1]
2*F3[1, 1, 1, 1, 1, 1] + 4*F3[2, 1, 1, 1, 1] + 4*F3[2, 2, 1, 1] + 4*F3[2, 2, 2]
+ 2*F3[3, 1, 1, 1] + 4*F3[3, 2, 1] + 2*F3[3, 3]


When $$t$$ is not equal to $$1$$, the subspace spanned by the $$k$$-Schur functions is realized as a quotient of the ring of symmetric functions by the ideal generated by the Hall-Littlewood symmetric functions in the P basis indexed by partitions with first part greater than $$k$$.:

sage: Sym = SymmetricFunctions(FractionField(QQ['t']))
sage: SymQ3 = Sym.kBoundedQuotient(3)
sage: kHLP = SymQ3.kHallLittlewoodP()
sage: kHLP[2,1]*kHLP[2,1]
(t^2+2*t+1)*HLP3[2, 2, 1, 1] + (t^3+2*t^2+2*t+1)*HLP3[2, 2, 2]
+ (-t^4-t^3+t+1)*HLP3[3, 1, 1, 1] + (-t^2+t+2)*HLP3[3, 2, 1] + (t+1)*HLP3[3, 3]
sage: HLP = Sym.hall_littlewood().P()
sage: kHLP(HLP[3,1])
HLP3[3, 1]
sage: kHLP(HLP[4])
0


In this space, the basis which is dual to the $$k$$-Schur functions conjecturally expands positively in the $$k$$-bounded Hall-Littlewood functions and has positive structure coefficients.:

sage: dks = SymQ3.dual_k_Schur()
sage: kHLP(dks[2,2])
(t^4+t^2)*HLP3[1, 1, 1, 1] + t*HLP3[2, 1, 1] + HLP3[2, 2]
sage: dks[2,1]*dks[1,1]
(t^2+t)*dks3[1, 1, 1, 1, 1] + (t+1)*dks3[2, 1, 1, 1] + (t+1)*dks3[2, 2, 1]
+ dks3[3, 1, 1] + dks3[3, 2]


At $$t=1$$ the $$k$$-bounded Hall-Littlewood basis is equal to the $$k$$-bounded monomial basis and the dual $$k$$-Schur elements are equal to the affine Schur basis. The $$k$$-bounded monomial basis and affine Schur functions are faster and should be used instead of the $$k$$-bounded Hall-Littlewood P basis and dual $$k$$-Schur functions when $$t=1$$.:

sage: SymQ3 = Sym.kBoundedQuotient(3,t=1)
sage: dks = SymQ3.dual_k_Schur()
sage: F = SymQ3.affineSchur()
sage: F[3,1]==dks[3,1]
True


Implementing new bases

In order to implement a new symmetric function basis, Sage will need to know at a minimum how to change back and forth between at least one other basis (although they do not necessarily have to be the same basis). All of the standard functions associated with the basis will have a default implementation (although a more specific implementation may be more efficient).

To present an idea of how this is done, we will create here the example of how to implement the basis $$s_\mu[X(1-t)]$$.

To begin, we import the class sage.combinat.sf.sfa.SymmetricFunctionAlgebra_generic(). Our new basis will inherit all of the default methods from this class:

sage: from sage.combinat.sf.sfa import SymmetricFunctionAlgebra_generic as SFA_generic


Now the basis we are creating has a parameter $$t$$ which is possible to specialize. In this example we will convert to and from the Schur basis. For this we implement methods _self_to_s and _s_to_self. By registering these two functions as coercions, Sage then knows automatically how it possible to change between any two bases for which there is a path of changes of bases.

sage: from sage.categories.morphism import SetMorphism
sage: class SFA_st(SFA_generic):
....:     def __init__(self, Sym, t):
....:         SFA_generic.__init__(self, Sym, basis_name=
....:           "Schur functions with a plethystic substitution of X -> X(1-t)",
....:           prefix='st')
....:         self._s = Sym.s()
....:         self.t = Sym.base_ring()(t)
....:         cat = HopfAlgebras(Sym.base_ring()).WithBasis()
....:         self.register_coercion(
....:           SetMorphism(Hom(self._s, self, cat), self._s_to_self))
....:         self._s.register_coercion(
....:           SetMorphism(Hom(self, self._s, cat), self._self_to_s))
....:     def _s_to_self(self, f):
....:         # f is a Schur function and the output is in the st basis
....:         return self._from_dict(f.theta_qt(0,self.t)._monomial_coefficients)
....:     def _self_to_s(self, f):
....:         # f is in the st basis and the output is in the Schur basis
....:         return self._s.sum(cmu*self._s(mu).theta_qt(self.t,0) for mu,cmu in f)
....:     class Element(SFA_generic.Element):
....:         pass


An instance of this basis is created by calling it with a symmetric function ring Sym and a parameter t which is in the base ring of Sym. The Element class inherits all of the methods from sage.combinat.sf.sfa.SymmetricFunctionAlgebra_generic_Element.

In the reference [MAC] on page 354, this basis is denoted $$S_\lambda(x;t)$$ and the change of basis coefficients of the Macdonald J basis are the coefficients $$K_{\lambda\mu}(q,t)$$. Here is an example of its use:

sage: QQqt = QQ['q','t'].fraction_field()
sage: (q,t) = QQqt.gens()
sage: st = SFA_st(SymmetricFunctions(QQqt),t)
sage: st
Symmetric Functions over Fraction Field of Multivariate Polynomial
Ring in q, t over Rational Field in the Schur functions with a
plethystic substitution of X -> X(1-t) basis
sage: st[2,1] * st[1]
st[2, 1, 1] + st[2, 2] + st[3, 1]
sage: st([2]).coproduct()
st[] # st[2] + st[1] # st[1] + st[2] # st[]
sage: J = st.symmetric_function_ring().macdonald().J()
sage: st(J[2,1])
q*st[1, 1, 1] + (q*t+1)*st[2, 1] + t*st[3]


Acknowledgements

The design is heavily inspired from the implementation of symmetric functions in MuPAD-Combinat (see [HT04] and [FD06]).

REFERENCES:

[FD06]

Francois Descouens, Making research on symmetric functions using MuPAD-Combinat. In Andres Iglesias and Nobuki Takayama, editors, 2nd International Congress on Mathematical Software (ICMS’06), volume 4151 of LNCS, pages 407-418, Castro Urdiales, Spain, September 2006. Springer-Verlag. arXiv 0806.1873

[HT04]

Florent Hivert and Nicolas M. Thiery, MuPAD-Combinat, an open-source package for research in algebraic combinatorics. Sem. Lothar. Combin., 51 :Art. B51z, 70 pp. (electronic), 2004. http://mupad-combinat.sf.net/.

[MAC] (1,2)

Ian Macdonald, Symmetric Functions and Orthogonal Polynomials, Second edition. With contributions by A. Zelevinsky. Oxford Mathematical Monographs. Oxford Science Publications. The Clarendon Press, Oxford University Press, New York, 1995. x+475 pp. ISBN: 0-19-853489-2

[STA] (1,2,3)

Richard Stanley, Enumerative combinatorics. Vol. 2. With a foreword by Gian-Carlo Rota and appendix 1 by Sergey Fomin. Cambridge Studies in Advanced Mathematics, 62. Cambridge University Press, Cambridge, 1999. xii+581 pp. ISBN: 0-521-56069-1; 0-521-78987-7

[ST94]

Scharf, Thomas, Thibon, Jean-Yves, A Hopf-algebra approach to inner plethysm. Adv. Math. 104 (1994), no. 1, 30-58. doi:10.1006/aima.1994.1019