# sage_setup: distribution = sagemath-combinat
# sage.doctest: needs sage.combinat sage.modules
r"""
Quotient of symmetric function space by ideal generated by Hall-Littlewood symmetric functions

The quotient of symmetric functions by the ideal generated by the Hall-Littlewood P
symmetric functions indexed by partitions with first part greater than `k`.  When `t=1`
this space is the quotient of the symmetric functions by the ideal generated by the
monomial symmetric functions indexed by partitions with first part greater than `k`.

AUTHORS:

- Chris Berg (2012-12-01)

- Mike Zabrocki - `k`-bounded Hall Littlewood P and dual `k`-Schur functions (2012-12-02)
"""
# ****************************************************************************
#       Copyright (C) 2012 Chris Berg <chrisjamesberg@gmail.com>
#       Based off of similar code of Jason Bandlow, Anne Schilling
#                                    and Mike Zabrocki
#
#  Distributed under the terms of the GNU General Public License (GPL)
#
#    This code is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
#    General Public License for more details.
#
#  The full text of the GPL is available at:
#
#                  https://www.gnu.org/licenses/
# ****************************************************************************

from sage.categories.graded_hopf_algebras import GradedHopfAlgebras
from sage.categories.graded_hopf_algebras_with_basis import GradedHopfAlgebrasWithBasis
from sage.categories.realizations import Category_realization_of_parent, Realizations
from sage.combinat.free_module import CombinatorialFreeModule
from sage.combinat.partition import (
    Partition,
    Partitions,
    Partitions_all_bounded,
    PartitionsGreatestLE,
)
from sage.cpython.getattr import raw_getattr
from sage.misc.cachefunc import cached_method
from sage.misc.constant_function import ConstantFunction
from sage.rings.integer import Integer
from sage.rings.integer_ring import ZZ
from sage.structure.parent import Parent
from sage.structure.unique_representation import UniqueRepresentation


