Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
""" Generic dual bases symmetric functions """ #***************************************************************************** # Copyright (C) 2007 Mike Hansen <mhansen@gmail.com> # 2012 Mike Zabrocki <mike.zabrocki@gmail.com> # # 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: # # http://www.gnu.org/licenses/ #*****************************************************************************
r""" Generic dual basis of a basis of symmetric functions.
INPUT:
- ``dual_basis`` -- a basis of the ring of symmetric functions
- ``scalar`` -- A function `z` on partitions which determines the scalar product on the power sum basis by `\langle p_{\mu}, p_{\mu} \rangle = z(\mu)`. (Independently on the function chosen, the power sum basis will always be orthogonal; the function ``scalar`` only determines the norms of the basis elements.) This defaults to the function ``zee`` defined in ``sage.combinat.sf.sfa``, that is, the function is defined by:
.. MATH::
\lambda \mapsto \prod_{i = 1}^\infty m_i(\lambda)! i^{m_i(\lambda)}`,
where `m_i(\lambda)` means the number of times `i` appears in `\lambda`. This default function gives the standard Hall scalar product on the ring of symmetric functions.
- ``scalar_name`` -- (default: the empty string) a string giving a description of the scalar product specified by the parameter ``scalar``
- ``basis_name`` -- (optional) a string to serve as name for the basis to be generated (such as "forgotten" in "the forgotten basis"); don't set it to any of the already existing basis names (such as ``homogeneous``, ``monomial``, ``forgotten``, etc.).
- ``prefix`` -- (default: ``'d'`` and the prefix for ``dual_basis``) a string to use as the symbol for the basis
OUTPUT:
The basis of the ring of symmetric functions dual to the basis ``dual_basis`` with respect to the scalar product determined by ``scalar``.
EXAMPLES::
sage: e = SymmetricFunctions(QQ).e() sage: f = e.dual_basis(prefix = "m", basis_name="Forgotten symmetric functions"); f Symmetric Functions over Rational Field in the Forgotten symmetric functions basis sage: TestSuite(f).run(elements = [f[1,1]+2*f[2], f[1]+3*f[1,1]]) sage: TestSuite(f).run() # long time (11s on sage.math, 2011)
This class defines canonical coercions between ``self`` and ``self^*``, as follow:
Lookup for the canonical isomorphism from ``self`` to `P` (=powersum), and build the adjoint isomorphism from `P^*` to ``self^*``. Since `P` is self-adjoint for this scalar product, derive an isomorphism from `P` to ``self^*``, and by composition with the above get an isomorphism from ``self`` to ``self^*`` (and similarly for the isomorphism ``self^*`` to ``self``).
This should be striped down to just (auto?) defining canonical isomorphism by adjunction (as in MuPAD-Combinat), and let the coercion handle the rest.
Inversions may not be possible if the base ring is not a field::
sage: m = SymmetricFunctions(ZZ).m() sage: h = m.dual_basis(lambda x: 1) sage: h[2,1] Traceback (most recent call last): ... TypeError: no conversion of this rational to integer
By transitivity, this defines indirect coercions to and from all other bases::
sage: s = SymmetricFunctions(QQ['t'].fraction_field()).s() sage: t = QQ['t'].fraction_field().gen() sage: zee_hl = lambda x: x.centralizer_size(t=t) sage: S = s.dual_basis(zee_hl) sage: S(s([2,1])) (-t/(t^5-2*t^4+t^3-t^2+2*t-1))*d_s[1, 1, 1] + ((-t^2-1)/(t^5-2*t^4+t^3-t^2+2*t-1))*d_s[2, 1] + (-t/(t^5-2*t^4+t^3-t^2+2*t-1))*d_s[3]
TESTS:
Regression test for :trac:`12489`. This ticket improving equality test revealed that the conversion back from the dual basis did not strip cancelled terms from the dictionary::
sage: y = e[1, 1, 1, 1] - 2*e[2, 1, 1] + e[2, 2] sage: sorted(f.element_class(f, dual = y)) [([1, 1, 1, 1], 6), ([2, 1, 1], 2), ([2, 2], 1)]
"""
# Set up the cache
# cache for the coordinates of the elements # of ``dual_basis`` with respect to ``self`` # cache for the coordinates of the elements # of ``self`` with respect to ``dual_basis`` # cache for transition matrices which contain the coordinates of # the elements of ``dual_basis`` with respect to ``self`` # cache for transition matrices which contain the coordinates of # the elements of ``self`` with respect to ``dual_basis``
basis_name = basis_name, prefix = prefix)
# temporary until Hom(GradedHopfAlgebrasWithBasis work better)
""" Coerce an element of the dual of ``self`` canonically into ``self``.
INPUT:
- ``x`` -- an element in the dual basis of ``self``
OUTPUT:
- returns ``x`` expressed in the basis ``self``
EXAMPLES::
sage: m = SymmetricFunctions(QQ).monomial() sage: zee = sage.combinat.sf.sfa.zee sage: h = m.dual_basis(scalar=zee) sage: h._dual_to_self(m([2,1]) + 3*m[1,1,1]) d_m[1, 1, 1] - d_m[2, 1] sage: hh = m.realization_of().h() sage: h._dual_to_self(m(hh([2,2,2]))) d_m[2, 2, 2]
:: Note that the result is not correct if ``x`` is not an element of the dual basis of ``self``
sage: h._dual_to_self(m([2,1])) -2*d_m[1, 1, 1] + 5*d_m[2, 1] - 3*d_m[3] sage: h._dual_to_self(hh([2,1])) -2*d_m[1, 1, 1] + 5*d_m[2, 1] - 3*d_m[3]
This is for internal use only. Please use instead::
sage: h(m([2,1]) + 3*m[1,1,1]) d_m[1, 1, 1] - d_m[2, 1] """
""" Coerce an element of ``self`` canonically into the dual.
INPUT:
- ``x`` -- an element of ``self``
OUTPUT:
- returns ``x`` expressed in the dual basis
EXAMPLES::
sage: m = SymmetricFunctions(QQ).monomial() sage: zee = sage.combinat.sf.sfa.zee sage: h = m.dual_basis(scalar=zee) sage: h._self_to_dual(h([2,1]) + 3*h[1,1,1]) 21*m[1, 1, 1] + 11*m[2, 1] + 4*m[3]
This is for internal use only. Please use instead:
sage: m(h([2,1]) + 3*h[1,1,1]) 21*m[1, 1, 1] + 11*m[2, 1] + 4*m[3]
or::
sage: (h([2,1]) + 3*h[1,1,1]).dual() 21*m[1, 1, 1] + 11*m[2, 1] + 4*m[3] """
""" Returns the default value for ``self.dual_basis()``
This returns the basis ``self`` has been built from by duality.
.. WARNING::
This is not necessarily the dual basis for the standard (Hall) scalar product!
EXAMPLES::
sage: m = SymmetricFunctions(QQ).monomial() sage: zee = sage.combinat.sf.sfa.zee sage: h = m.dual_basis(scalar=zee) sage: h.dual_basis() Symmetric Functions over Rational Field in the monomial basis sage: m2 = h.dual_basis(zee, prefix='m2') sage: m([2])^2 2*m[2, 2] + m[4] sage: m2([2])^2 2*m2[2, 2] + m2[4]
TESTS::
sage: h.dual_basis() is h._dual_basis_default() True """
""" Representation of ``self``.
OUTPUT:
- a string description of ``self``
EXAMPLES::
sage: m = SymmetricFunctions(QQ).monomial() sage: zee = sage.combinat.sf.sfa.zee sage: h = m.dual_basis(scalar=zee); h #indirect doctests Dual basis to Symmetric Functions over Rational Field in the monomial basis sage: h = m.dual_basis(scalar=zee, scalar_name='Hall scalar product'); h #indirect doctest Dual basis to Symmetric Functions over Rational Field in the monomial basis with respect to the Hall scalar product """ else:
""" Compute the transition matrices between ``self`` and its dual basis for the homogeneous component of size `n`. The result is not returned, but stored in the cache.
INPUT:
- ``n`` -- nonnegative integer
EXAMPLES::
sage: e = SymmetricFunctions(QQ['t']).elementary() sage: f = e.dual_basis() sage: f._precompute(0) sage: f._precompute(1) sage: f._precompute(2) sage: l = lambda c: [ (i[0],[j for j in sorted(i[1].items())]) for i in sorted(c.items())] sage: l(f._to_self_cache) # note: this may depend on possible previous computations! [([], [([], 1)]), ([1], [([1], 1)]), ([1, 1], [([1, 1], 2), ([2], 1)]), ([2], [([1, 1], 1), ([2], 1)])] sage: l(f._from_self_cache) [([], [([], 1)]), ([1], [([1], 1)]), ([1, 1], [([1, 1], 1), ([2], -1)]), ([2], [([1, 1], -1), ([2], 2)])] sage: f._transition_matrices[2] [1 1] [1 2] sage: f._inverse_transition_matrices[2] [ 2 -1] [-1 1] """
# Handle the n == 0 and n == 1 cases separately
# We now get separated into two cases, depending on whether we can # use the power-sum basis to compute the matrix, or we have to use # the Schur basis.
# This is the case when (due to the base ring not being a # \mathbb{Q}-algebra) we cannot use the power-sum basis, # but (due to zee being the standard zee function) we can # use the Schur basis.
# Get all the basis elements of the n^th homogeneous component # of the dual basis and express them in the Schur basis
# This contains the data for the transition matrix from the # dual basis to self.
# This first section calculates how the basis elements of the # dual basis are expressed in terms of self's basis.
# For every partition p of size n, compute self(p) in # terms of the dual basis using the scalar product. # s_part corresponds to self(dual_basis(part)) # s_mcs corresponds to self(dual_basis(part))._monomial_coefficients
# We need to compute the scalar product of d[s_part] and # all of the d[p_part]'s # Compute the scalar product of d[s_part] and d[p_part]
else: # Now the other case. Note that just being in this case doesn't # guarantee that we can use the power-sum basis, but we can at # least try.
# Get all the basis elements of the n^th homogeneous component # of the dual basis and express them in the power-sum basis
# This contains the data for the transition matrix from the # dual basis to self.
# This first section calculates how the basis elements of the # dual basis are expressed in terms of self's basis.
# For every partition p of size n, compute self(p) in # terms of the dual basis using the scalar product. # s_part corresponds to self(dual_basis(part)) # s_mcs corresponds to self(dual_basis(part))._monomial_coefficients
# We need to compute the scalar product of d[s_part] and # all of the d[p_part]'s # Compute the scalar product of d[s_part] and d[p_part]
# Save the transition matrix
# This second section calculates how the basis elements of # self expand in terms of the dual basis. We do this by # computing the inverse of the matrix obtained above.
r""" Returns the transition matrix between the `n^{th}` homogeneous components of ``self`` and ``basis``.
INPUT:
- ``basis`` -- a target basis of the ring of symmetric functions - ``n`` -- nonnegative integer
OUTPUT:
- A transition matrix from ``self`` to ``basis`` for the elements of degree ``n``. The indexing order of the rows and columns is the order of ``Partitions(n)``.
EXAMPLES::
sage: Sym = SymmetricFunctions(QQ) sage: s = Sym.schur() sage: e = Sym.elementary() sage: f = e.dual_basis() sage: f.transition_matrix(s, 5) [ 1 -1 0 1 0 -1 1] [-2 1 1 -1 -1 1 0] [-2 2 -1 -1 1 0 0] [ 3 -1 -1 1 0 0 0] [ 3 -2 1 0 0 0 0] [-4 1 0 0 0 0 0] [ 1 0 0 0 0 0 0] sage: Partitions(5).list() [[5], [4, 1], [3, 2], [3, 1, 1], [2, 2, 1], [2, 1, 1, 1], [1, 1, 1, 1, 1]] sage: s(f[2,2,1]) s[3, 2] - 2*s[4, 1] + 3*s[5] sage: e.transition_matrix(s, 5).inverse().transpose() [ 1 -1 0 1 0 -1 1] [-2 1 1 -1 -1 1 0] [-2 2 -1 -1 1 0 0] [ 3 -1 -1 1 0 0 0] [ 3 -2 1 0 0 0 0] [-4 1 0 0 0 0 0] [ 1 0 0 0 0 0 0] """
return self._inverse_transition_matrices[n] else:
""" Return product of ``left`` and ``right``.
Multiplication is done by performing the multiplication in the dual basis of ``self`` and then converting back to ``self``.
INPUT:
- ``left``, ``right`` -- elements of ``self``
OUTPUT:
- the product of ``left`` and ``right`` in the basis ``self``
EXAMPLES::
sage: m = SymmetricFunctions(QQ).monomial() sage: zee = sage.combinat.sf.sfa.zee sage: h = m.dual_basis(scalar=zee) sage: a = h([2]) sage: b = a*a; b # indirect doctest d_m[2, 2] sage: b.dual() 6*m[1, 1, 1, 1] + 4*m[2, 1, 1] + 3*m[2, 2] + 2*m[3, 1] + m[4] """
#Do the multiplication in the dual basis #and then convert back to self.
""" An element in the dual basis.
INPUT:
At least one of the following must be specified. The one (if any) which is not provided will be computed.
- ``dictionary`` -- an internal dictionary for the monomials and coefficients of ``self``
- ``dual`` -- self as an element of the dual basis. """ """ Create an element of a dual basis.
TESTS::
sage: m = SymmetricFunctions(QQ).monomial() sage: zee = sage.combinat.sf.sfa.zee sage: h = m.dual_basis(scalar=zee, prefix='h') sage: a = h([2]) sage: ec = h._element_class sage: ec(h, dual=m([2])) -h[1, 1] + 2*h[2] sage: h(m([2])) -h[1, 1] + 2*h[2] sage: h([2]) h[2] sage: h([2])._dual m[1, 1] + m[2] sage: m(h([2])) m[1, 1] + m[2] """ raise ValueError("you must specify either x or dual")
# We need to compute the dual
# Get the underlying dictionary for self
# Make sure all the conversions from self to # to the dual basis have been precomputed
# Create the monomial coefficient dictionary from the # the monomial coefficient dictionary of dual
# We need to compute the monomial coefficients dictionary
# Get the underlying dictionary for the dual
# Make sure all the conversions from the dual basis # to self have been precomputed
# Create the monomial coefficient dictionary from the # the monomial coefficient dictionary of dual
# Initialize self
""" Return ``self`` in the dual basis.
OUTPUT:
- the element ``self`` expanded in the dual basis to ``self.parent()``
EXAMPLES::
sage: m = SymmetricFunctions(QQ).monomial() sage: zee = sage.combinat.sf.sfa.zee sage: h = m.dual_basis(scalar=zee) sage: a = h([2,1]) sage: a.parent() Dual basis to Symmetric Functions over Rational Field in the monomial basis sage: a.dual() 3*m[1, 1, 1] + 2*m[2, 1] + m[3] """
r""" Return the image of ``self`` under the omega automorphism.
The *omega automorphism* is defined to be the unique algebra endomorphism `\omega` of the ring of symmetric functions that satisfies `\omega(e_k) = h_k` for all positive integers `k` (where `e_k` stands for the `k`-th elementary symmetric function, and `h_k` stands for the `k`-th complete homogeneous symmetric function). It furthermore is a Hopf algebra endomorphism and an involution, and it is also known as the *omega involution*. It sends the power-sum symmetric function `p_k` to `(-1)^{k-1} p_k` for every positive integer `k`.
The images of some bases under the omega automorphism are given by
.. MATH::
\omega(e_{\lambda}) = h_{\lambda}, \qquad \omega(h_{\lambda}) = e_{\lambda}, \qquad \omega(p_{\lambda}) = (-1)^{|\lambda| - \ell(\lambda)} p_{\lambda}, \qquad \omega(s_{\lambda}) = s_{\lambda^{\prime}},
where `\lambda` is any partition, where `\ell(\lambda)` denotes the length (:meth:`~sage.combinat.partition.Partition.length`) of the partition `\lambda`, where `\lambda^{\prime}` denotes the conjugate partition (:meth:`~sage.combinat.partition.Partition.conjugate`) of `\lambda`, and where the usual notations for bases are used (`e` = elementary, `h` = complete homogeneous, `p` = powersum, `s` = Schur).
:meth:`omega_involution` is a synonym for the :meth:`omega` method.
OUTPUT:
- the result of applying omega to ``self``
EXAMPLES::
sage: m = SymmetricFunctions(QQ).monomial() sage: zee = sage.combinat.sf.sfa.zee sage: h = m.dual_basis(zee) sage: hh = SymmetricFunctions(QQ).homogeneous() sage: hh([2,1]).omega() h[1, 1, 1] - h[2, 1] sage: h([2,1]).omega() d_m[1, 1, 1] - d_m[2, 1] """
""" Return the standard scalar product of ``self`` and ``x``.
INPUT:
- ``x`` -- element of the symmetric functions
OUTPUT:
- the scalar product between ``x`` and ``self``
EXAMPLES::
sage: m = SymmetricFunctions(QQ).monomial() sage: zee = sage.combinat.sf.sfa.zee sage: h = m.dual_basis(scalar=zee) sage: a = h([2,1]) sage: a.scalar(a) 2 """
""" Return the Hall-Littlewood scalar product of ``self`` and ``x``.
INPUT:
- ``x`` -- element of the same dual basis as ``self``
OUTPUT:
- the Hall-Littlewood scalar product between ``x`` and ``self``
EXAMPLES::
sage: m = SymmetricFunctions(QQ).monomial() sage: zee = sage.combinat.sf.sfa.zee sage: h = m.dual_basis(scalar=zee) sage: a = h([2,1]) sage: a.scalar_hl(a) (t + 2)/(-t^4 + 2*t^3 - 2*t + 1) """
""" Add two elements in the dual basis.
INPUT:
- ``y`` -- element of the same dual basis as ``self``
OUTPUT:
- the sum of ``self`` and ``y``
EXAMPLES::
sage: m = SymmetricFunctions(QQ).monomial() sage: zee = sage.combinat.sf.sfa.zee sage: h = m.dual_basis(zee) sage: a = h([2,1])+h([3]); a # indirect doctest d_m[2, 1] + d_m[3] sage: h[2,1]._add_(h[3]) d_m[2, 1] + d_m[3] sage: a.dual() 4*m[1, 1, 1] + 3*m[2, 1] + 2*m[3] """
""" Return the negative of ``self``.
EXAMPLES::
sage: m = SymmetricFunctions(QQ).monomial() sage: zee = sage.combinat.sf.sfa.zee sage: h = m.dual_basis(zee) sage: -h([2,1]) # indirect doctest -d_m[2, 1] """
""" Subtract two elements in the dual basis.
INPUT:
- ``y`` -- element of the same dual basis as ``self``
OUTPUT:
- the difference of ``self`` and ``y``
EXAMPLES::
sage: m = SymmetricFunctions(QQ).monomial() sage: zee = sage.combinat.sf.sfa.zee sage: h = m.dual_basis(zee) sage: h([2,1])-h([3]) # indirect doctest d_m[2, 1] - d_m[3] sage: h[2,1]._sub_(h[3]) d_m[2, 1] - d_m[3] """
""" Divide an element ``self`` of the dual basis by ``y``.
INPUT:
- ``y`` -- element of base field
OUTPUT:
- the element ``self`` divided by ``y``
EXAMPLES::
sage: m = SymmetricFunctions(QQ).monomial() sage: zee = sage.combinat.sf.sfa.zee sage: h = m.dual_basis(zee) sage: a = h([2,1])+h([3]) sage: a/2 # indirect doctest 1/2*d_m[2, 1] + 1/2*d_m[3] """ return self*(~y)
""" Invert ``self`` (only possible if ``self`` is a scalar multiple of `1` and we are working over a field).
OUTPUT:
- multiplicative inverse of ``self`` if possible
EXAMPLES::
sage: m = SymmetricFunctions(QQ).monomial() sage: zee = sage.combinat.sf.sfa.zee sage: h = m.dual_basis(zee) sage: a = h(2); a 2*d_m[] sage: ~a 1/2*d_m[] sage: a = 3*h[1] sage: a.__invert__() Traceback (most recent call last): ... ValueError: cannot invert self (= 3*m[1]) """
""" Expand the symmetric function ``self`` as a symmetric polynomial in ``n`` variables.
INPUT:
- ``n`` -- a nonnegative integer
- ``alphabet`` -- (default: ``'x'``) a variable for the expansion
OUTPUT:
A monomial expansion of ``self`` in the `n` variables labelled by ``alphabet``.
EXAMPLES::
sage: m = SymmetricFunctions(QQ).monomial() sage: zee = sage.combinat.sf.sfa.zee sage: h = m.dual_basis(zee) sage: a = h([2,1])+h([3]) sage: a.expand(2) 2*x0^3 + 3*x0^2*x1 + 3*x0*x1^2 + 2*x1^3 sage: a.dual().expand(2) 2*x0^3 + 3*x0^2*x1 + 3*x0*x1^2 + 2*x1^3 sage: a.expand(2,alphabet='y') 2*y0^3 + 3*y0^2*y1 + 3*y0*y1^2 + 2*y1^3 sage: a.expand(2,alphabet='x,y') 2*x^3 + 3*x^2*y + 3*x*y^2 + 2*y^3 sage: h([1]).expand(0) 0 sage: (3*h([])).expand(0) 3 """
# Backward compatibility for unpickling
|