Ticket #15311: trac_15311-hall_algebras-ts.patch

File trac_15311-hall_algebras-ts.patch, 34.2 KB (added by tscrim, 6 years ago)
  • doc/en/reference/algebras/index.rst

    # HG changeset patch
    # User Travis Scrimshaw <tscrim@ucdavis.edu>
    # Date 1382293123 25200
    # Node ID 3534e1edc6e4fa839de2a021ec349e9e950c47f8
    # Parent 64b71789db04f7566bfea7109274547c0a4ec28b
    Implemented the classical Hall algebra.
    * * *
    trac #15311: new review patch, fixing q=0 case
    
    diff --git a/doc/en/reference/algebras/index.rst b/doc/en/reference/algebras/index.rst
    a b Algebras 
    1818
    1919   sage/algebras/iwahori_hecke_algebra
    2020
     21   sage/algebras/hall_algebra
     22
    2123   sage/algebras/shuffle_algebra
    2224
    2325   sage/algebras/steenrod/steenrod_algebra
  • doc/en/reference/combinat/index.rst

    diff --git a/doc/en/reference/combinat/index.rst b/doc/en/reference/combinat/index.rst
    a b Combinatorics 
    2424   sage/combinat/tamari_lattices
    2525   sage/combinat/e_one_star
    2626   sage/combinat/finite_class
     27   sage/combinat/hall_polynomial
    2728   sage/combinat/integer_list
    2829   sage/combinat/integer_matrices
    2930   sage/combinat/integer_vector
  • sage/algebras/all.py

    diff --git a/sage/algebras/all.py b/sage/algebras/all.py
    a b from iwahori_hecke_algebra import Iwahor 
    3838from affine_nil_temperley_lieb import AffineNilTemperleyLiebTypeA
    3939lazy_import('sage.algebras.nil_coxeter_algebra', 'NilCoxeterAlgebra')
    4040
     41lazy_import('sage.algebras.hall_algebra', 'HallAlgebra')
     42
    4143lazy_import('sage.algebras.shuffle_algebra', 'ShuffleAlgebra')
  • new file sage/algebras/hall_algebra.py

    diff --git a/sage/algebras/hall_algebra.py b/sage/algebras/hall_algebra.py
    new file mode 100644
    - +  
     1r"""
     2Hall Algebras
     3
     4AUTHORS:
     5
     6- Travis Scrimshaw (2013-10-17): Initial version
     7"""
     8
     9#*****************************************************************************
     10#  Copyright (C) 2013 Travis Scrimshaw <tscrim at ucdavis.edu>
     11#
     12#  Distributed under the terms of the GNU General Public License (GPL)
     13#                  http://www.gnu.org/licenses/
     14#*****************************************************************************
     15
     16from sage.misc.misc_c import prod
     17from sage.misc.cachefunc import cached_method
     18from sage.categories.algebras_with_basis import AlgebrasWithBasis
     19from sage.categories.hopf_algebras_with_basis import HopfAlgebrasWithBasis
     20from sage.combinat.partition import Partition, Partitions
     21from sage.combinat.free_module import CombinatorialFreeModule
     22from sage.combinat.hall_polynomial import hall_polynomial
     23from sage.combinat.sf.sf import SymmetricFunctions
     24from sage.rings.all import ZZ
     25
     26def transpose_cmp(x, y):
     27    r"""
     28    Compare partitions ``x`` and ``y`` in transpose dominance order.
     29
     30    We say partitions `\mu` and `\lambda` satisfy `\mu \prec \lambda`
     31    in transpose dominance order if for all `i \geq 1` we have:
     32
     33    .. MATH::
     34
     35        l_1 + 2 l_2 + \cdots + (i-1) l_{i-1} + i(l_i + l_{i+1} + \cdots) \leq
     36        m_1 + 2 m_2 + \cdots + (i-1) m_{i-1} + i(m_i + m_{i+1} + \cdots),
     37
     38    where `l_k` denotes the number of appearances of `k` in
     39    `\lambda`, and `m_k` denotes the number of appearances of `k`
     40    in `\mu`.
     41
     42    Equivalently, `\mu \prec \lambda` if the conjugate of the
     43    partition `\mu` dominates the conjugate of the partition
     44    `\lambda`.
     45
     46    Since this is a partial ordering, we fallback to lex ordering
     47    `\mu <_L \lambda` if we cannot compare in the transpose order.
     48
     49    EXAMPLES::
     50
     51        sage: from sage.algebras.hall_algebra import transpose_cmp
     52        sage: transpose_cmp(Partition([4,3,1]), Partition([3,2,2,1]))
     53        -1
     54        sage: transpose_cmp(Partition([2,2,1]), Partition([3,2]))
     55        1
     56        sage: transpose_cmp(Partition([4,1,1]), Partition([4,1,1]))
     57        0
     58    """
     59    if x == y:
     60        return 0
     61    xexp = x.to_exp()
     62    yexp = y.to_exp()
     63    n = min(len(xexp), len(yexp))
     64    def check(m, l):
     65        s1 = 0
     66        s2 = 0
     67        for i in range(n):
     68            s1 += sum(l[i:])
     69            s2 += sum(m[i:])
     70            if s1 > s2:
     71                return False
     72        return sum(l) <= sum(m)
     73    if check(xexp, yexp):
     74        return 1
     75    if check(yexp, xexp):
     76        return -1
     77    return cmp(x, y)
     78
     79class HallAlgebra(CombinatorialFreeModule):
     80    r"""
     81    The (classical) Hall algebra.
     82
     83    The *(classical) Hall algebra* over a commutative ring `R` with a
     84    parameter `q \in R` is defined to be the free `R`-module with
     85    basis `(I_\lambda)`, where `\lambda` runs over all integer
     86    partitions. The algebra structure is given by a product defined by
     87
     88    .. MATH::
     89
     90        I_\mu \cdot I_\lambda = \sum_\nu P^{\nu}_{\mu, \lambda}(q) I_\nu,
     91
     92    where `P^{\nu}_{\mu, \lambda}` is a Hall polynomial (see
     93    :meth:`~sage.combinat.hall_polynomial.hall_polynomial`). The
     94    unity of this algebra is `I_{\emptyset}`.
     95
     96    The (classical) Hall algebra is also known as the Hall-Steinitz
     97    algebra.
     98
     99    We can define an `R`-algebra isomorphism `\Phi` from the
     100    `R`-algebra of symmetric functions (see
     101    :class:`~sage.combinat.sf.sf.SymmetricFunctions`) to the
     102    (classical) Hall algebra by sending the `r`-th elementary
     103    symmetric function `e_r` to `q^{r(r-1)/2} I_{(1^r)}` for every
     104    positive integer `r`. This isomorphism used to transport the
     105    Hopf algebra structure from the `R`-algebra of symmetric functions
     106    to the Hall algebra, thus making the latter a connected graded
     107    Hopf algebra. If `\lambda` is a partition, then the preimage
     108    of the basis element `I_{\lambda}` under this isomorphism is
     109    `q^{n(\lambda)} P_{\lambda}(x; q^{-1})`, where `P_{\lambda}` denotes
     110    the `\lambda`-th Hall-Littlewood `P`-function, and where
     111    `n(\lambda) = \sum_i (i - 1) \lambda_i`.
     112
     113    See section 2.3 in [Schiffmann]_, and sections II.2 and III.3
     114    in [Macdonald1995]_ (where our `I_{\lambda}` is called `u_{\lambda}`).
     115
     116    .. WARNING::
     117
     118        We could work in a Laurent polynomial ring, but currently Laurent
     119        polynomials do not simplify if possible. Instead we typically must
     120        use the fraction field of `\ZZ[q]`. See :trac:`11726`. ::
     121
     122            sage: R.<q> = LaurentPolynomialRing(ZZ)
     123            sage: H = HallAlgebra(R, q)
     124            sage: I = H.monomial_basis()
     125            sage: H(I[2,1])
     126            H[2, 1] + ((-q^3+1)/(-q+1))*H[1, 1, 1]
     127            sage: H[2]*H[2]
     128            Traceback (most recent call last):
     129            ...
     130            TypeError: unsupported operand parent(s) for '-':
     131             'Hall algebra with q=q over Univariate Laurent Polynomial Ring in q over Integer Ring'
     132             and '<type 'NoneType'>'
     133
     134    EXAMPLES::
     135
     136        sage: R.<q> = ZZ[]
     137        sage: H = HallAlgebra(R, q)
     138        sage: H[2,1]*H[1,1]
     139        H[3, 2] + (q+1)*H[3, 1, 1] + (q^2+q)*H[2, 2, 1] + (q^4+q^3+q^2)*H[2, 1, 1, 1]
     140        sage: H[2]*H[2,1]
     141        H[4, 1] + q*H[3, 2] + (q^2-1)*H[3, 1, 1] + (q^3+q^2)*H[2, 2, 1]
     142        sage: H[3]*H[1,1]
     143        H[4, 1] + q^2*H[3, 1, 1]
     144        sage: H[3]*H[2,1]
     145        H[5, 1] + q*H[4, 2] + (q^2-1)*H[4, 1, 1] + q^3*H[3, 2, 1]
     146
     147    We can rewrite the Hall algebra in terms of monomials of
     148    the elements `I_{(1^r)}`::
     149
     150        sage: I = H.monomial_basis()
     151        sage: H(I[2,1,1])
     152        H[3, 1] + (q+1)*H[2, 2] + (2*q^2+2*q+1)*H[2, 1, 1]
     153         + (q^5+2*q^4+3*q^3+3*q^2+2*q+1)*H[1, 1, 1, 1]
     154        sage: I(H[2,1,1])
     155        I[3, 1] + (-q^3-q^2-q-1)*I[4]
     156
     157    The isomorphism between the Hall algebra and the symmetric
     158    functions described above is implemented as a coercion::
     159
     160        sage: R = PolynomialRing(ZZ, 'q').fraction_field()
     161        sage: q = R.gen()
     162        sage: H = HallAlgebra(R, q)
     163        sage: e = SymmetricFunctions(R).e()
     164        sage: e(H[1,1,1])
     165        1/q^3*e[3]
     166
     167    We can also do computations with any special value of ``q``,
     168    such as `0` or `1` or (most commonly) a prime power. Here
     169    is an example using a prime::
     170
     171        sage: H = HallAlgebra(ZZ, 2)
     172        sage: H[2,1]*H[1,1]
     173        H[3, 2] + 3*H[3, 1, 1] + 6*H[2, 2, 1] + 28*H[2, 1, 1, 1]
     174        sage: H[3,1]*H[2]
     175        H[5, 1] + H[4, 2] + 6*H[3, 3] + 3*H[4, 1, 1] + 8*H[3, 2, 1]
     176        sage: H[2,1,1]*H[3,1]
     177        H[5, 2, 1] + 2*H[4, 3, 1] + 6*H[4, 2, 2] + 7*H[5, 1, 1, 1]
     178         + 19*H[4, 2, 1, 1] + 24*H[3, 3, 1, 1] + 48*H[3, 2, 2, 1]
     179         + 105*H[4, 1, 1, 1, 1] + 224*H[3, 2, 1, 1, 1]
     180        sage: I = H.monomial_basis()
     181        sage: H(I[2,1,1])
     182        H[3, 1] + 3*H[2, 2] + 13*H[2, 1, 1] + 105*H[1, 1, 1, 1]
     183        sage: I(H[2,1,1])
     184        I[3, 1] - 15*I[4]
     185
     186    If `q` is set to `1`, the coercion to the symmetric functions
     187    sends `I_{\lambda}` to `m_{\lambda}`::
     188
     189        sage: H = HallAlgebra(QQ, 1)
     190        sage: H[2,1] * H[2,1]
     191        H[4, 2] + 2*H[3, 3] + 2*H[4, 1, 1] + 2*H[3, 2, 1] + 6*H[2, 2, 2] + 4*H[2, 2, 1, 1]
     192        sage: m = SymmetricFunctions(QQ).m()
     193        sage: m[2,1] * m[2,1]
     194        4*m[2, 2, 1, 1] + 6*m[2, 2, 2] + 2*m[3, 2, 1] + 2*m[3, 3] + 2*m[4, 1, 1] + m[4, 2]
     195        sage: m(H[3,1])
     196        m[3, 1]
     197
     198    We can set `q` to `0` (but should keep in mind that we don't get
     199    the Schur functions this way)::
     200
     201        sage: H = HallAlgebra(QQ, 0)
     202        sage: H[2,1] * H[2,1]
     203        H[4, 2] + H[3, 3] + H[4, 1, 1] - H[3, 2, 1] - H[3, 1, 1, 1]
     204
     205    REFERENCES:
     206
     207    .. [Schiffmann] Oliver Schiffmann. *Lectures on Hall algebras*.
     208       :arxiv:`0611617v2`.
     209    """
     210    def __init__(self, base_ring, q, prefix='H'):
     211        """
     212        Initialize ``self``.
     213
     214        EXAMPLES::
     215
     216            sage: R.<q> = ZZ[]
     217            sage: H = HallAlgebra(R, q)
     218            sage: TestSuite(H).run()
     219            sage: R = PolynomialRing(ZZ, 'q').fraction_field()
     220            sage: q = R.gen()
     221            sage: H = HallAlgebra(R, q)
     222            sage: TestSuite(H).run()
     223        """
     224        self._q = q
     225        try:
     226            q_inverse = q**-1
     227            if not q_inverse in base_ring:
     228                hopf_structure = False
     229            else:
     230                hopf_structure = True
     231        except StandardError:
     232            hopf_structure = False
     233        if hopf_structure:
     234            category = HopfAlgebrasWithBasis(base_ring)
     235        else:
     236            category = AlgebrasWithBasis(base_ring)
     237        CombinatorialFreeModule.__init__(self, base_ring, Partitions(),
     238                                         prefix=prefix, bracket=False,
     239                                         monomial_cmp=transpose_cmp,
     240                                         category=category)
     241
     242        # Coercions
     243        I = self.monomial_basis()
     244        M = I.module_morphism(I._to_natural_on_basis, codomain=self,
     245                              triangular='upper', unitriangular=True,
     246                              inverse_on_support=lambda x: x.conjugate())
     247        M.register_as_coercion()
     248        (~M).register_as_coercion()
     249
     250    def _repr_(self):
     251        """
     252        Return a string representation of ``self``.
     253
     254        EXAMPLES::
     255
     256            sage: R.<q> = ZZ[]
     257            sage: HallAlgebra(R, q)
     258            Hall algebra with q=q over Univariate Polynomial Ring in q over Integer Ring
     259        """
     260        return "Hall algebra with q={} over {}".format(self._q, self.base_ring())
     261
     262    def one_basis(self):
     263        """
     264        Return the index of the basis element `1`.
     265
     266        EXAMPLES::
     267
     268            sage: R.<q> = ZZ[]
     269            sage: H = HallAlgebra(R, q)
     270            sage: H.one_basis()
     271            []
     272        """
     273        return Partition([])
     274
     275    def product_on_basis(self, mu, la):
     276        """
     277        Return the product of the two basis elements indexed by ``mu``
     278        and ``la``.
     279
     280        EXAMPLES::
     281
     282            sage: R.<q> = ZZ[]
     283            sage: H = HallAlgebra(R, q)
     284            sage: H.product_on_basis(Partition([1,1]), Partition([1]))
     285            H[2, 1] + (q^2+q+1)*H[1, 1, 1]
     286            sage: H.product_on_basis(Partition([2,1]), Partition([1,1]))
     287            H[3, 2] + (q+1)*H[3, 1, 1] + (q^2+q)*H[2, 2, 1] + (q^4+q^3+q^2)*H[2, 1, 1, 1]
     288            sage: H.product_on_basis(Partition([3,2]), Partition([2,1]))
     289            H[5, 3] + (q+1)*H[4, 4] + q*H[5, 2, 1] + (2*q^2-1)*H[4, 3, 1]
     290             + (q^3+q^2)*H[4, 2, 2] + (q^4+q^3)*H[3, 3, 2]
     291             + (q^4-q^2)*H[4, 2, 1, 1] + (q^5+q^4-q^3-q^2)*H[3, 3, 1, 1]
     292             + (q^6+q^5)*H[3, 2, 2, 1]
     293            sage: H.product_on_basis(Partition([3,1,1]), Partition([2,1]))
     294            H[5, 2, 1] + q*H[4, 3, 1] + (q^2-1)*H[4, 2, 2]
     295             + (q^3+q^2)*H[3, 3, 2] + (q^2+q+1)*H[5, 1, 1, 1]
     296             + (2*q^3+q^2-q-1)*H[4, 2, 1, 1] + (q^4+2*q^3+q^2)*H[3, 3, 1, 1]
     297             + (q^5+q^4)*H[3, 2, 2, 1] + (q^6+q^5+q^4-q^2-q-1)*H[4, 1, 1, 1, 1]
     298             + (q^7+q^6+q^5)*H[3, 2, 1, 1, 1]
     299        """
     300        # Check conditions for multiplying by 1
     301        if len(mu) == 0:
     302            return self.monomial(la)
     303        if len(la) == 0:
     304            return self.monomial(mu)
     305
     306        if all(x == 1 for x in la):
     307            return self.sum_of_terms([(p, hall_polynomial(p, mu, la, self._q))
     308                                      for p in Partitions(sum(mu) + len(la))],
     309                                     distinct=True)
     310
     311        I = HallAlgebraMonomials(self.base_ring(), self._q)
     312        mu = self.monomial(mu)
     313        la = self.monomial(la)
     314        return self(I(mu) * I(la))
     315
     316    def coproduct_on_basis(self, la):
     317        """
     318        Return the coproduct of the basis element indexed by ``la``.
     319
     320        EXAMPLES::
     321
     322            sage: R = PolynomialRing(ZZ, 'q').fraction_field()
     323            sage: q = R.gen()
     324            sage: H = HallAlgebra(R, q)
     325            sage: H.coproduct_on_basis(Partition([1,1]))
     326            H[] # H[1, 1] + 1/q*H[1] # H[1] + H[1, 1] # H[]
     327            sage: H.coproduct_on_basis(Partition([2]))
     328            H[] # H[2] + ((q-1)/q)*H[1] # H[1] + H[2] # H[]
     329            sage: H.coproduct_on_basis(Partition([2,1]))
     330            H[] # H[2, 1] + ((q^2-1)/q^2)*H[1] # H[1, 1] + 1/q*H[1] # H[2]
     331             + ((q^2-1)/q^2)*H[1, 1] # H[1] + 1/q*H[2] # H[1] + H[2, 1] # H[]
     332        """
     333        S = self.tensor_square()
     334        if all(x == 1 for x in la):
     335            n = len(la)
     336            return S.sum_of_terms([( (Partition([1]*r), Partition([1]*(n-r))), self._q**(-r*(n-r)) )
     337                                   for r in range(n+1)], distinct=True)
     338
     339        I = HallAlgebraMonomials(self.base_ring(), self._q)
     340        la = self.monomial(la)
     341        return S(I(la).coproduct())
     342
     343    def antipode_on_basis(self, la):
     344        """
     345        Return the antipode of the basis element indexed by ``la``.
     346
     347        EXAMPLES::
     348
     349            sage: R = PolynomialRing(ZZ, 'q').fraction_field()
     350            sage: q = R.gen()
     351            sage: H = HallAlgebra(R, q)
     352            sage: H.antipode_on_basis(Partition([1,1]))
     353            1/q*H[2] + 1/q*H[1, 1]
     354            sage: H.antipode_on_basis(Partition([2]))
     355            -1/q*H[2] + ((q^2-1)/q)*H[1, 1]
     356        """
     357        if all(x == 1 for x in la):
     358            r = len(la)
     359            q = (-1)**r * self._q**(-r*(r-1)/2)
     360            return self._from_dict({p: q for p in Partitions(r)})
     361
     362        I = HallAlgebraMonomials(self.base_ring(), self._q)
     363        return self(I(self.monomial(la)).antipode())
     364
     365    def counit(self, x):
     366        """
     367        Return the counit of the element ``x``.
     368
     369        EXAMPLES::
     370
     371            sage: R = PolynomialRing(ZZ, 'q').fraction_field()
     372            sage: q = R.gen()
     373            sage: H = HallAlgebra(R, q)
     374            sage: H.counit(H.an_element())
     375            2
     376        """
     377        return x.coefficient(self.one_basis())
     378
     379    def monomial_basis(self):
     380        """
     381        Return the basis of the Hall algebra given by monomials in the
     382        `I_{(1^r)}`.
     383
     384        EXAMPLES::
     385
     386            sage: R.<q> = ZZ[]
     387            sage: H = HallAlgebra(R, q)
     388            sage: H.monomial_basis()
     389            Hall algebra with q=q over Univariate Polynomial Ring in q over
     390             Integer Ring in the monomial basis
     391        """
     392        return HallAlgebraMonomials(self.base_ring(), self._q)
     393
     394    def __getitem__(self, la):
     395        """
     396        Return the basis element indexed by ``la``.
     397
     398        EXAMPLES::
     399
     400            sage: R.<q> = ZZ[]
     401            sage: H = HallAlgebra(R, q)
     402            sage: H[[]]
     403            H[]
     404            sage: H[2]
     405            H[2]
     406            sage: H[[2]]
     407            H[2]
     408            sage: H[2,1]
     409            H[2, 1]
     410            sage: H[Partition([2,1])]
     411            H[2, 1]
     412            sage: H[(2,1)]
     413            H[2, 1]
     414        """
     415        if la in ZZ:
     416            return self.monomial(Partition([la]))
     417        return self.monomial(Partition(la))
     418
     419    class Element(CombinatorialFreeModule.Element):
     420        def scalar(self, y):
     421            r"""
     422            Return the scalar product of ``self`` and ``y``.
     423
     424            The scalar product is given by
     425
     426            .. MATH::
     427
     428                (I_{\lambda}, I_{\mu}) = \delta_{\lambda,\mu}
     429                \frac{1}{a_{\lambda}},
     430
     431            where `a_{\lambda}` is given by
     432
     433            .. MATH::
     434
     435                a_{\lambda} = q^{|\lambda| + 2 n(\lambda)} \prod_k
     436                \prod_{i=1}^{l_k} (1 - q^{-i})
     437
     438            where `n(\lambda) = \sum_i (i - 1) \lambda_i` and
     439            `\lambda = (1^{l_1}, 2^{l_2}, \ldots, m^{l_m})`.
     440
     441            Note that `a_{\lambda}` can be interpreted as the number
     442            of automorphisms of a certain object in a category
     443            corresponding to `\lambda`. See Lemma 2.8 in [Schiffmann]_
     444            for details.
     445
     446            EXAMPLES::
     447
     448                sage: R.<q> = ZZ[]
     449                sage: H = HallAlgebra(R, q)
     450                sage: H[1].scalar(H[1])
     451                1/(q - 1)
     452                sage: H[2].scalar(H[2])
     453                1/(q^2 - q)
     454                sage: H[2,1].scalar(H[2,1])
     455                1/(q^5 - 2*q^4 + q^3)
     456                sage: H[1,1,1,1].scalar(H[1,1,1,1])
     457                1/(q^16 - q^15 - q^14 + 2*q^11 - q^8 - q^7 + q^6)
     458                sage: H.an_element().scalar(H.an_element())
     459                (4*q^2 + 9)/(q^2 - q)
     460            """
     461            q = self.parent()._q
     462            f = lambda la: ~( q**(sum(la) + 2*la.weighted_size())
     463                              * prod(prod((1 - q**-i) for i in range(1,k+1))
     464                                     for k in la.to_exp()) )
     465            y = self.parent()(y)
     466            ret = q.parent().zero()
     467            for mx, cx in self:
     468                cy = y.coefficient(mx)
     469                if cy != 0:
     470                    ret += cx * cy * f(mx)
     471            return ret
     472
     473class HallAlgebraMonomials(CombinatorialFreeModule):
     474    r"""
     475    The classical Hall algebra given in terms of monomials in the
     476    `I_{(1^r)}`.
     477
     478    We first associate a monomial `I_{(1^{r_1})} I_{(1^{r_2})} \cdots
     479    I_{(1^{r_k})}` with the composition `(r_1, r_2, \ldots, r_k)`. However
     480    since `I_{(1^r)}` commutes with `I_{(1^s)}`, the basis is indexed
     481    by partitions.
     482
     483    EXAMPLES:
     484
     485    We could work in a Laurent polynomial ring, but pending :trac:`11726`,
     486    we use the fraction field of `\ZZ[q]` instead.
     487
     488        sage: R = PolynomialRing(ZZ, 'q').fraction_field()
     489        sage: q = R.gen()
     490        sage: H = HallAlgebra(R, q)
     491        sage: I = H.monomial_basis()
     492
     493    We check that the basis conversions are mutually inverse::
     494
     495        sage: all(H(I(H[p])) == H[p] for i in range(7) for p in Partitions(i))
     496        True
     497        sage: all(I(H(I[p])) == I[p] for i in range(7) for p in Partitions(i))
     498        True
     499
     500    We can also convert to the symmetric functions. The natural basis
     501    corresponds to the Hall-Littlewood basis (up to a renormalization and
     502    an inversion of the `q` parameter), and this basis corresponds
     503    to the elementary basis (up to a renormalization)::
     504
     505        sage: Sym = SymmetricFunctions(R)
     506        sage: e = Sym.e()
     507        sage: e(I[2,1])
     508        1/q*e[2, 1]
     509        sage: e(I[4,2,2,1])
     510        1/q^8*e[4, 2, 2, 1]
     511        sage: HLP = Sym.hall_littlewood(q).P()
     512        sage: H(I[2,1])
     513        H[2, 1] + (q^2+q+1)*H[1, 1, 1]
     514        sage: HLP(e[2,1])
     515        (q^2+q+1)*HLP[1, 1, 1] + HLP[2, 1]
     516        sage: all( e(H[lam]) == q**-sum([i * x for i, x in enumerate(lam)])
     517        ....:          * e(HLP[lam]).map_coefficients(lambda p: p(q**(-1)))
     518        ....:      for lam in Partitions(4) )
     519        True
     520
     521    We can also do computations using a prime power::
     522
     523        sage: H = HallAlgebra(ZZ, 3)
     524        sage: I = H.monomial_basis()
     525        sage: I[2,1]*I[1,1]
     526        I[2, 1, 1, 1]
     527        sage: H(_)
     528        H[4, 1] + 7*H[3, 2] + 37*H[3, 1, 1] + 136*H[2, 2, 1]
     529         + 1495*H[2, 1, 1, 1] + 62920*H[1, 1, 1, 1, 1]
     530    """
     531    def __init__(self, base_ring, q, prefix='I'):
     532        """
     533        Initialize ``self``.
     534
     535        EXAMPLES::
     536
     537            sage: R.<q> = ZZ[]
     538            sage: I = HallAlgebra(R, q).monomial_basis()
     539            sage: TestSuite(I).run()
     540            sage: R = PolynomialRing(ZZ, 'q').fraction_field()
     541            sage: q = R.gen()
     542            sage: I = HallAlgebra(R, q).monomial_basis()
     543            sage: TestSuite(I).run()
     544        """
     545        self._q = q
     546        try:
     547            q_inverse = q**-1
     548            if not q_inverse in base_ring:
     549                hopf_structure = False
     550            else:
     551                hopf_structure = True
     552        except StandardError:
     553            hopf_structure = False
     554        if hopf_structure:
     555            category = HopfAlgebrasWithBasis(base_ring)
     556        else:
     557            category = AlgebrasWithBasis(base_ring)
     558        CombinatorialFreeModule.__init__(self, base_ring, Partitions(),
     559                                         prefix=prefix, bracket=False,
     560                                         category=category)
     561
     562        # Coercions
     563        if hopf_structure:
     564            e = SymmetricFunctions(base_ring).e()
     565            f = lambda la: q**sum(-(r*(r-1)/2) for r in la)
     566            M = self.module_morphism(diagonal=f, codomain=e)
     567            M.register_as_coercion()
     568            (~M).register_as_coercion()
     569
     570    @cached_method
     571    def _to_natural_on_basis(self, a):
     572        """
     573        Return the basis element indexed by ``a`` converted into
     574        the partition basis.
     575
     576        EXAMPLES::
     577
     578            sage: R.<q> = ZZ[]
     579            sage: I = HallAlgebra(R, q).monomial_basis()
     580            sage: I._to_natural_on_basis(Partition([3]))
     581            H[1, 1, 1]
     582            sage: I._to_natural_on_basis(Partition([2,1,1]))
     583            H[3, 1] + (q+1)*H[2, 2] + (2*q^2+2*q+1)*H[2, 1, 1]
     584             + (q^5+2*q^4+3*q^3+3*q^2+2*q+1)*H[1, 1, 1, 1]
     585        """
     586        H = HallAlgebra(self.base_ring(), self._q)
     587        return reduce(lambda cur,r: cur * H.monomial(Partition([1]*r)), a, H.one())
     588
     589    def _repr_(self):
     590        """
     591        Return a string representation of ``self``.
     592
     593        EXAMPLES::
     594
     595            sage: R.<q> = ZZ[]
     596            sage: HallAlgebra(R, q).monomial_basis()
     597            Hall algebra with q=q over Univariate Polynomial Ring in q over
     598             Integer Ring in the monomial basis
     599        """
     600        return "Hall algebra with q={} over {} in the monomial basis".format(self._q, self.base_ring())
     601
     602    def one_basis(self):
     603        """
     604        Return the index of the basis element `1`.
     605
     606        EXAMPLES::
     607
     608            sage: R.<q> = ZZ[]
     609            sage: I = HallAlgebra(R, q).monomial_basis()
     610            sage: I.one_basis()
     611            []
     612        """
     613        return Partition([])
     614
     615    def product_on_basis(self, a, b):
     616        """
     617        Return the product of the two basis elements indexed by ``a``
     618        and ``b``.
     619
     620        EXAMPLES::
     621
     622            sage: R.<q> = ZZ[]
     623            sage: I = HallAlgebra(R, q).monomial_basis()
     624            sage: I.product_on_basis(Partition([4,2,1]), Partition([3,2,1]))
     625            I[4, 3, 2, 2, 1, 1]
     626        """
     627        return self.monomial(Partition(sorted(list(a) + list(b), reverse=True)))
     628
     629    def coproduct_on_basis(self, a):
     630        """
     631        Return the coproduct of the basis element indexed by ``a``.
     632
     633        EXAMPLES::
     634
     635            sage: R = PolynomialRing(ZZ, 'q').fraction_field()
     636            sage: q = R.gen()
     637            sage: I = HallAlgebra(R, q).monomial_basis()
     638            sage: I.coproduct_on_basis(Partition([1]))
     639            I[] # I[1] + I[1] # I[]
     640            sage: I.coproduct_on_basis(Partition([2]))
     641            I[] # I[2] + 1/q*I[1] # I[1] + I[2] # I[]
     642            sage: I.coproduct_on_basis(Partition([2,1]))
     643            I[] # I[2, 1] + 1/q*I[1] # I[1, 1] + I[1] # I[2]
     644             + 1/q*I[1, 1] # I[1] + I[2] # I[1] + I[2, 1] # I[]
     645        """
     646        S = self.tensor_square()
     647        return S.prod(S.sum_of_terms([( (Partition([r]), Partition([n-r]) ), self._q**(-r*(n-r)) )
     648                                      for r in range(n+1)], distinct=True) for n in a)
     649
     650    def antipode_on_basis(self, a):
     651        """
     652        Return the antipode of the basis element indexed by ``a``.
     653
     654        EXAMPLES::
     655
     656            sage: R = PolynomialRing(ZZ, 'q').fraction_field()
     657            sage: q = R.gen()
     658            sage: I = HallAlgebra(R, q).monomial_basis()
     659            sage: I.antipode_on_basis(Partition([1]))
     660            -I[1]
     661            sage: I.antipode_on_basis(Partition([2]))
     662            1/q*I[1, 1] - I[2]
     663            sage: I.antipode_on_basis(Partition([2,1]))
     664            -1/q*I[1, 1, 1] + I[2, 1]
     665        """
     666        H = HallAlgebra(self.base_ring(), self._q)
     667        cur = self.one()
     668        for r in a:
     669            q = (-1)**r * self._q**(-r*(r-1)/2)
     670            cur *= self(H._from_dict({p: q for p in Partitions(r)}))
     671        return cur
     672
     673    def counit(self, x):
     674        """
     675        Return the counit of the element ``x``.
     676
     677        EXAMPLES::
     678
     679            sage: R = PolynomialRing(ZZ, 'q').fraction_field()
     680            sage: q = R.gen()
     681            sage: I = HallAlgebra(R, q).monomial_basis()
     682            sage: I.counit(I.an_element())
     683            2
     684        """
     685        return x.coefficient(self.one_basis())
     686
     687    def __getitem__(self, a):
     688        """
     689        Return the basis element indexed by ``a``.
     690
     691        EXAMPLES::
     692
     693            sage: R.<q> = ZZ[]
     694            sage: I = HallAlgebra(R, q).monomial_basis()
     695            sage: I[3,1,1] + 3*I[1,1]
     696            3*I[1, 1] + I[3, 1, 1]
     697            sage: I[Partition([3,2,2])]
     698            I[3, 2, 2]
     699            sage: I[2]
     700            I[2]
     701            sage: I[[2]]
     702            I[2]
     703            sage: I[[]]
     704            I[]
     705        """
     706        if a in ZZ:
     707            return self.monomial(Partition([a]))
     708        return self.monomial(Partition(a))
     709
     710    class Element(CombinatorialFreeModule.Element):
     711        def scalar(self, y):
     712            r"""
     713            Return the scalar product of ``self`` and ``y``.
     714
     715            The scalar product is computed by converting into the
     716            natural basis.
     717
     718            EXAMPLES::
     719
     720                sage: R.<q> = ZZ[]
     721                sage: I = HallAlgebra(R, q).monomial_basis()
     722                sage: I[1].scalar(I[1])
     723                1/(q - 1)
     724                sage: I[2].scalar(I[2])
     725                1/(q^4 - q^3 - q^2 + q)
     726                sage: I[2,1].scalar(I[2,1])
     727                (2*q + 1)/(q^6 - 2*q^5 + 2*q^3 - q^2)
     728                sage: I[1,1,1,1].scalar(I[1,1,1,1])
     729                24/(q^4 - 4*q^3 + 6*q^2 - 4*q + 1)
     730                sage: I.an_element().scalar(I.an_element())
     731                (4*q^4 - 4*q^2 + 9)/(q^4 - q^3 - q^2 + q)
     732            """
     733            H = HallAlgebra(self.parent().base_ring(), self.parent()._q)
     734            return H(self).scalar(H(y))
     735
  • new file sage/combinat/hall_polynomial.py

    diff --git a/sage/combinat/hall_polynomial.py b/sage/combinat/hall_polynomial.py
    new file mode 100644
    - +  
     1r"""
     2Hall Polynomials
     3"""
     4#*****************************************************************************
     5#       Copyright (C) 2013 Travis Scrimshaw <tscrim at ucdavis.edu>,
     6#
     7#  Distributed under the terms of the GNU General Public License (GPL)
     8#
     9#    This code is distributed in the hope that it will be useful,
     10#    but WITHOUT ANY WARRANTY; without even the implied warranty of
     11#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     12#    General Public License for more details.
     13#
     14#  The full text of the GPL is available at:
     15#
     16#                  http://www.gnu.org/licenses/
     17#*****************************************************************************
     18
     19from sage.misc.misc import prod
     20from sage.rings.all import ZZ
     21from sage.combinat.partition import Partition
     22from sage.combinat.q_analogues import q_binomial
     23
     24def hall_polynomial(nu, mu, la, q=None):
     25    r"""
     26    Return the (classical) Hall polynomial `P^{\nu}_{\mu,\lambda}`
     27    (where `\nu`, `\mu` and `\lambda` are the inputs ``nu``, ``mu``
     28    and ``la``).
     29
     30    Let `\nu,\mu,\lambda` be partitions. The Hall polynomial
     31    `P^{\nu}_{\mu,\lambda}(q)` (in the indeterminate `q`) is defined
     32    as follows: Specialize `q` to a prime power, and consider the
     33    category of `\GF{q}`-vector spaces with a distinguished
     34    nilpotent endomorphism. The morphisms in this category shall be
     35    the linear maps commuting with the distinguished endomorphisms.
     36    The *type* of an object in the category will be the Jordan type
     37    of the distinguished endomorphism; this is a partition. Now, if
     38    `N` is any fixed object of type `\nu` in this category, then
     39    the polynomial `P^{\nu}_{\mu,\lambda}(q)` specialized at the
     40    prime power `q` counts the number of subobjects `L` of `N` having
     41    type `\lambda` such that the quotient object `N / L` has type
     42    `\mu`. This determines the values of the polynomial
     43    `P^{\nu}_{\mu,\lambda}` at infinitely many points (namely, at all
     44    prime powers), and hence `P^{\nu}_{\mu,\lambda}` is uniquely
     45    determined. The degree of this polynomial is at most
     46    `n(\nu) - n(\lambda) - n(\mu)`, where
     47    `n(\kappa) = \sum_i (i-1) \kappa_i` for every partition `\kappa`.
     48    (If this is negative, then the polynomial is zero.)
     49
     50    These are the structure coefficients of the
     51    :class:`(classical) Hall algebra <HallAlgebra>`.
     52
     53    If `\lvert \nu \rvert \neq \lvert \mu \rvert + \lvert \lambda \rvert`,
     54    then we have `P^{\nu}_{\mu,\lambda} = 0`. More generally, if the
     55    Littlewood-Richardson coefficient `c^{\nu}_{\mu,\lambda}`
     56    vanishes, then `P^{\nu}_{\mu,\lambda} = 0`.
     57
     58    The Hall polynomials satisfy the symmetry property
     59    `P^{\nu}_{\mu,\lambda} = P^{\nu}_{\lambda,\mu}`.
     60
     61    ALGORITHM:
     62
     63    If `\lambda = (1^r)` and
     64    `\lvert \nu \rvert = \lvert \mu \rvert + \lvert \lambda \rvert`,
     65    then we compute `P^{\nu}_{\mu,\lambda}` as follows (cf. Example 2.4
     66    in [Schiffmann]_):
     67
     68    First, write `\nu = (1^{l_1}, 2^{l_2}, \ldots, n^{l_n})`, and
     69    define a sequence `r = r_0 \geq r_1 \geq \cdots \geq r_n` such that
     70
     71    .. MATH::
     72
     73        \mu = \left( 1^{l_1 - r_0 + 2r_1 - r_2}, 2^{l_2 - r_1 + 2r_2 - r_3},
     74        \ldots , (n-1)^{l_{n-1} - r_{n-2} + 2r_{n-1} - r_n},
     75        n^{l_n - r_{n-1} + r_n} \right).
     76
     77    Thus if `\mu = (1^{m_1}, \ldots, n^{m_n})`, we have the following system
     78    of equations:
     79
     80    .. MATH::
     81
     82        \begin{aligned}
     83        m_1 & = l_1 - r + 2r_1 - r_2,
     84        \\ m_2 & = l_2 - r_1 + 2r_2 - r_3,
     85        \\ & \vdots ,
     86        \\ m_{n-1} & = l_{n-1} - r_{n-2} + 2r_{n-1} - r_n,
     87        \\ m_n & = l_n - r_{n-1} + r_n
     88        \end{aligned}
     89
     90    and solving for `r_i` and back substituting we obtain the equations:
     91
     92    .. MATH::
     93
     94        \begin{aligned}
     95        r_n & = r_{n-1} + m_n - l_n,
     96        \\ r_{n-1} & = r_{n-2} + m_{n-1} - l_{n-1} + m_n - l_n,
     97        \\ & \vdots ,
     98        \\ r_1 & = r + \sum_{k=1}^n (m_k - l_k),
     99        \end{aligned}
     100
     101    or in general we have the recursive equation:
     102
     103    .. MATH::
     104
     105        r_i = r_{i-1} + \sum_{k=i}^n (m_k - l_k).
     106
     107    This, combined with the condition that `r_0 = r`, determines the
     108    `r_i` uniquely (recursively). Next we define
     109
     110    .. MATH::
     111
     112        t = (r_{n-2} - r_{n-1})(l_n - r_{n-1})
     113        + (r_{n-3} - r_{n-2})(l_{n-1} + l_n - r_{n-2}) + \cdots
     114        + (r_0 - r_1)(l_2 + \cdots + l_n - r_1),
     115
     116    and with these notations we have
     117
     118    .. MATH::
     119
     120        P^{\nu}_{\mu,(1^r)} = q^t \binom{l_n}{r_{n-1}}_q
     121        \binom{l_{n-1}}{r_{n-2} - r_{n-1}}_q \cdots \binom{l_1}{r_0 - r_1}_q.
     122
     123    To compute `P^{\nu}_{\mu,\lambda}` in general, we compute the product
     124    `I_{\mu} I_{\lambda}` in the Hall algebra and return the coefficient of
     125    `I_{\nu}`.
     126
     127    EXAMPLES::
     128
     129        sage: from sage.combinat.hall_polynomial import hall_polynomial
     130        sage: hall_polynomial([1,1],[1],[1])
     131        q + 1
     132        sage: hall_polynomial([2],[1],[1])
     133        1
     134        sage: hall_polynomial([2,1],[2],[1])
     135        q
     136        sage: hall_polynomial([2,2,1],[2,1],[1,1])
     137        q^2 + q
     138        sage: hall_polynomial([2,2,2,1],[2,2,1],[1,1])
     139        q^4 + q^3 + q^2
     140        sage: hall_polynomial([3,2,2,1], [3,2], [2,1])
     141        q^6 + q^5
     142        sage: hall_polynomial([4,2,1,1], [3,1,1], [2,1])
     143        2*q^3 + q^2 - q - 1
     144        sage: hall_polynomial([4,2], [2,1], [2,1], 0)
     145        1
     146    """
     147    if q is None:
     148        q = ZZ['q'].gen()
     149    R = q.parent()
     150
     151    # Make sure they are partitions
     152    nu = Partition(nu)
     153    mu = Partition(mu)
     154    la = Partition(la)
     155
     156    if sum(nu) != sum(mu) + sum(la):
     157        return R.zero()
     158
     159    if all(x == 1 for x in la):
     160        r = [len(la)]   # r will be [r_0, r_1, ..., r_n].
     161        exp_nu = nu.to_exp()  # exp_nu == [l_1, l_2, ..., l_n].
     162        exp_mu = mu.to_exp()  # exp_mu == [m_1, m_2, ..., m_n].
     163        n = max(len(exp_nu), len(exp_mu))
     164        for k in range(n):
     165            r.append(r[-1] + sum(exp_mu[k:]) - sum(exp_nu[k:]))
     166        # Now, r is [r_0, r_1, ..., r_n].
     167        exp_nu += [0]*(n - len(exp_nu)) # Pad with 0's until it has length n
     168        # Note that all -1 for exp_nu is due to indexing
     169        t = sum((r[k-2] - r[k-1])*(sum(exp_nu[k-1:]) - r[k-1]) for k in range(2,n+1))
     170        if t < 0:
     171            # This case needs short-circuiting, since otherwise q**-t
     172            # might throw an exception if q is non-invertible.
     173            return R.zero()
     174        return q**t * q_binomial(exp_nu[n-1], r[n-1], q) \
     175               * prod([q_binomial(exp_nu[k-1], r[k-1] - r[k], q)
     176                       for k in range(1, n)], R.one())
     177
     178    from sage.algebras.hall_algebra import HallAlgebra
     179    H = HallAlgebra(R, q)
     180    return (H[mu]*H[la]).coefficient(nu)
     181