class KBoundedQuotient(UniqueRepresentation, Parent):

    def __init__(self, Sym, k, t='t'):
        r"""
        Initialization of the ring of Symmetric functions modulo the ideal of monomial
        symmetric functions which are indexed by partitions whose first part is greater
        than `k`.

        INPUT:

        - ``Sym`` -- an element of class :class:`sage.combinat.sf.sf.SymmetricFunctions`

        - ``k`` -- positive integer

        - ``R`` -- a ring

        EXAMPLES::

            sage: Sym = SymmetricFunctions(QQ)
            sage: Q = Sym.kBoundedQuotient(3,t=1)
            sage: Q
            3-Bounded Quotient of Symmetric Functions over Rational Field with t=1
            sage: km = Q.km()
            sage: km
            3-Bounded Quotient of Symmetric Functions over Rational Field with t=1 in the 3-bounded monomial basis
            sage: F = Q.affineSchur()
            sage: F(km(F[3,1,1])) == F[3,1,1]                                           # needs lrcalc_python
            True
            sage: km(F(km([3,2]))) == km[3,2]                                           # needs lrcalc_python
            True
            sage: F[3,2].lift()
            m[1, 1, 1, 1, 1] + m[2, 1, 1, 1] + m[2, 2, 1] + m[3, 1, 1] + m[3, 2]
            sage: F[2,1]*F[2,1]                                                         # needs lrcalc_python
            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]
            sage: F[1,2]
            Traceback (most recent call last):
            ...
            ValueError: [1, 2] is not an element of 3-Bounded Partitions
            sage: F[4,2]
            Traceback (most recent call last):
            ...
            ValueError: [4, 2] is not an element of 3-Bounded Partitions
            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: HLPk = Q.kHallLittlewoodP()
            sage: HLPk[2,1]*HLPk[2,1]                                                   # needs lrcalc_python
            4*HLP3[2, 2, 1, 1] + 6*HLP3[2, 2, 2] + 2*HLP3[3, 2, 1] + 2*HLP3[3, 3]
            sage: dks = Q.dual_k_Schur()
            sage: dks[2,1]*dks[2,1]                                                     # needs lrcalc_python
            2*dks3[1, 1, 1, 1, 1, 1] + 4*dks3[2, 1, 1, 1, 1] + 4*dks3[2, 2, 1, 1] + 4*dks3[2, 2, 2] + 2*dks3[3, 1, 1, 1] + 4*dks3[3, 2, 1] + 2*dks3[3, 3]

        ::

            sage: Q = Sym.kBoundedQuotient(3)
            Traceback (most recent call last):
            ...
            TypeError: unable to convert 't' to a rational
            sage: Sym = SymmetricFunctions(QQ['t'].fraction_field())
            sage: Q = Sym.kBoundedQuotient(3)
            sage: km = Q.km()
            sage: F = Q.affineSchur()
            sage: F(km(F[3,1,1])) == F[3,1,1]                                           # needs lrcalc_python
            True
            sage: km(F(km([3,2]))) == km[3,2]                                           # needs lrcalc_python
            True
            sage: dks = Q.dual_k_Schur()
            sage: HLPk = Q.kHallLittlewoodP()
            sage: dks(HLPk(dks[3,1,1])) == dks[3,1,1]
            True
            sage: km(dks(km([3,2]))) == km[3,2]
            True
            sage: dks[2,1]*dks[2,1]                                                     # needs lrcalc_python
            (t^3+t^2)*dks3[1, 1, 1, 1, 1, 1] + (2*t^2+2*t)*dks3[2, 1, 1, 1, 1] + (t^2+2*t+1)*dks3[2, 2, 1, 1] + (t^2+2*t+1)*dks3[2, 2, 2] + (t+1)*dks3[3, 1, 1, 1] + (2*t+2)*dks3[3, 2, 1] + (t+1)*dks3[3, 3]

        TESTS::

            sage: TestSuite(Q).run()                                                    # needs lrcalc_python
        """
        R = Sym.base_ring()
        self.k = k
        self.t = R(t)
        self._base = R # Won't be needed when CategoryObject won't override anymore base_ring
        self._sym = Sym
        if t == 1:
            self._quotient_basis = Sym.m()
        else:
            self._quotient_basis = Sym.hall_littlewood(t=self.t).P()
        Parent.__init__(self, category=GradedHopfAlgebras(R).Quotients().WithRealizations())
        self.indices = ConstantFunction(Partitions_all_bounded(k))

    def ambient(self):
        r"""

        Returns the Symmetric Functions over the same ring as ``self``. This is needed to
        realize our ring as a quotient.

        TESTS::

            sage: Sym = SymmetricFunctions(QQ)
            sage: Q = Sym.kBoundedQuotient(3,t=1)
            sage: Q.ambient()
            Symmetric Functions over Rational Field
        """
        return self._sym

    def a_realization(self):
        r"""
        Return a particular realization of ``self`` (the basis of `k`-bounded monomials
        if `t=1` and the basis of `k`-bounded Hall-Littlewood functions otherwise).

        EXAMPLES::

            sage: Sym = SymmetricFunctions(QQ)
            sage: Q = Sym.kBoundedQuotient(3,t=1)
            sage: Q.a_realization()
            3-Bounded Quotient of Symmetric Functions over Rational Field with t=1 in the 3-bounded monomial basis
            sage: Q = Sym.kBoundedQuotient(3,t=2)
            sage: Q.a_realization()
            3-Bounded Quotient of Symmetric Functions over Rational Field with t=2 in the 3-bounded Hall-Littlewood P basis
        """
        if self.t == 1:
            return self.kmonomial()
        else:
            return self.kHallLittlewoodP()

    def _repr_(self):
        r"""
        Representation of ``self``.

        TESTS::

            sage: Sym = SymmetricFunctions(RR) # indirect doctest
            sage: Sym.kBoundedQuotient(4,t=1)
            4-Bounded Quotient of Symmetric Functions over Real Field with 53 bits of precision with t=1.00000000000000
        """
        ending = ""
        if str(self.t) != 't':
            ending = ' with t=%s' % (self.t)
        return "%s-Bounded Quotient of Symmetric Functions over %s" % (self.k, self.base_ring())+ending

    def kmonomial(self):
        r"""
        The monomial basis of the `k`-bounded quotient of symmetric functions, indexed by
        `k`-bounded partitions.

        EXAMPLES::

            sage: SymmetricFunctions(QQ).kBoundedQuotient(2,t=1).kmonomial()
            2-Bounded Quotient of Symmetric Functions over Rational Field with t=1 in the 2-bounded monomial basis
        """
        return kMonomial(self)

    km = kmonomial

    def kHallLittlewoodP(self):
        r"""
        The Hall-Littlewood P basis of the `k`-bounded quotient of symmetric functions,
        indexed by `k`-bounded partitions.  At `t=1` this basis is equal to the
        `k`-bounded monomial basis and calculations will be faster using elements in the
        `k`-bounded monomial basis (see :meth:`kmonomial`).

        EXAMPLES::

            sage: SymmetricFunctions(QQ['t'].fraction_field()).kBoundedQuotient(2).kHallLittlewoodP()
            2-Bounded Quotient of Symmetric Functions over Fraction Field of Univariate Polynomial Ring in t over Rational Field in the 2-bounded Hall-Littlewood P basis
        """
        return kbounded_HallLittlewoodP(self)

    kHLP = kHallLittlewoodP

    def dual_k_Schur(self):
        r"""
        The dual `k`-Schur basis of the `k`-bounded quotient of symmetric functions,
        indexed by `k`-bounded partitions.  At `t=1` this is also equal to the affine
        Schur basis and calculations will be faster using elements in the :meth:`affineSchur`
        basis.

        EXAMPLES::

            sage: SymmetricFunctions(QQ['t'].fraction_field()).kBoundedQuotient(2).dual_k_Schur()
            2-Bounded Quotient of Symmetric Functions over Fraction Field of Univariate Polynomial Ring in t over Rational Field in the dual 2-Schur basis
        """
        return DualkSchurFunctions(self)

    dks = dual_k_Schur

    def affineSchur(self):
        r"""
        The affine Schur basis of the `k`-bounded quotient of symmetric functions,
        indexed by `k`-bounded partitions.  This is also equal to the affine Stanley
        symmetric functions (see :meth:`WeylGroups.ElementMethods.stanley_symmetric_function`)
        indexed by an affine Grassmannian permutation.

        EXAMPLES::

            sage: SymmetricFunctions(QQ).kBoundedQuotient(2,t=1).affineSchur()
            2-Bounded Quotient of Symmetric Functions over Rational Field with t=1 in the 2-bounded affine Schur basis
        """
        return AffineSchurFunctions(self)

    F = affineSchur

    @cached_method
    def _G_to_km_on_basis_single_level(self, w, m):
        r"""
        Return the `m`-th level of the affine Grothendieck
        polynomial indexed by the affine Permutation ``w``. This code could be
        significantly sped up if it didn't depend on the Iwahori Hecke algebra
        code.

        INPUT:

        - ``w`` -- an affine permutation (an element of the affine type `A` Weyl group)

        - ``m`` -- integer

        OUTPUT: an element of the `k`-bounded quotient

        EXAMPLES::

            sage: Q = SymmetricFunctions(QQ).kBoundedQuotient(3,t=1)
            sage: W = WeylGroup(['A',3,1])
            sage: Q._G_to_km_on_basis_single_level(W.an_element(), 3)
            0
            sage: Q._G_to_km_on_basis_single_level(W.an_element(), 4)
            m3[1, 1, 1, 1]
            sage: Q._G_to_km_on_basis_single_level(W.an_element(), 5)
            -4*m3[1, 1, 1, 1, 1]
        """
        kB = self._sym.kBoundedSubspace(self.k,t=1)
        g = kB.K_kschur()
        mon = self.km()
        if m < w.length():
            return 0
        ans = self.zero()
        for la in Partitions(m, max_part=self.k):
            ans += g.homogeneous_basis_noncommutative_variables_zero_Hecke(la).coefficient(w) * mon(la)
        return ans

    def _AffineGrothendieck(self, w, m):
        r"""
        Return the affine Grothendieck polynomial indexed by the affine permutation
        ``w``.  Because this belongs to the completion of the algebra, and hence is an
        infinite sum, it computes only up to those symmetric functions of degree at most
        ``m``.

        INPUT:

        - ``w`` -- an affine permutation (an element of the affine type `A` Weyl group)

        - ``m`` -- integer

        OUTPUT: an element of the `k`-bounded quotient

        EXAMPLES::

            sage: Q = SymmetricFunctions(QQ).kBoundedQuotient(3,t=1)
            sage: W = WeylGroup(['A',3,1])
            sage: Q._AffineGrothendieck(W.an_element(), 5)
            m3[1, 1, 1, 1] - 4*m3[1, 1, 1, 1, 1]
        """
        return sum(self._G_to_km_on_basis_single_level(w,j) for j in range(w.length(),m+1))

    @cached_method
    def _AffineGrothendieckPolynomial(self, la, m):
        r"""
        Return the affine Grothendieck polynomial indexed by the partition ``la``.
        Because this belongs to the completion of the algebra, and hence is an infinite
        sum, it computes only up to those symmetric functions of degree at most ``m``.
        This method is here to cache the polynomials.

        INPUT:

        - ``la`` -- a `k`-bounded partition

        - ``m`` -- integer

        EXAMPLES::

            sage: Q = SymmetricFunctions(QQ).kBoundedQuotient(3,t=1)
            sage: Q._AffineGrothendieckPolynomial(Partition([2,1]),4)
            2*m3[1, 1, 1] - 8*m3[1, 1, 1, 1] + m3[2, 1] - 3*m3[2, 1, 1] - m3[2, 2]
        """
        return self._AffineGrothendieck(la.to_core(self.k).to_grassmannian(),m)

    def AffineGrothendieckPolynomial(self, la, m):
        r"""
        Return the affine Grothendieck polynomial indexed by the partition ``la``.
        Because this belongs to the completion of the algebra, and hence is an infinite
        sum, it computes only up to those symmetric functions of degree at most ``m``.
        See :meth:`_AffineGrothendieckPolynomial` for the code.

        INPUT:

        - ``la`` -- a `k`-bounded partition

        - ``m`` -- integer

        EXAMPLES::

            sage: Q = SymmetricFunctions(QQ).kBoundedQuotient(3,t=1)
            sage: Q.AffineGrothendieckPolynomial([2,1],4)
            2*m3[1, 1, 1] - 8*m3[1, 1, 1, 1] + m3[2, 1] - 3*m3[2, 1, 1] - m3[2, 2]
        """
        if la == []:
            return self.a_realization().one()
        return self._AffineGrothendieckPolynomial(Partition(la),m)

    def _an_element_(self):
        r"""
        Return an element of the quotient ring of `k`-bounded symmetric functions.

        This method is here to make the TestSuite run properly.

        EXAMPLES::

            sage: Q = SymmetricFunctions(QQ).kBoundedQuotient(3,t=1)
            sage: Q.an_element()
            2*m3[] + 2*m3[1] + 3*m3[2]
        """
        return self.a_realization().an_element()

    def one(self):
        r"""
        Return the unit of the quotient ring of `k`-bounded symmetric functions. This
        method is here to make the TestSuite run properly.

        EXAMPLES::

            sage: Q = SymmetricFunctions(QQ).kBoundedQuotient(3,t=1)
            sage: Q.one()
            m3[]
        """
        return self.a_realization().one()

    def retract(self, la):
        r"""
        Give the retract map from the symmetric functions to the quotient ring of
        `k`-bounded symmetric functions. This method is here to make the TestSuite run
        properly.

        INPUT:

        - ``la`` -- a partition

        OUTPUT: the monomial element of the `k`-bounded quotient indexed by ``la``

        EXAMPLES::

            sage: Q = SymmetricFunctions(QQ).kBoundedQuotient(3,t=1)
            sage: Q.retract([2,1])
            m3[2, 1]
        """
        km = self.a_realization()
        return km.retract(la)

    def lift(self, la):
        r"""
        Give the lift map from the quotient ring of `k`-bounded symmetric functions to
        the symmetric functions. This method is here to make the TestSuite run properly.

        INPUT:

        - ``la`` -- a `k`-bounded partition

        OUTPUT:

        - The monomial element or a Hall-Littlewood P element of the symmetric functions
            indexed by the partition ``la``.

        EXAMPLES::

            sage: Q = SymmetricFunctions(QQ).kBoundedQuotient(3,t=1)
            sage: Q.lift([2,1])
            m[2, 1]
            sage: Q = SymmetricFunctions(QQ['t'].fraction_field()).kBoundedQuotient(3)
            sage: Q.lift([2,1])
            HLP[2, 1]
        """
        km = self.a_realization()
        return km.lift(la)

    def realizations(self):
        """
        A list of realizations of the `k`-bounded quotient.

        EXAMPLES::

            sage: kQ = SymmetricFunctions(QQ['t'].fraction_field()).kBoundedQuotient(3)
            sage: kQ.realizations()
            [3-Bounded Quotient of Symmetric Functions over Fraction Field of Univariate Polynomial Ring in t over Rational Field in the 3-bounded monomial basis, 3-Bounded Quotient of Symmetric Functions over Fraction Field of Univariate Polynomial Ring in t over Rational Field in the 3-bounded Hall-Littlewood P basis, 3-Bounded Quotient of Symmetric Functions over Fraction Field of Univariate Polynomial Ring in t over Rational Field in the 3-bounded affine Schur basis, 3-Bounded Quotient of Symmetric Functions over Fraction Field of Univariate Polynomial Ring in t over Rational Field in the dual 3-Schur basis]
            sage: HLP = kQ.ambient().hall_littlewood().P()
            sage: all( rzn(HLP[3,2,1]).lift() == HLP[3,2,1] for rzn in kQ.realizations())   # needs lrcalc_python
            True
            sage: kQ = SymmetricFunctions(QQ).kBoundedQuotient(3,1)
            sage: kQ.realizations()
            [3-Bounded Quotient of Symmetric Functions over Rational Field with t=1 in the 3-bounded monomial basis, 3-Bounded Quotient of Symmetric Functions over Rational Field with t=1 in the 3-bounded Hall-Littlewood P basis, 3-Bounded Quotient of Symmetric Functions over Rational Field with t=1 in the 3-bounded affine Schur basis, 3-Bounded Quotient of Symmetric Functions over Rational Field with t=1 in the dual 3-Schur basis]
            sage: m = kQ.ambient().m()
            sage: all( rzn(m[3,2,1]).lift() == m[3,2,1] for rzn in kQ.realizations())       # needs lrcalc_python
            True
        """
        return [ self.km(), self.kHLP(), self.affineSchur(), self.dual_k_Schur()]


class KBoundedQuotientBases(Category_realization_of_parent):
    r"""
    The category of bases for the `k`-bounded subspace of symmetric functions.
    """

    def __init__(self, base):
        """
        Initialization of the bases of the `k`-bounded subspace.

        INPUT:

        - ``base`` -- a basis in the `k`-bounded subspace

        TESTS::

            sage: Sym = SymmetricFunctions(QQ['t'])
            sage: from sage.combinat.sf.k_dual import KBoundedQuotientBases
            sage: Q = Sym.kBoundedQuotient(3,t=1)
            sage: KQB = KBoundedQuotientBases(Q); KQB
            Category of k bounded quotient bases of 3-Bounded Quotient of Symmetric Functions over Univariate Polynomial Ring in t over Rational Field with t=1
        """
        Category_realization_of_parent.__init__(self, base)

    def super_categories(self):
        r"""
        The super categories of ``self``.

        EXAMPLES::

            sage: Sym = SymmetricFunctions(QQ['t'])
            sage: from sage.combinat.sf.k_dual import KBoundedQuotientBases
            sage: Q = Sym.kBoundedQuotient(3,t=1)
            sage: KQB = KBoundedQuotientBases(Q)
            sage: KQB.super_categories()
            [Category of realizations of 3-Bounded Quotient of Symmetric Functions over Univariate Polynomial Ring in t over Rational Field with t=1,
             Join of Category of graded Hopf algebras with basis over Univariate Polynomial Ring in t over Rational Field
                 and Category of quotients of algebras over Univariate Polynomial Ring in t over Rational Field
                 and Category of quotients of graded modules with basis over Univariate Polynomial Ring in t over Rational Field]
        """
        R = self.base().base_ring()
        category = GradedHopfAlgebrasWithBasis(R)
        return [Realizations(self.base()), category.Quotients()]

    class ParentMethods:

        def retract(self, la):
            r"""
            Give the retract map from the symmetric functions to the quotient ring of
            `k`-bounded symmetric functions. This method is here to make the TestSuite run
            properly.

            INPUT:

            - ``la`` -- a partition

            OUTPUT: the monomial element of the `k`-bounded quotient indexed by ``la``

            EXAMPLES::

                sage: Q = SymmetricFunctions(QQ).kBoundedQuotient(3,t=1)
                sage: Q.retract([2,1])
                m3[2, 1]
            """
            kmhlp = self.realization_of().a_realization()
            return kmhlp.retract(la)

        def _element_constructor_(self, x):
            r"""
            Needed to rewrite the element constructor because of a bug in free_module.py.
            Ideally :meth:`_element_constructor_` would be inherited from free_module.py,
            but it allows for bad inputs.

            INPUT:

            - ``x`` -- a `k`-bounded partition

            OUTPUT: an element of the `k`-bounded basis

            EXAMPLES::

                sage: Q = SymmetricFunctions(QQ).kBoundedQuotient(3,t=1)
                sage: F = Q.affineSchur()
                sage: F([2,1])
                F3[2, 1]
                sage: F(Partition([4,1]))
                Traceback (most recent call last):
                ...
                TypeError: do not know how to make x (= [4, 1]) an element of self (=3-Bounded Quotient of Symmetric Functions over Rational Field with t=1 in the 3-bounded affine Schur basis)
            """
            R = self.base_ring()

            #Coerce ints to Integers
            if isinstance(x, int):
                x = Integer(x)
            if x in R:
                if x == 0:
                    return self.zero()
                else:
                    raise TypeError("do not know how to make x (= %s) an element of %s" % (x, self))
            #x is an element of the basis enumerated set;
            elif x in self._indices:
                return self.monomial(self._indices(x))
            raise TypeError("do not know how to make x (= %s) an element of self (=%s)" % (x, self))

        def ambient(self):
            r"""
            Return the symmetric functions.

            EXAMPLES::

                sage: km = SymmetricFunctions(QQ).kBoundedQuotient(3,t=1).km()
                sage: km.ambient()
                Symmetric Functions over Rational Field
            """
            return self.realization_of()._sym

        def __getitem__(self, c):
            r"""
            Implement shorthand for accessing basis elements.

            For a basis `X` indexed by partitions, this method allows for
            `X[[3,2]]` and `X[3,2]` to be equivalent to `X[Partition([3,2])]`.

            Due to limitations in Python syntax, one must use `X[[]]` and not
            `X[]` for the basis element indexed by the empty partition.

            EXAMPLES::

                sage: F = SymmetricFunctions(QQ).kBoundedQuotient(3,t=1).affineSchur()
                sage: F[3,2]
                F3[3, 2]
                sage: F[[]]
                F3[]
            """
            if c in ZZ:
                c = self._kbounded_partitions([c])
            else:
                c = self._kbounded_partitions(c)
            return self.monomial(c)

        def _repr_term(self, c):
            """
            Display elements with single brackets.

            The default implementation of CombinatorialFreeModule gives double
            brackets for basis elements indexed by partitions, i.e.,
            `X[[3,2]]`.

            EXAMPLES::

                sage: F = SymmetricFunctions(QQ).kBoundedQuotient(3,t=1).affineSchur()
                sage: F[3,2]    # indirect doctest
                F3[3, 2]
            """
            return self.prefix()+str(c)

        @cached_method
        def one_basis(self):
            r"""
            Return the basis element indexing ``1``.

            EXAMPLES::

                sage: F = SymmetricFunctions(QQ).kBoundedQuotient(3,t=1).affineSchur()
                sage: F.one()  # indirect doctest
                F3[]
            """
            return self._kbounded_partitions([])

        # This is sufficient for degree to work

        def degree_on_basis(self, b):
            r"""
            Return the degree of the basis element indexed by ``b``.

            INPUT:

            - ``b`` -- a partition

            EXAMPLES::

                sage: F = SymmetricFunctions(QQ).kBoundedQuotient(3,t=1).affineSchur()
                sage: F.degree_on_basis(Partition([3,2]))
                5
            """
            return sum(b)

        def indices(self):
            r"""
            The set of `k`-bounded partitions of all nonnegative integers.

            EXAMPLES::

                sage: km = SymmetricFunctions(QQ).kBoundedQuotient(3,t=1).km()
                sage: km.indices()
                3-Bounded Partitions
            """
            return self._kbounded_partitions

        def lift(self, la):
            r"""
            Implement the lift map from the basis ``self`` to the monomial basis of
            symmetric functions.

            INPUT:

            - ``la`` -- a `k`-bounded partition

            OUTPUT: a symmetric function in the monomial basis

            EXAMPLES::

                sage: F = SymmetricFunctions(QQ).kBoundedQuotient(3,t=1).affineSchur()
                sage: F.lift([3,1])
                m[1, 1, 1, 1] + m[2, 1, 1] + m[2, 2] + m[3, 1]
                sage: Sym = SymmetricFunctions(QQ['t'].fraction_field())
                sage: dks = Sym.kBoundedQuotient(3).dual_k_Schur()
                sage: dks.lift([3,1])
                t^5*HLP[1, 1, 1, 1] + t^2*HLP[2, 1, 1] + t*HLP[2, 2] + HLP[3, 1]
                sage: dks = Sym.kBoundedQuotient(3,t=1).dual_k_Schur()
                sage: dks.lift([3,1])                                                       # needs lrcalc_python
                m[1, 1, 1, 1] + m[2, 1, 1] + m[2, 2] + m[3, 1]
            """
            kmhlp = self.realization_of().a_realization()
            return kmhlp(self(la)).lift()

        def product(self, x, y):
            r"""
            Return the product of two elements ``x`` and ``y``.

            INPUT:

            - ``x``, ``y`` -- elements of the `k`-bounded quotient of symmetric functions

            OUTPUT: a `k`-bounded symmetric function in the dual `k`-Schur function basis

            EXAMPLES::

                sage: # needs lrcalc_python
                sage: dks3 = SymmetricFunctions(QQ).kBoundedQuotient(3,t=1).dual_k_Schur()
                sage: dks3.product(dks3[2,1],dks3[1,1])
                2*dks3[1, 1, 1, 1, 1] + 2*dks3[2, 1, 1, 1] + 2*dks3[2, 2, 1] + dks3[3, 1, 1] + dks3[3, 2]
                sage: dks3.product(dks3[2,1]+dks3[1], dks3[1,1])
                dks3[1, 1, 1] + 2*dks3[1, 1, 1, 1, 1] + dks3[2, 1] + 2*dks3[2, 1, 1, 1] + 2*dks3[2, 2, 1] + dks3[3, 1, 1] + dks3[3, 2]
                sage: dks3.product(dks3[2,1]+dks3[1], dks3([]))
                dks3[1] + dks3[2, 1]
                sage: dks3.product(dks3([]), dks3([]))
                dks3[]
                sage: dks3.product(dks3([]), dks3([4,1]))
                Traceback (most recent call last):
                ...
                TypeError: do not know how to make x (= [4, 1]) an element of self (=3-Bounded Quotient of Symmetric Functions over Rational Field with t=1 in the dual 3-Schur basis)

            ::

                sage: # needs lrcalc_python
                sage: dks3 = SymmetricFunctions(QQ['t'].fraction_field()).kBoundedQuotient(3).dual_k_Schur()
                sage: dks3.product(dks3[2,1],dks3[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]
                sage: dks3.product(dks3[2,1]+dks3[1], dks3[1,1])
                dks3[1, 1, 1] + (t^2+t)*dks3[1, 1, 1, 1, 1] + dks3[2, 1] + (t+1)*dks3[2, 1, 1, 1] + (t+1)*dks3[2, 2, 1] + dks3[3, 1, 1] + dks3[3, 2]
                sage: dks3.product(dks3[2,1]+dks3[1], dks3([]))
                dks3[1] + dks3[2, 1]
                sage: dks3.product(dks3([]), dks3([]))
                dks3[]

            ::

                sage: # needs lrcalc_python
                sage: F = SymmetricFunctions(QQ).kBoundedQuotient(3,t=1).affineSchur()
                sage: F.product(F[2,1],F[1,1])
                2*F3[1, 1, 1, 1, 1] + 2*F3[2, 1, 1, 1] + 2*F3[2, 2, 1] + F3[3, 1, 1] + F3[3, 2]
                sage: F.product(F[2,1]+F[1], F[1,1])
                F3[1, 1, 1] + 2*F3[1, 1, 1, 1, 1] + F3[2, 1] + 2*F3[2, 1, 1, 1] + 2*F3[2, 2, 1] + F3[3, 1, 1] + F3[3, 2]
                sage: F.product(F[2,1]+F[1], F([]))
                F3[1] + F3[2, 1]
                sage: F.product(F([]), F([]))
                F3[]
                sage: F.product(F([]), F([4,1]))
                Traceback (most recent call last):
                ...
                TypeError: do not know how to make x (= [4, 1]) an element of self (=3-Bounded Quotient of Symmetric Functions over Rational Field with t=1 in the 3-bounded affine Schur basis)

            ::

                sage: # needs lrcalc_python
                sage: F = SymmetricFunctions(QQ['t'].fraction_field()).kBoundedQuotient(3).affineSchur()
                sage: F.product(F[2,1],F[1,1])
                2*F3[1, 1, 1, 1, 1] + 2*F3[2, 1, 1, 1] + 2*F3[2, 2, 1] + F3[3, 1, 1] + F3[3, 2]
                sage: F.product(F[2,1],F[2])
                (t^4+t^3-2*t^2+1)*F3[1, 1, 1, 1, 1] + (-t^2+t+1)*F3[2, 1, 1, 1] + (-t^2+t+2)*F3[2, 2, 1] + (t+1)*F3[3, 1, 1] + (t+1)*F3[3, 2]
                sage: F.product(F[2,1]+F[1], F[1,1])
                F3[1, 1, 1] + 2*F3[1, 1, 1, 1, 1] + F3[2, 1] + 2*F3[2, 1, 1, 1] + 2*F3[2, 2, 1] + F3[3, 1, 1] + F3[3, 2]
                sage: F.product(F[2,1]+F[1], F([]))
                F3[1] + F3[2, 1]
                sage: F.product(F([]), F([]))
                F3[]

            ::

                sage: # needs lrcalc_python
                sage: km = SymmetricFunctions(QQ).kBoundedQuotient(3,t=1).km()
                sage: km.product(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: Q3 = SymmetricFunctions(FractionField(QQ['t'])).kBoundedQuotient(3)
                sage: km = Q3.km()
                sage: km.product(km[2,1],km[2,1])
                (t^5+7*t^4-8*t^3-28*t^2+47*t-19)*m3[1, 1, 1, 1, 1, 1] + (t^4-3*t^3-9*t^2+23*t-12)*m3[2, 1, 1, 1, 1] + (-t^3-3*t^2+11*t-3)*m3[2, 2, 1, 1] + (-t^2+5*t+2)*m3[2, 2, 2] + (6*t-6)*m3[3, 1, 1, 1] + (3*t-1)*m3[3, 2, 1] + (t+1)*m3[3, 3]
                sage: dks = Q3.dual_k_Schur()
                sage: km.product(dks[2,1],dks[1,1])
                20*m3[1, 1, 1, 1, 1] + 9*m3[2, 1, 1, 1] + 4*m3[2, 2, 1] + 2*m3[3, 1, 1] + m3[3, 2]
            """
            return self( x.lift() * y.lift() )

        def antipode(self, element):
            r"""
            Return the antipode of ``element`` via lifting to the symmetric
            functions and then retracting into the `k`-bounded quotient basis.

            INPUT:

            - ``element`` -- an element in a basis of the ring of symmetric
              functions

            EXAMPLES::

                sage: # needs lrcalc_python
                sage: dks3 = SymmetricFunctions(QQ).kBoundedQuotient(3,t=1).dual_k_Schur()
                sage: dks3[3,2].antipode()
                -dks3[1, 1, 1, 1, 1]
                sage: km = SymmetricFunctions(QQ).kBoundedQuotient(3,t=1).km()
                sage: km[3,2].antipode()
                m3[3, 2]
                sage: km.antipode(km[3,2])
                m3[3, 2]
                sage: m = SymmetricFunctions(QQ).m()
                sage: m[3,2].antipode()
                m[3, 2] + 2*m[5]

            ::

                sage: # needs lrcalc_python
                sage: km = SymmetricFunctions(FractionField(QQ['t'])).kBoundedQuotient(3).km()
                sage: km[1,1,1,1].antipode()
                (t^3-3*t^2+3*t)*m3[1, 1, 1, 1] + (-t^2+2*t)*m3[2, 1, 1] + t*m3[2, 2] + t*m3[3, 1]
                sage: kHP = SymmetricFunctions(FractionField(QQ['t'])).kBoundedQuotient(3).kHLP()
                sage: kHP[2,2].antipode()
                (t^9-t^6-t^5+t^2)*HLP3[1, 1, 1, 1] + (t^6-t^3-t^2+t)*HLP3[2, 1, 1] + (t^5-t^2+1)*HLP3[2, 2] + (t^4-t)*HLP3[3, 1]
                sage: dks = SymmetricFunctions(FractionField(QQ['t'])).kBoundedQuotient(3).dks()
                sage: dks[2,2].antipode()
                dks3[2, 2]
                sage: dks[3,2].antipode()
                -t^2*dks3[1, 1, 1, 1, 1] + (t^2-1)*dks3[2, 2, 1] + (-t^5+t)*dks3[3, 2]
            """
            return self(element.lift().antipode())

        def coproduct(self, element):
            r"""
            Return the coproduct of ``element`` via lifting to the symmetric
            functions and then returning to the `k`-bounded quotient basis.
            This method is implemented for all `t` but is (weakly) conjectured
            to not be the correct operation for arbitrary `t` because the
            coproduct on dual-`k`-Schur functions does not have a positive
            expansion.

            INPUT:

            - ``element`` -- an element in a basis of the ring of symmetric
              functions

            EXAMPLES::

                sage: # needs lrcalc_python
                sage: Q3 = SymmetricFunctions(QQ).kBoundedQuotient(3,t=1)
                sage: km = Q3.km()
                sage: km[3,2].coproduct()
                m3[] # m3[3, 2] + m3[2] # m3[3] + m3[3] # m3[2] + m3[3, 2] # m3[]
                sage: dks3 = Q3.dual_k_Schur()
                sage: dks3[2,2].coproduct()
                dks3[] # dks3[2, 2] + dks3[1] # dks3[2, 1] + dks3[1, 1] # dks3[1, 1] + dks3[2] # dks3[2] + dks3[2, 1] # dks3[1] + dks3[2, 2] # dks3[]

            ::

                sage: # needs lrcalc_python
                sage: Q3t = SymmetricFunctions(FractionField(QQ['t'])).kBoundedQuotient(3)
                sage: km = Q3t.km()
                sage: km[3,2].coproduct()
                m3[] # m3[3, 2] + m3[2] # m3[3] + m3[3] # m3[2] + m3[3, 2] # m3[]
                sage: dks = Q3t.dks()
                sage: dks[2,1,1].coproduct()
                dks3[] # dks3[2, 1, 1] + (-t+1)*dks3[1] # dks3[1, 1, 1] + dks3[1] # dks3[2, 1] + (-t+1)*dks3[1, 1] # dks3[1, 1] + dks3[1, 1] # dks3[2] + (-t+1)*dks3[1, 1, 1] # dks3[1] + dks3[2] # dks3[1, 1] + dks3[2, 1] # dks3[1] + dks3[2, 1, 1] # dks3[]
                sage: kHLP = Q3t.kHLP()
                sage: kHLP[2,1].coproduct()
                HLP3[] # HLP3[2, 1] + (-t^2+1)*HLP3[1] # HLP3[1, 1] + HLP3[1] # HLP3[2] + (-t^2+1)*HLP3[1, 1] # HLP3[1] + HLP3[2] # HLP3[1] + HLP3[2, 1] # HLP3[]
                sage: km.coproduct(km[3,2])
                m3[] # m3[3, 2] + m3[2] # m3[3] + m3[3] # m3[2] + m3[3, 2] # m3[]
            """
            from sage.categories.tensor import tensor
            base = element.lift().parent()
            return self.tensor_square().sum(coeff * tensor([self(base[x]), self(base[y])])
                                            for ((x,y), coeff) in element.lift().coproduct())

        def counit(self, element):
            r"""
            Return the counit of ``element``.

            The counit is the constant term of ``element``.

            INPUT:

            - ``element`` -- an element in a basis

            EXAMPLES::

                sage: km = SymmetricFunctions(FractionField(QQ['t'])).kBoundedQuotient(3).km()
                sage: f = 2*km[2,1] - 3*km([])
                sage: f.counit()
                -3
                sage: km.counit(f)
                -3
            """
            return element.coefficient([])

    class ElementMethods:
        pass


class KBoundedQuotientBasis(CombinatorialFreeModule):
    r"""
    Abstract base class for the bases of the `k`-bounded quotient.
    """

    def __init__(self, kBoundedRing, prefix):
        r"""
        Initialize ``self``.

        INPUT:

        - ``kBoundedRing`` -- an element which is of class :class:`KBoundedQuotient`
        - ``prefix`` -- string used to distinguish this basis, and used in printing

        EXAMPLES::

            sage: from sage.combinat.sf.k_dual import kMonomial
            sage: km = kMonomial(SymmetricFunctions(QQ).kBoundedQuotient(4,t=1))
            sage: km.prefix()  # indirect doctest
            'm4'
            sage: isinstance(km, sage.combinat.sf.k_dual.KBoundedQuotientBasis)
            True
        """
        CombinatorialFreeModule.__init__(self, kBoundedRing.base_ring(),
            kBoundedRing.indices(),
            category=KBoundedQuotientBases(kBoundedRing),
            prefix='%s%d' % (prefix, kBoundedRing.k))

        self._kBoundedRing = kBoundedRing
        self.k = kBoundedRing.k
        self.t = kBoundedRing.t
        self._kbounded_partitions = Partitions_all_bounded(kBoundedRing.k)

    # The following are meant to be inherited with the category framework, but
    # this fails because they are methods of Parent. The trick below overcomes
    # this problem.
    __getitem__ = raw_getattr(KBoundedQuotientBases.ParentMethods, "__getitem__")
    _repr_term = raw_getattr(KBoundedQuotientBases.ParentMethods, "_repr_term")
    _element_constructor_ = raw_getattr(KBoundedQuotientBases.ParentMethods, "_element_constructor_")


class kMonomial(KBoundedQuotientBasis):
    r"""
    The basis of monomial symmetric functions indexed by partitions with first
    part less than or equal to `k`.
    """

    def __init__(self, kBoundedRing):
        r"""
        Initialize the ring which is the `k`-Bounded monomial quotient basis.

        INPUT:

        - ``kBoundedRing`` -- an element which is of class :class:`KBoundedQuotient`

        EXAMPLES::

            sage: from sage.combinat.sf.k_dual import kMonomial
            sage: km = kMonomial(SymmetricFunctions(QQ).kBoundedQuotient(4,t=1))
            sage: km
            4-Bounded Quotient of Symmetric Functions over Rational Field with t=1 in the 4-bounded monomial basis
            sage: TestSuite(km).run()
        """
        KBoundedQuotientBasis.__init__(self, kBoundedRing, 'm')
        Sym = kBoundedRing.ambient()
        Sym.m().module_morphism(self.retract,codomain=self).register_as_coercion() # coercion of monomial to k-bounded monomial

    def _repr_(self):
        """
        TESTS::

            sage: Sym = SymmetricFunctions(QQ)
            sage: km = Sym.kBoundedQuotient(3,t=1).km()
            sage: km._repr_()
            '3-Bounded Quotient of Symmetric Functions over Rational Field with t=1 in the 3-bounded monomial basis'
        """
        return self.realization_of()._repr_() + ' in the %s-bounded monomial basis' % (self.k)

    def retract(self, la):
        r"""
        Implement the retract function on the monomial basis. Given a partition ``la``,
        the retract will return the corresponding `k`-bounded monomial basis element if
        ``la`` is `k`-bounded; zero otherwise.

        INPUT:

        - ``la`` -- a partition

        OUTPUT: a `k`-bounded monomial symmetric function in the `k`-quotient of symmetric
        functions

        EXAMPLES::

            sage: km = SymmetricFunctions(QQ).kBoundedQuotient(3,t=1).km()
            sage: km.retract(Partition([3,1]))
            m3[3, 1]
            sage: km.retract(Partition([4,1]))
            0
            sage: km.retract([])
            m3[]
            sage: m = SymmetricFunctions(QQ).m()
            sage: km(m[3, 1])
            m3[3, 1]
            sage: km(m[4, 1])
            0

        ::

            sage: km = SymmetricFunctions(FractionField(QQ['t'])).kBoundedQuotient(3).km()
            sage: km.retract(Partition([3,1]))
            m3[3, 1]
            sage: km.retract(Partition([4,1]))
            (t^4+t^3-9*t^2+11*t-4)*m3[1, 1, 1, 1, 1] + (-3*t^2+6*t-3)*m3[2, 1, 1, 1] + (-t^2+3*t-2)*m3[2, 2, 1] + (2*t-2)*m3[3, 1, 1] + (t-1)*m3[3, 2]
            sage: m = SymmetricFunctions(FractionField(QQ['t'])).m()
            sage: km(m[3, 1])
            m3[3, 1]
            sage: km(m[4, 1])
            (t^4+t^3-9*t^2+11*t-4)*m3[1, 1, 1, 1, 1] + (-3*t^2+6*t-3)*m3[2, 1, 1, 1] + (-t^2+3*t-2)*m3[2, 2, 1] + (2*t-2)*m3[3, 1, 1] + (t-1)*m3[3, 2]
        """
        if la == []:
            return self([])
        if la[0] <= self.k:
            return self(la)
        if self.t == 1:
            return self.zero()
        else:
            kHLP = self._kBoundedRing.kHallLittlewoodP()
            return self(kHLP._m_to_kHLP_on_basis(la))

    def lift(self, la):
        r"""
        Implement the lift function on the monomial basis. Given a `k`-bounded partition
        ``la``, the lift will return the corresponding monomial basis element.

        INPUT:

        - ``la`` -- a `k`-bounded partition

        OUTPUT: a monomial symmetric function

        EXAMPLES::

            sage: km = SymmetricFunctions(QQ).kBoundedQuotient(3,t=1).km()
            sage: km.lift(Partition([3,1]))
            m[3, 1]
            sage: km.lift([])
            m[]
            sage: km.lift(Partition([4,1]))
            Traceback (most recent call last):
            ...
            TypeError: do not know how to make x (= [4, 1]) an element of self (=3-Bounded Quotient of Symmetric Functions over Rational Field with t=1 in the 3-bounded monomial basis)
        """
        m = self._kBoundedRing.ambient().m()
        return m._from_dict(dict(self(la)))


class kbounded_HallLittlewoodP(KBoundedQuotientBasis):
    r"""
    The basis of P Hall-Littlewood symmetric functions indexed by partitions with first
    part less than or equal to `k`.
    """

    def __init__(self, kBoundedRing):
        r"""
        Initialize the ring which is the `k`-Bounded Hall-Littlewood P quotient basis.

        INPUT:

        - ``kBoundedRing`` -- an element which is of class :class:`KBoundedQuotient`

        EXAMPLES::

            sage: from sage.combinat.sf.k_dual import kbounded_HallLittlewoodP
            sage: kP = kbounded_HallLittlewoodP(SymmetricFunctions(QQ['t'].fraction_field()).kBoundedQuotient(4))
            sage: kP
            4-Bounded Quotient of Symmetric Functions over Fraction Field of Univariate Polynomial Ring in t over Rational Field in the 4-bounded Hall-Littlewood P basis
            sage: TestSuite(kP).run()
        """
        KBoundedQuotientBasis.__init__(self, kBoundedRing, 'HLP')

        Sym = kBoundedRing.ambient()
        Sym.hall_littlewood(kBoundedRing.t).P().module_morphism(self.retract,codomain=self).register_as_coercion() # morphism from HLP to k-bounded HLP
        km = kBoundedRing.km()
        self.module_morphism(self._HLP_to_mk_on_basis, codomain=km, triangular='lower', unitriangular=True).register_as_coercion() # morphism from k-bounded-HLP to k-bounded-m
        km.module_morphism(self._m_to_kHLP_on_basis, codomain=self, triangular='lower', unitriangular=True).register_as_coercion() # morphism from k-bounded-m to k-bounded-HLP

    def _repr_(self):
        """
        TESTS::

            sage: Sym = SymmetricFunctions(QQ['t'].fraction_field())
            sage: kHLP = Sym.kBoundedQuotient(3).kHallLittlewoodP()
            sage: kHLP._repr_()
            '3-Bounded Quotient of Symmetric Functions over Fraction Field of Univariate Polynomial Ring in t over Rational Field in the 3-bounded Hall-Littlewood P basis'
        """
        return self.realization_of()._repr_() + ' in the %s-bounded Hall-Littlewood P basis' % (self.k)

    def _m_to_kHLP_on_basis(self, la):
        r"""
        Convert from the monomial basis to the `k`-bounded Hall-Littlewood
        P basis.  If ``la`` is not `k`-bounded then it returns the projection of
        the monomial by the ideal generated by the Hall-Littlewood P basis indexed
        by partitions whose first part is greater than `k`.

        INPUT:

        - ``la`` -- a partition

        OUTPUT: an element of the `k`-bounded Hall-Littlewood P basis

        EXAMPLES::

            sage: Sym = SymmetricFunctions(QQ['t'].fraction_field())
            sage: kHLP = Sym.kBoundedQuotient(3).kHallLittlewoodP()
            sage: kHLP._m_to_kHLP_on_basis([3,1])
            (t^5-2*t^2-t+2)*HLP3[1, 1, 1, 1] + (t^2-1)*HLP3[2, 1, 1] + (t-1)*HLP3[2, 2] + HLP3[3, 1]
            sage: kHLP._m_to_kHLP_on_basis([4])
            (t^6-t^5-t^4+t^2+t-1)*HLP3[1, 1, 1, 1] + (t^3-t^2-t+1)*HLP3[2, 1, 1] + (t^2-t)*HLP3[2, 2] + (t-1)*HLP3[3, 1]
            sage: mk = kHLP.realization_of().km()
            sage: kHLP(mk([1,1])^2)
            (t^4+t^3+2*t^2+t+1)*HLP3[1, 1, 1, 1] + (t+1)*HLP3[2, 1, 1] + HLP3[2, 2]
            sage: kHLP._m_to_kHLP_on_basis([])
            HLP3[]
            sage: kHLP = SymmetricFunctions(QQ).kBoundedQuotient(3,t=1).kHallLittlewoodP()
            sage: kHLP._m_to_kHLP_on_basis([3,1])
            HLP3[3, 1]
            sage: kHLP._m_to_kHLP_on_basis([4])
            0
            sage: mk = kHLP.realization_of().km()
            sage: kHLP(mk([1,1])^2)
            6*HLP3[1, 1, 1, 1] + 2*HLP3[2, 1, 1] + HLP3[2, 2]
            sage: kHLP(mk([2,1])^2)
            4*HLP3[2, 2, 1, 1] + 6*HLP3[2, 2, 2] + 2*HLP3[3, 2, 1] + 2*HLP3[3, 3]
        """
        if self.t == 1:
            if la in self._kbounded_partitions:
                return self(la)
            else:
                return self.zero()
        else:
            HLP = self._kBoundedRing._quotient_basis
            m = self._kBoundedRing._sym.m()
            elt = dict(x for x in dict(HLP(m(la))).items()
                       if x[0] in self._kbounded_partitions)
            return self._from_dict(elt)

    def _HLP_to_mk_on_basis(self, la):
        r"""
        Convert from the Hall-Littlewood P basis to the `k`-bounded monomial basis and
        projects into the `k`-bounded quotient if ``la`` is not a bounded partition.

        INPUT:

        - ``la`` -- a partition

        OUTPUT: an element of the `k`-bounded monomial basis

        EXAMPLES::

            sage: Sym = SymmetricFunctions(QQ['t'].fraction_field())
            sage: kHLP = Sym.kBoundedQuotient(3).kHallLittlewoodP()
            sage: kHLP._HLP_to_mk_on_basis([3,1])
            (t^3+t^2-5*t+3)*m3[1, 1, 1, 1] + (-2*t+2)*m3[2, 1, 1] + (-t+1)*m3[2, 2] + m3[3, 1]
            sage: kHLP._HLP_to_mk_on_basis([4,1])
            0
            sage: kHLP._HLP_to_mk_on_basis([])
            m3[]
            sage: kHLP = Sym.kBoundedQuotient(3,t=1).kHallLittlewoodP()
            sage: kHLP._HLP_to_mk_on_basis([3,1])
            m3[3, 1]
            sage: kHLP._HLP_to_mk_on_basis([4,1])
            0
            sage: kHLP._HLP_to_mk_on_basis([])
            m3[]
        """
        mk = self._kBoundedRing.km()
        if la not in self._kbounded_partitions:
            return mk.zero()
        if self.t == 1:
            return mk(la)
        else:
            HLP = self._kBoundedRing._quotient_basis
            return mk(HLP(la))

    def retract(self, la):
        r"""
        Implement the retract function on the Hall-Littlewood P basis. Given a partition
        ``la``, the retract will return the corresponding `k`-bounded Hall-Littlewood P
        basis element if ``la`` is `k`-bounded; zero otherwise.

        INPUT:

        - ``la`` -- a partition

        OUTPUT: a `k`-bounded Hall-Littlewood P symmetric function in the `k`-quotient of
        symmetric functions

        EXAMPLES::

            sage: kHLP = SymmetricFunctions(QQ['t'].fraction_field()).kBoundedQuotient(3).kHallLittlewoodP()
            sage: kHLP.retract(Partition([3,1]))
            HLP3[3, 1]
            sage: kHLP.retract(Partition([4,1]))
            0
            sage: kHLP.retract([])
            HLP3[]
            sage: m = kHLP.realization_of().ambient().m()
            sage: kHLP(m[2,2])
            (t^4-t^3-t+1)*HLP3[1, 1, 1, 1] + (t-1)*HLP3[2, 1, 1] + HLP3[2, 2]
        """
        if la == []:
            return self([])
        if la[0] > self.k:
            return self.zero()
        hlp = self._kBoundedRing.ambient().hall_littlewood(self.t).P()
        f = hlp(la)
        return sum(self(x)*f.coefficient(x) for x in f.support() if x in self._kbounded_partitions)

    def lift(self, la):
        r"""
        Implement the lift function on the Hall-Littlewood P basis. Given a `k`-bounded
        partition ``la``, the lift will return the corresponding Hall-Littlewood P basis
        element.

        INPUT:

        - ``la`` -- a `k`-bounded partition

        OUTPUT: a Hall-Littlewood symmetric function

        EXAMPLES::

            sage: kHLP = SymmetricFunctions(QQ['t'].fraction_field()).kBoundedQuotient(3).kHallLittlewoodP()
            sage: kHLP.lift(Partition([3,1]))
            HLP[3, 1]
            sage: kHLP.lift([])
            HLP[]
            sage: kHLP.lift(Partition([4,1]))
            Traceback (most recent call last):
            ...
            TypeError: do not know how to make x (= [4, 1]) an element of self (=3-Bounded Quotient of Symmetric Functions over Fraction Field of Univariate Polynomial Ring in t over Rational Field in the 3-bounded Hall-Littlewood P basis)
        """
        HLP = self._kBoundedRing.ambient().hall_littlewood(t=self.t).P()
        return HLP._from_dict(dict(self(la)))


class DualkSchurFunctions(KBoundedQuotientBasis):
    r"""
    This basis is dual to the `k`-Schur functions.  The expansion is given
    in Section 4.12 of [LLMSSZ]_.  When `t=1` this basis is equal to the
    :class:`AffineSchurFunctions` and that basis is more efficient in this case.

    REFERENCES:

    .. [LLMSSZ] \T. Lam, L. Lapointe, J. Morse, A. Schilling, M. Shimozono, M. Zabrocki,
        k-Schur functions and affine Schubert calculus.
    """

    def __init__(self, kBoundedRing):
        r"""
        Initialize the ring which is the dual `k`-Schur function basis.

        INPUT:

        - ``kBoundedRing`` -- an element which is of class :class:`KBoundedQuotient`

        EXAMPLES::

            sage: from sage.combinat.sf.k_dual import DualkSchurFunctions
            sage: Sym = SymmetricFunctions(QQ['t'].fraction_field())
            sage: dks4 = DualkSchurFunctions(Sym.kBoundedQuotient(4))
            sage: dks4
            4-Bounded Quotient of Symmetric Functions over Fraction Field of Univariate Polynomial Ring in t over Rational Field in the dual 4-Schur basis
            sage: TestSuite(dks4).run()  # long time (7s on sage.math, 2013)
            sage: dks4 = DualkSchurFunctions(Sym.kBoundedQuotient(4,t=1))
            sage: TestSuite(dks4).run()  # long time (7s on sage.math, 2013)
        """
        KBoundedQuotientBasis.__init__(self, kBoundedRing, 'dks')

        kHLP = kBoundedRing.kHallLittlewoodP()
        self.module_morphism(self._dks_to_khlp_on_basis,codomain=kHLP).register_as_coercion() # morphism from dual-k-Schurs to k-bounded-HLP
        kHLP.module_morphism(self._khlp_to_dks_on_basis,codomain=self).register_as_coercion() # morphism from k-bounded-HLP to dual-k-Schurs

    def _repr_(self):
        """
        TESTS::

            sage: Sym = SymmetricFunctions(QQ['t'].fraction_field())
            sage: dks3 = Sym.kBoundedQuotient(3).dual_k_Schur()
            sage: dks3._repr_()
            '3-Bounded Quotient of Symmetric Functions over Fraction Field of Univariate Polynomial Ring in t over Rational Field in the dual 3-Schur basis'
        """
        return self.realization_of()._repr_() + ' in the dual %s-Schur basis' % (self.k)

    def _dks_to_khlp_on_basis(self, la):
        r"""
        Give the expansion of the dual `k`-Schur basis element indexed by ``la`` into
        the Hall-Littlewood P basis.

        INPUT:

        - ``la`` -- a `k`-bounded partition

        OUTPUT: a symmetric function in the Hall-Littlewood P basis

        EXAMPLES::

            sage: # needs lrcalc_python
            sage: dks3 = SymmetricFunctions(QQ).kBoundedQuotient(3,t=1).dual_k_Schur()
            sage: dks3._dks_to_khlp_on_basis(Partition([2,1]))
            2*HLP3[1, 1, 1] + HLP3[2, 1]
            sage: dks3._dks_to_khlp_on_basis(Partition([]))
            HLP3[]
            sage: dks3._dks_to_khlp_on_basis(Partition([4,1]))
            Traceback (most recent call last):
            ...
            AssertionError: [4, 1] should be an element of 3-Bounded Partitions
        """
        Sym = self._kBoundedRing.ambient()
        kB = Sym.kBoundedSubspace(self.k, t=self.t)
        Qp = Sym.hall_littlewood(t=self.t).Qp()
        ks = kB.kschur()
        kHLP = self._kBoundedRing.kHallLittlewoodP()
        return sum( ks(Qp(x)).coefficient(la) * kHLP(x) for x in PartitionsGreatestLE(sum(la), self.k))

    def _khlp_to_dks_on_basis(self, la):
        r"""
        Give the expansion of the `k`-bounded Hall-Littlewood P basis element indexed by
        ``la`` into the dual `k`-Schur basis.

        INPUT:

        - ``la`` -- a `k`-bounded partition

        OUTPUT: a `k`-bounded quotient symmetric function in the dual `k`-Schur basis

        EXAMPLES::

            sage: # needs lrcalc_python
            sage: dks3 = SymmetricFunctions(QQ).kBoundedQuotient(3,t=1).dual_k_Schur()
            sage: dks3._khlp_to_dks_on_basis(Partition([2,1]))
            -2*dks3[1, 1, 1] + dks3[2, 1]
            sage: dks3._khlp_to_dks_on_basis([2,1])
            -2*dks3[1, 1, 1] + dks3[2, 1]
            sage: dks3._khlp_to_dks_on_basis(Partition([]))
            dks3[]
            sage: dks3._khlp_to_dks_on_basis(Partition([4,1]))
            0

        ::

            sage: # needs lrcalc_python
            sage: dks3 = SymmetricFunctions(QQ['t'].fraction_field()).kBoundedQuotient(3).dual_k_Schur()
            sage: dks3._khlp_to_dks_on_basis(Partition([2,1]))
            (-t^2-t)*dks3[1, 1, 1] + dks3[2, 1]
            sage: dks3._khlp_to_dks_on_basis(Partition([2,2]))
            (t^3-t^2)*dks3[1, 1, 1, 1] - t*dks3[2, 1, 1] + dks3[2, 2]
            sage: dks3._khlp_to_dks_on_basis(Partition([]))
            dks3[]
            sage: dks3._khlp_to_dks_on_basis(Partition([4,1]))
            0
        """
        Sym = self._kBoundedRing.ambient()
        kB = Sym.kBoundedSubspace(self.k, t=self.t)
        Qp = Sym.hall_littlewood(t=self.t).Qp()
        ks = kB.kschur()
        return sum( Qp(ks(x)).coefficient(la) * self(x) for x in PartitionsGreatestLE(sum(la), self.k))


class AffineSchurFunctions(KBoundedQuotientBasis):
    r"""
    This basis is dual to the `k`-Schur functions at `t=1`.  This realization
    follows the monomial expansion given by Lam [Lam2006]_.

    REFERENCES:

    .. [Lam2006] \T. Lam, Schubert polynomials for the affine Grassmannian, J. Amer.
        Math. Soc., 21 (2008), 259-281.
    """

    def __init__(self, kBoundedRing):
        r"""
        Initialize the ring which is the `k`-Bounded affine Schur quotient basis.

        INPUT:

        - ``kBoundedRing`` -- an element which is of class :class:`KBoundedQuotient`

        EXAMPLES::

            sage: from sage.combinat.sf.k_dual import AffineSchurFunctions
            sage: F = AffineSchurFunctions(SymmetricFunctions(QQ['t']).kBoundedQuotient(4,t=1))
            sage: F
            4-Bounded Quotient of Symmetric Functions over Univariate Polynomial Ring in t over Rational Field with t=1 in the 4-bounded affine Schur basis
            sage: TestSuite(F).run()  # long time (5s on sage.math, 2013)
        """
        KBoundedQuotientBasis.__init__(self, kBoundedRing, 'F')

        from sage.combinat.root_system.weyl_group import WeylGroup
        self._weyl = WeylGroup(['A', kBoundedRing.k, 1])

        km = kBoundedRing.km()
        self.module_morphism(self._F_to_m_on_basis,codomain=km).register_as_coercion() # morphism from affine Schur functions to k-bounded-m
        km.module_morphism(self._m_to_F_on_basis,codomain=self).register_as_coercion() # morphism from k-bounded-m basis to affine-Schur basis

    def _repr_(self):
        """
        TESTS::

            sage: Sym = SymmetricFunctions(QQ)
            sage: F = Sym.kBoundedQuotient(3,t=1).affineSchur()
            sage: F._repr_()
            '3-Bounded Quotient of Symmetric Functions over Rational Field with t=1 in the 3-bounded affine Schur basis'
        """
        return self.realization_of()._repr_() + ' in the %s-bounded affine Schur basis' % (self.k)

    def _F_to_m_on_basis(self, la):
        r"""
        Give the expansion of the affine Schur basis element indexed by ``la`` into
        the monomial basis.

        INPUT:

        - ``la`` -- a `k`-bounded partition

        OUTPUT: a symmetric function in the monomial basis

        EXAMPLES::

            sage: F = SymmetricFunctions(QQ).kBoundedQuotient(3,t=1).affineSchur()
            sage: F._F_to_m_on_basis(Partition([2,1]))
            2*m[1, 1, 1] + m[2, 1]
            sage: F._F_to_m_on_basis(Partition([]))
            m[]
            sage: km = F.realization_of().km()
            sage: km( F[2,2] )
            2*m3[1, 1, 1, 1] + m3[2, 1, 1] + m3[2, 2]
            sage: F._F_to_m_on_basis(Partition([4,1]))
            Traceback (most recent call last):
            ...
            ValueError: the partition must be 3-bounded
        """
        return self._weyl.from_reduced_word(Partition(la).from_kbounded_to_reduced_word(self.k)).stanley_symmetric_function()

    def _m_to_F_on_basis(self, la):
        r"""
        Give the expansion of the `k`-monomial basis element indexed by ``la`` into
        the affine Schur basis.

        INPUT:

        - ``la`` -- a `k`-bounded partition

        OUTPUT: a `k`-bounded quotient symmetric function in the affine Schur basis

        EXAMPLES::

            sage: # needs lrcalc_python
            sage: F = SymmetricFunctions(QQ).kBoundedQuotient(3,t=1).affineSchur()
            sage: F._m_to_F_on_basis(Partition([2,1]))
            -2*F3[1, 1, 1] + F3[2, 1]
            sage: F._m_to_F_on_basis([2,1])
            -2*F3[1, 1, 1] + F3[2, 1]
            sage: F._m_to_F_on_basis(Partition([]))
            F3[]
            sage: F._m_to_F_on_basis(Partition([4,1]))
            Traceback (most recent call last):
            ...
            AssertionError: [4, 1] should be an element of 3-Bounded Partitions
        """
        Sym = self._kBoundedRing.ambient()
        kB = Sym.kBoundedSubspace(self.k, t=1)
        h = kB.khomogeneous()
        ks = kB.kschur()
        return sum( h(ks(x)).coefficient(la) * self(x) for x in PartitionsGreatestLE(sum(la), self.k))
