diff --git a/src/sage/combinat/sf/character.py b/src/sage/combinat/sf/character.py index 3bd8ab5e0a1..2cc71c28626 100644 --- a/src/sage/combinat/sf/character.py +++ b/src/sage/combinat/sf/character.py @@ -37,6 +37,23 @@ class generic_character(SFA_generic): + + def construction(self): + """ + Return a pair ``(F, R)``, where ``F`` is a + :class:`SymmetricFunctionsFunctor` and `R` is a ring, such + that ``F(R)`` returns ``self``. + + EXAMPLES:: + + sage: ht = SymmetricFunctions(QQ).ht() + sage: ht.construction() + (SymmetricFunctionsFunctor[induced trivial symmetric group character], + Rational Field) + """ + return (CharacterSymmetricFunctionsFunctor(self, self.basis_name()), + self.base_ring()) + def _my_key(self, la): r""" A rank function for partitions. @@ -151,6 +168,61 @@ def _b_power_k(self, k): for d in divisors(k)) +from sage.combinat.sf.sfa import SymmetricFunctionsFunctor +class CharacterSymmetricFunctionsFunctor(SymmetricFunctionsFunctor): + def __init__(self, basis, name): + r""" + Initialise the functor. + + INPUT: + + - ``basis`` -- the basis of the Character symmetric function algebra + - ``name`` -- the name of the basis + + .. WARNING:: + + The codomain of this functor could actually be + :class:`CommutativeAlgebras` over the given ring, but + parameterized functors are currently not available. + + EXAMPLES:: + + sage: from sage.combinat.sf.character import CharacterSymmetricFunctionsFunctor + sage: B = SymmetricFunctions(QQ).ht() + sage: CharacterSymmetricFunctionsFunctor(B, B.basis_name()) + SymmetricFunctionsFunctor[induced trivial symmetric group character] + + """ + super().__init__(basis, name) + self._prefix = basis._prefix + + def _apply_functor(self, R): + """ + Apply the functor to an object of ``self``'s domain. + + EXAMPLES:: + + sage: B = SymmetricFunctions(QQ).ht() + sage: F, R = B.construction() # indirect doctest + sage: F(QQbar) + Symmetric Functions over Algebraic Field in the induced trivial + symmetric group character basis + """ + from sage.combinat.sf.sf import SymmetricFunctions + return self._basis(SymmetricFunctions(R), self._prefix) + + def __eq__(self, other): + """ + EXAMPLES:: + + sage: B1 = SymmetricFunctions(QQ).ht() + sage: B2 = SymmetricFunctions(QQ).st() + sage: B1.construction()[0] == B2.construction()[0] + False + """ + return super().__eq__(other) and self._prefix == other._prefix + + class induced_trivial_character_basis(generic_character): r""" The induced trivial symmetric group character basis of diff --git a/src/sage/combinat/sf/dual.py b/src/sage/combinat/sf/dual.py index 97f81551f8b..cad463cd6d1 100644 --- a/src/sage/combinat/sf/dual.py +++ b/src/sage/combinat/sf/dual.py @@ -26,7 +26,16 @@ class SymmetricFunctionAlgebra_dual(classical.SymmetricFunctionAlgebra_classical): - def __init__(self, dual_basis, scalar, scalar_name="", basis_name=None, prefix=None): + @staticmethod + def __classcall__(cls, dual_basis, scalar, scalar_name="", basis_name=None, prefix=None): + """ + Normalize the arguments. + """ + if prefix is None: + prefix = 'd_'+dual_basis.prefix() + return super().__classcall__(cls, dual_basis, scalar, scalar_name, basis_name, prefix) + + def __init__(self, dual_basis, scalar, scalar_name, basis_name, prefix): r""" Generic dual basis of a basis of symmetric functions. @@ -72,9 +81,9 @@ def __init__(self, dual_basis, scalar, scalar_name="", basis_name=None, prefix=N EXAMPLES:: sage: e = SymmetricFunctions(QQ).e() - sage: f = e.dual_basis(prefix = "m", basis_name="Forgotten symmetric functions"); f + 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(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 @@ -145,9 +154,6 @@ def __init__(self, dual_basis, scalar, scalar_name="", basis_name=None, prefix=N self._sym = sage.combinat.sf.sf.SymmetricFunctions(scalar_target) self._p = self._sym.power() - if prefix is None: - prefix = 'd_'+dual_basis.prefix() - classical.SymmetricFunctionAlgebra_classical.__init__(self, self._sym, basis_name=basis_name, prefix=prefix) @@ -157,6 +163,20 @@ def __init__(self, dual_basis, scalar, scalar_name="", basis_name=None, prefix=N self.register_coercion(SetMorphism(Hom(self._dual_basis, self, category), self._dual_to_self)) self._dual_basis.register_coercion(SetMorphism(Hom(self, self._dual_basis, category), self._self_to_dual)) + def construction(self): + """ + Return a pair ``(F, R)``, where ``F`` is a + :class:`SymmetricFunctionsFunctor` and `R` is a ring, such + that ``F(R)`` returns ``self``. + + EXAMPLES:: + + sage: w = SymmetricFunctions(ZZ).witt() + sage: w.dual_basis().construction() + (SymmetricFunctionsFunctor[dual Witt], Integer Ring) + """ + return DualBasisFunctor(self), self.base_ring() + def _dual_to_self(self, x): """ Coerce an element of the dual of ``self`` canonically into ``self``. @@ -259,6 +279,24 @@ def _dual_basis_default(self): """ return self._dual_basis + def basis_name(self): + r""" + Return the name of the basis of ``self``. + + This is used for output and, for the classical bases of + symmetric functions, to connect this basis with Symmetrica. + + EXAMPLES:: + + sage: Sym = SymmetricFunctions(QQ) + sage: f = Sym.f() + sage: f.basis_name() + 'forgotten' + """ + if self._basis_name is None: + return "dual " + self._dual_basis.basis_name() + return self._basis_name + def _repr_(self): """ Representation of ``self``. @@ -276,12 +314,11 @@ def _repr_(self): 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 """ - if hasattr(self, "_basis"): + if self._basis_name is not None: return super()._repr_() if self._scalar_name: return "Dual basis to %s" % self._dual_basis + " with respect to the " + self._scalar_name - else: - return "Dual basis to %s" % self._dual_basis + return "Dual basis to %s" % self._dual_basis def _precompute(self, n): """ @@ -890,6 +927,72 @@ def expand(self, n, alphabet='x'): return self._dual.expand(n, alphabet) +from sage.combinat.sf.sfa import SymmetricFunctionsFunctor +class DualBasisFunctor(SymmetricFunctionsFunctor): + """ + A constructor for algebras of symmetric functions constructed by + duality. + + EXAMPLES:: + + sage: w = SymmetricFunctions(ZZ).witt() + sage: w.dual_basis().construction() + (SymmetricFunctionsFunctor[dual Witt], Integer Ring) + """ + def __init__(self, basis): + r""" + Initialise the functor. + + INPUT: + + - ``basis`` -- the basis of the symmetric function algebra + """ + self._dual_basis = basis._dual_basis + self._basis_name = basis._basis_name + self._scalar = basis._scalar + self._scalar_name = basis._scalar_name + self._prefix = basis._prefix + super().__init__(basis, self._basis_name) + + def _apply_functor(self, R): + """ + Apply the functor to an object of ``self``'s domain. + + EXAMPLES:: + + sage: m = SymmetricFunctions(ZZ).monomial() + sage: zee = sage.combinat.sf.sfa.zee + sage: h = m.dual_basis(scalar=zee) + sage: F, R = h.construction() # indirect doctest + sage: F(QQ) + Dual basis to Symmetric Functions over Rational Field in the monomial basis + + sage: b = m.dual_basis(scalar=zee).dual_basis(scalar=lambda x: 1) + sage: F, R = b.construction() # indirect doctest + sage: F(QQ) + Dual basis to Dual basis to Symmetric Functions over Rational Field in the monomial basis + """ + dual_basis = self._dual_basis.change_ring(R) + return self._basis(dual_basis, self._scalar, self._scalar_name, + self._basis_name, self._prefix) + + def _repr_(self): + """ + Return a string representation of ``self``. + + EXAMPLES:: + + sage: w = SymmetricFunctions(ZZ).witt() + sage: w.dual_basis().construction() + (SymmetricFunctionsFunctor[dual Witt], Integer Ring) + """ + if self._basis_name is None: + name = "dual " + self._dual_basis.basis_name() + else: + name = self._basis_name + return "SymmetricFunctionsFunctor[" + name + "]" + + # Backward compatibility for unpickling from sage.misc.persist import register_unpickle_override register_unpickle_override('sage.combinat.sf.dual', 'SymmetricFunctionAlgebraElement_dual', SymmetricFunctionAlgebra_dual.Element) diff --git a/src/sage/combinat/sf/hall_littlewood.py b/src/sage/combinat/sf/hall_littlewood.py index c3376537a35..f315978ca43 100644 --- a/src/sage/combinat/sf/hall_littlewood.py +++ b/src/sage/combinat/sf/hall_littlewood.py @@ -77,7 +77,14 @@ def __repr__(self): """ return self._name + " over %s" % self._sym.base_ring() - def __init__(self, Sym, t='t'): + @staticmethod + def __classcall__(cls, Sym, t='t'): + """ + Normalize the arguments. + """ + return super().__classcall__(cls, Sym, Sym.base_ring()(t)) + + def __init__(self, Sym, t): """ Initialize ``self``. @@ -387,6 +394,24 @@ def __init__(self, hall_littlewood): self .register_coercion(SetMorphism(Hom(self._s, self, category), self._s_to_self)) self._s.register_coercion(SetMorphism(Hom(self, self._s, category), self._self_to_s)) + def construction(self): + """ + Return a pair ``(F, R)``, where ``F`` is a + :class:`SymmetricFunctionsFunctor` and `R` is a ring, such + that ``F(R)`` returns ``self``. + + EXAMPLES:: + + sage: P = SymmetricFunctions(QQ).hall_littlewood(t=2).P() + sage: P.construction() + (SymmetricFunctionsFunctor[Hall-Littlewood P with t=2], Rational Field) + """ + + return (HallLittlewoodSymmetricFunctionsFunctor(self, + self.basis_name(), + self.t), + self.base_ring()) + def _s_to_self(self, x): r""" Isomorphism from the Schur basis into ``self`` @@ -673,6 +698,80 @@ def scalar_hl(self, x, t=None): orthogonal=True) +from sage.combinat.sf.sfa import SymmetricFunctionsFunctor +class HallLittlewoodSymmetricFunctionsFunctor(SymmetricFunctionsFunctor): + def __init__(self, basis, name, t): + r"""Initialise the functor. + + INPUT: + + - ``basis`` -- the basis of the Hall-Littlewood symmetric function + algebra + - ``name`` -- the name of the basis + - ``t`` -- the parameter `t` + + .. WARNING:: + + Strictly speaking, this is not a functor on + :class:`CommutativeRings`, but rather a functor on + commutative rings with a distinguished element. Apart + from that, the codomain of this functor could actually be + :class:`CommutativeAlgebras` over the given ring, but + parameterized functors are currently not available. + + EXAMPLES:: + + sage: from sage.combinat.sf.hall_littlewood import HallLittlewoodSymmetricFunctionsFunctor + sage: R. = ZZ[] + sage: P = SymmetricFunctions(R).hall_littlewood().P() + sage: HallLittlewoodSymmetricFunctionsFunctor(P, P.basis_name(), t) + SymmetricFunctionsFunctor[Hall-Littlewood P] + """ + super().__init__(basis, name) + self._t = t + + def _apply_functor(self, R): + """ + Apply the functor to an object of ``self``'s domain. + + EXAMPLES:: + + sage: Sym = SymmetricFunctions(QQ['t']) + sage: P = Sym.hall_littlewood().P(); P + Symmetric Functions over Univariate Polynomial Ring in t + over Rational Field in the Hall-Littlewood P basis + sage: F, R = P.construction() # indirect doctest + sage: F(QQ['t']) + Symmetric Functions over Univariate Polynomial Ring in t + over Rational Field in the Hall-Littlewood P basis + + TESTS:: + + sage: F(QQ) + Traceback (most recent call last): + ... + TypeError: not a constant polynomial + """ + from sage.combinat.sf.sf import SymmetricFunctions + return self._basis(HallLittlewood(SymmetricFunctions(R), self._t)) + + def __eq__(self, other): + """ + EXAMPLES:: + + sage: R. = ZZ[] + sage: S. = QQ[] + sage: T. = QQ[] + sage: PR = SymmetricFunctions(R).hall_littlewood().P() + sage: PS = SymmetricFunctions(S).hall_littlewood().P() + sage: PT = SymmetricFunctions(T).hall_littlewood(t=s).P() + sage: PR.construction()[0] == PS.construction()[0] + True + sage: PR.construction()[0] == PT.construction()[0] + False + """ + return super().__eq__(other) and self._t == other._t + ########### # P basis # ########### diff --git a/src/sage/combinat/sf/hecke.py b/src/sage/combinat/sf/hecke.py index 5cea11ccb2c..b2643805498 100644 --- a/src/sage/combinat/sf/hecke.py +++ b/src/sage/combinat/sf/hecke.py @@ -121,8 +121,14 @@ class HeckeCharacter(SymmetricFunctionAlgebra_multiplicative): - [Ram1991]_ - [RR1997]_ """ + @staticmethod + def __classcall__(cls, Sym, q='q'): + """ + Normalize the arguments. + """ + return super().__classcall__(cls, Sym, Sym.base_ring()(q)) - def __init__(self, sym, q='q'): + def __init__(self, sym, q): r""" Initialize ``self``. @@ -156,7 +162,7 @@ def __init__(self, sym, q='q'): ....: for mu in Partitions(n)) True """ - self.q = sym.base_ring()(q) + self.q = q SymmetricFunctionAlgebra_multiplicative.__init__(self, sym, basis_name="Hecke character with q={}".format(self.q), prefix="qbar") @@ -169,6 +175,22 @@ def __init__(self, sym, q='q'): self._p.register_coercion(self._module_morphism(self._qbar_to_p_on_basis, codomain=self._p)) + def construction(self): + """ + Return a pair ``(F, R)``, where ``F`` is a + :class:`SymmetricFunctionsFunctor` and `R` is a ring, such + that ``F(R)`` returns ``self``. + + EXAMPLES:: + + sage: qbar = SymmetricFunctions(QQ['q']).qbar('q') + sage: qbar.construction() + (SymmetricFunctionsFunctor[Hecke character with q=q], + Univariate Polynomial Ring in q over Rational Field) + """ + return (HeckeSymmetricFunctionsFunctor(self, self.basis_name(), self.q), + self.base_ring()) + def _p_to_qbar_on_generator(self, n): r""" Convert `p_n` to ``self`` @@ -298,3 +320,70 @@ def P(i): q = self.q return T.sum_of_terms(((P(j), P(r-j)), one if j in [0,r] else q-one) for j in range(r+1)) + + +from sage.combinat.sf.sfa import SymmetricFunctionsFunctor +class HeckeSymmetricFunctionsFunctor(SymmetricFunctionsFunctor): + def __init__(self, basis, name, q): + r""" + Initialise the functor. + + INPUT: + + - ``basis`` -- the basis of the Hecke symmetric function algebra + - ``name`` -- the name of the basis + - ``q`` -- the parameter `q` + + .. WARNING:: + + Strictly speaking, this is not a functor on + :class:`CommutativeRings`, but rather a functor on + commutative rings with a distinguished element. Apart + from that, the codomain of this functor could actually be + :class:`CommutativeAlgebras` over the given ring, but + parameterized functors are currently not available. + + EXAMPLES:: + + sage: from sage.combinat.sf.hecke import HeckeSymmetricFunctionsFunctor + sage: R. = ZZ[] + sage: B = SymmetricFunctions(R).hecke_character() + sage: HeckeSymmetricFunctionsFunctor(B, B.basis_name(), q) + SymmetricFunctionsFunctor[Hecke character with q=q] + """ + super().__init__(basis, name) + self._q = q + + def _apply_functor(self, R): + """ + Apply the functor to an object of ``self``'s domain. + + EXAMPLES:: + + sage: R. = ZZ[] + sage: B = SymmetricFunctions(R).hecke_character() + sage: F, R = B.construction() # indirect doctest + sage: F(QQ['q']) + Symmetric Functions over Univariate Polynomial Ring in q over + Rational Field in the Hecke character with q=q basis + + TESTS:: + + sage: F(QQ) + Traceback (most recent call last): + ... + TypeError: cannot convert nonconstant polynomial + """ + from sage.combinat.sf.sf import SymmetricFunctions + return self._basis(SymmetricFunctions(R), self._q) + + def __eq__(self, other): + """ + EXAMPLES:: + + sage: B1 = SymmetricFunctions(ZZ["q"]).hecke_character() + sage: B2 = SymmetricFunctions(QQ["q"]).qbar() + sage: B1.construction()[0] == B2.construction()[0] + True + """ + return super().__eq__(other) and self._q == other._q diff --git a/src/sage/combinat/sf/jack.py b/src/sage/combinat/sf/jack.py index a7a0fec6186..0b03fa88fa5 100644 --- a/src/sage/combinat/sf/jack.py +++ b/src/sage/combinat/sf/jack.py @@ -50,8 +50,14 @@ class Jack(UniqueRepresentation): + @staticmethod + def __classcall__(cls, Sym, t='t'): + """ + Normalize the arguments. + """ + return super().__classcall__(cls, Sym, Sym.base_ring()(t)) - def __init__(self, Sym, t='t'): + def __init__(self, Sym, t): r""" The family of Jack symmetric functions including the `P`, `Q`, `J`, `Qp` bases. The default parameter is ``t``. @@ -70,7 +76,7 @@ def __init__(self, Sym, t='t'): Jack polynomials with t=1 over Rational Field """ self._sym = Sym - self.t = Sym.base_ring()(t) + self.t = t self._name_suffix = "" if str(t) != 't': self._name_suffix += " with t=%s" % t @@ -533,6 +539,23 @@ def __init__(self, jack): self .register_coercion(SetMorphism(Hom(self._h, self, category), self._h_to_self)) self._h.register_coercion(SetMorphism(Hom(self, self._h, category), self._self_to_h)) + def construction(self): + """ + Return a pair ``(F, R)``, where ``F`` is a + :class:`SymmetricFunctionsFunctor` and `R` is a ring, such + that ``F(R)`` returns ``self``. + + EXAMPLES:: + + sage: Sym = SymmetricFunctions(FractionField(QQ['t'])) + sage: JP = Sym.jack().P() + sage: JP.construction() + (SymmetricFunctionsFunctor[Jack P], + Fraction Field of Univariate Polynomial Ring in t over Rational Field) + """ + return (JackSymmetricFunctionsFunctor(self, self.basis_name(), self.t), + self.base_ring()) + def _m_to_self(self, x): r""" Isomorphism from the monomial basis into ``self`` @@ -817,6 +840,81 @@ def scalar_jack(self, x, t=None): return parent._normalize_coefficients(res) +from sage.combinat.sf.sfa import SymmetricFunctionsFunctor +class JackSymmetricFunctionsFunctor(SymmetricFunctionsFunctor): + def __init__(self, basis, name, t): + r""" + Initialise the functor. + + INPUT: + + - ``basis`` -- the basis of the Jack symmetric function algebra + - ``name`` -- the name of the basis + - ``t`` -- the parameter `t` + + .. WARNING:: + + Strictly speaking, this is not a functor on + :class:`CommutativeRings`, but rather a functor on + commutative rings with a distinguished element. Apart + from that, the codomain of this functor could actually be + :class:`CommutativeAlgebras` over the given ring, but + parameterized functors are currently not available. + + EXAMPLES:: + + sage: from sage.combinat.sf.jack import JackSymmetricFunctionsFunctor + sage: R. = ZZ[] + sage: P = SymmetricFunctions(R).jack().P() + sage: JackSymmetricFunctionsFunctor(P, P.basis_name(), t) + SymmetricFunctionsFunctor[Jack P] + """ + super().__init__(basis, name) + self._t = t + + def _apply_functor(self, R): + """ + Apply the functor to an object of ``self``'s domain. + + EXAMPLES:: + + sage: Sym = SymmetricFunctions(QQ['t']) + sage: P = Sym.jack().P(); P + Symmetric Functions over Univariate Polynomial Ring in t + over Rational Field in the Jack P basis + sage: F, R = P.construction() # indirect doctest + sage: F(QQ['t']) + Symmetric Functions over Univariate Polynomial Ring in t + over Rational Field in the Jack P basis + + TESTS:: + + sage: F(QQ) + Traceback (most recent call last): + ... + TypeError: not a constant polynomial + """ + from sage.combinat.sf.sf import SymmetricFunctions + return self._basis(Jack(SymmetricFunctions(R), self._t)) + + def __eq__(self, other): + """ + EXAMPLES:: + + sage: R. = ZZ[] + sage: S. = QQ[] + sage: T. = QQ[] + sage: PR = SymmetricFunctions(R).jack().P() + sage: PS = SymmetricFunctions(S).jack().P() + sage: PT = SymmetricFunctions(T).jack(t=s).P() + sage: PR.construction()[0] == PS.construction()[0] + True + sage: PR.construction()[0] == PT.construction()[0] + False + """ + return super().__eq__(other) and self._t == other._t + + def part_scalar_jack(part1, part2, t): r""" Returns the Jack scalar product between ``p(part1)`` and ``p(part2)`` where diff --git a/src/sage/combinat/sf/llt.py b/src/sage/combinat/sf/llt.py index 6e0e20d49ba..e87492da324 100644 --- a/src/sage/combinat/sf/llt.py +++ b/src/sage/combinat/sf/llt.py @@ -91,8 +91,14 @@ class LLT_class(UniqueRepresentation): sage: HS3x(HC3t2[3,1]) 2*HSp3[3, 1] + (-2*x+1)*HSp3[4] """ + @staticmethod + def __classcall__(cls, Sym, k, t='t'): + """ + Normalize the arguments. + """ + return super().__classcall__(cls, Sym, k, Sym.base_ring()(t)) - def __init__(self, Sym, k, t='t'): + def __init__(self, Sym, k, t): r""" Class of LLT symmetric function bases @@ -129,7 +135,7 @@ def __init__(self, Sym, k, t='t'): self._k = k self._sym = Sym self._name = "level %s LLT polynomials" % self._k - self.t = Sym.base_ring()(t) + self.t = t self._name_suffix = "" if str(t) != 't': self._name_suffix += " with t=%s" % self.t @@ -441,7 +447,7 @@ def __init__(self, llt, prefix): self._llt = llt self._k = llt._k - sfa.SymmetricFunctionAlgebra_generic.__init__(self, self._sym) + sfa.SymmetricFunctionAlgebra_generic.__init__(self, self._sym, self._basis_name) # temporary until Hom(GradedHopfAlgebrasWithBasis work better) category = sage.categories.all.ModulesWithBasis(self._sym.base_ring()) @@ -449,6 +455,24 @@ def __init__(self, llt, prefix): self .register_coercion(SetMorphism(Hom(self._m, self, category), self._m_to_self)) self._m.register_coercion(SetMorphism(Hom(self, self._m, category), self._self_to_m)) + def construction(self): + """ + Return a pair ``(F, R)``, where ``F`` is a + :class:`SymmetricFunctionsFunctor` and `R` is a ring, such + that ``F(R)`` returns ``self``. + + EXAMPLES:: + + sage: Sym = SymmetricFunctions(FractionField(QQ['t'])) + sage: HSp3 = Sym.llt(3).hspin() + sage: HSp3.construction() + (SymmetricFunctionsFunctor[level 3 LLT spin], + Fraction Field of Univariate Polynomial Ring in t over Rational Field) + """ + return (LLTSymmetricFunctionsFunctor(self, self.basis_name(), + self._k, self.t), + self.base_ring()) + def _m_to_self(self, x): r""" Isomorphism from the monomial basis into ``self`` @@ -608,6 +632,84 @@ class Element(sfa.SymmetricFunctionAlgebra_generic.Element): pass +from sage.combinat.sf.sfa import SymmetricFunctionsFunctor +class LLTSymmetricFunctionsFunctor(SymmetricFunctionsFunctor): + def __init__(self, basis, name, k, t): + r""" + Initialise the functor. + + INPUT: + + - ``basis`` -- the basis of the LLT symmetric function algebra + - ``name`` -- the name of the basis + - ``k`` -- the parameter `k` + - ``t`` -- the parameter `t` + + .. WARNING:: + + Strictly speaking, this is not a functor on + :class:`CommutativeRings`, but rather a functor on + commutative rings with some distinguished elements. + Apart from that, the codomain of this functor could + actually be :class:`CommutativeAlgebras` over the given + ring, but parameterized functors are currently not + available. + + EXAMPLES:: + + sage: from sage.combinat.sf.llt import LLTSymmetricFunctionsFunctor + sage: R. = ZZ[] + sage: B = SymmetricFunctions(R).llt(3).hcospin() + sage: LLTSymmetricFunctionsFunctor(B, B.basis_name(), 3, t) + SymmetricFunctionsFunctor[level 3 LLT cospin] + """ + super().__init__(basis, name) + self._k = k + self._t = t + + def _apply_functor(self, R): + """ + Apply the functor to an object of ``self``'s domain. + + EXAMPLES:: + + sage: Sym = SymmetricFunctions(QQ['t']) + sage: B = Sym.llt(3).hcospin(); B + Symmetric Functions over Univariate Polynomial Ring in t + over Rational Field in the level 3 LLT cospin basis + sage: F, R = B.construction() # indirect doctest + sage: F(ZZ['t']) + Symmetric Functions over Univariate Polynomial Ring in t + over Integer Ring in the level 3 LLT cospin basis + + TESTS:: + + sage: F(QQ) + Traceback (most recent call last): + ... + TypeError: not a constant polynomial + """ + from sage.combinat.sf.sf import SymmetricFunctions + return self._basis(LLT_class(SymmetricFunctions(R), self._k, self._t)) + + def __eq__(self, other): + """ + EXAMPLES:: + + sage: R. = ZZ[] + sage: S. = QQ[] + sage: T. = QQ[] + sage: PR = SymmetricFunctions(R).llt(3).hcospin() + sage: PS = SymmetricFunctions(S).llt(3).hcospin() + sage: PT = SymmetricFunctions(T).llt(3, t=s).hcospin() + sage: PR.construction()[0] == PS.construction()[0] + True + sage: PR.construction()[0] == PT.construction()[0] + False + """ + return super().__eq__(other) and self._k == other._k and self._t == other._t + + # the H-spin basis class LLT_spin(LLT_generic): diff --git a/src/sage/combinat/sf/macdonald.py b/src/sage/combinat/sf/macdonald.py index 1358c5779df..d7c93ac41d0 100644 --- a/src/sage/combinat/sf/macdonald.py +++ b/src/sage/combinat/sf/macdonald.py @@ -97,7 +97,14 @@ def __repr__(self): """ return self._name - def __init__(self, Sym, q='q', t='t'): + @staticmethod + def __classcall__(cls, Sym, q='q', t='t'): + """ + Normalize the arguments. + """ + return super().__classcall__(cls, Sym, Sym.base_ring()(q), Sym.base_ring()(t)) + + def __init__(self, Sym, q, t): r""" Macdonald Symmetric functions including `P`, `Q`, `J`, `H`, `Ht` bases also including the S basis which is the plethystic transformation @@ -119,8 +126,8 @@ def __init__(self, Sym, q='q', t='t'): """ self._sym = Sym self._s = Sym.s() - self.q = Sym.base_ring()(q) - self.t = Sym.base_ring()(t) + self.q = q + self.t = t self._name_suffix = "" if str(q) != 'q': self._name_suffix += " with q=%s" % q @@ -767,6 +774,24 @@ def __init__(self, macdonald): self.register_coercion(SetMorphism(Hom(self._s, self, category), self._s_to_self)) self._s.register_coercion(SetMorphism(Hom(self, self._s, category), self._self_to_s)) + def construction(self): + """ + Return a pair ``(F, R)``, where ``F`` is a + :class:`SymmetricFunctionsFunctor` and `R` is a ring, such + that ``F(R)`` returns ``self``. + + EXAMPLES:: + + sage: Sym = SymmetricFunctions(FractionField(QQ['q'])) + sage: J = Sym.macdonald(t=2).J() + sage: J.construction() + (SymmetricFunctionsFunctor[Macdonald J with t=2], + Fraction Field of Univariate Polynomial Ring in q over Rational Field) + """ + return (MacdonaldSymmetricFunctionsFunctor(self, self.basis_name(), + self.q, self.t), + self.base_ring()) + def _s_to_self(self, x): r""" Isomorphism from the Schur basis into self @@ -990,9 +1015,87 @@ def nabla(self, q=None, t=None, power=1): Ht = parent.realization_of().macdonald(q=q,t=t).Ht() return parent(Ht(self).nabla(power=power)) -#P basis +from sage.combinat.sf.sfa import SymmetricFunctionsFunctor +class MacdonaldSymmetricFunctionsFunctor(SymmetricFunctionsFunctor): + def __init__(self, basis, name, q, t): + r""" + Initialise the functor. + + INPUT: + + - ``basis`` -- the basis of the Macdonald symmetric function algebra + - ``name`` -- the name of the basis + - ``q`` -- the parameter `q` + - ``t`` -- the parameter `t` + + .. WARNING:: + + Strictly speaking, this is not a functor on + :class:`CommutativeRings`, but rather a functor on + commutative rings with some distinguished elements. For + example, for the Macdonald polynomials, we have to + specify `q` and `t` in the ring. Apart from that, the + codomain of this functor could actually be + :class:`CommutativeAlgebras` over the given ring, but + parameterized functors are currently not available. + + EXAMPLES:: + + sage: from sage.combinat.sf.macdonald import MacdonaldSymmetricFunctionsFunctor + sage: R. = ZZ[] + sage: H = SymmetricFunctions(R).macdonald(q=1).H() + sage: MacdonaldSymmetricFunctionsFunctor(H, H.basis_name(), 1, t) + SymmetricFunctionsFunctor[Macdonald H with q=1] + """ + super().__init__(basis, name) + self._q = q + self._t = t + + def _apply_functor(self, R): + """ + Apply the functor to an object of ``self``'s domain. + + EXAMPLES:: + + sage: Sym = SymmetricFunctions(QQ['q','t']) + sage: P = Sym.macdonald(q=1/2).P(); P + Symmetric Functions over Multivariate Polynomial Ring in q, t + over Rational Field in the Macdonald P with q=1/2 basis + sage: F, R = P.construction() # indirect doctest + sage: F(QQ['t']) + Symmetric Functions over Univariate Polynomial Ring in t + over Rational Field in the Macdonald P with q=1/2 basis + + TESTS:: + + sage: F(QQ) + Traceback (most recent call last): + ... + TypeError: not a constant polynomial + """ + from sage.combinat.sf.sf import SymmetricFunctions + return self._basis(Macdonald(SymmetricFunctions(R), self._q, self._t)) + + def __eq__(self, other): + """ + EXAMPLES:: + + sage: R. = ZZ[] + sage: S. = QQ[] + sage: T. = QQ[] + sage: PR = SymmetricFunctions(R).macdonald().P() + sage: PS = SymmetricFunctions(S).macdonald().P() + sage: PT = SymmetricFunctions(T).macdonald(t=s).P() + sage: PR.construction()[0] == PS.construction()[0] + True + sage: PR.construction()[0] == PT.construction()[0] + False + """ + return super().__eq__(other) and self._q == other._q and self._t == other._t + +#P basis class MacdonaldPolynomials_p(MacdonaldPolynomials_generic): def __init__(self, macdonald): r""" diff --git a/src/sage/combinat/sf/orthotriang.py b/src/sage/combinat/sf/orthotriang.py index 2e1650e57a7..b14df92bd1d 100644 --- a/src/sage/combinat/sf/orthotriang.py +++ b/src/sage/combinat/sf/orthotriang.py @@ -49,8 +49,14 @@ class SymmetricFunctionAlgebra_orthotriang(sfa.SymmetricFunctionAlgebra_generic) class Element(sfa.SymmetricFunctionAlgebra_generic.Element): pass + @staticmethod + def __classcall__(cls, Sym, base, scalar, prefix, basis_name, leading_coeff=None): + """ + Normalize the arguments. + """ + return super().__classcall__(cls, Sym, base, scalar, prefix, basis_name, leading_coeff) - def __init__(self, Sym, base, scalar, prefix, basis_name, leading_coeff=None): + def __init__(self, Sym, base, scalar, prefix, basis_name, leading_coeff): r""" Initialization of the symmetric function algebra defined via orthotriangular rules. @@ -84,8 +90,8 @@ def __init__(self, Sym, base, scalar, prefix, basis_name, leading_coeff=None): TESTS:: - sage: TestSuite(s).run(elements = [s[1,1]+2*s[2], s[1]+3*s[1,1]]) - sage: TestSuite(s).run(skip = ["_test_associativity", "_test_prod"]) # long time (7s on sage.math, 2011) + sage: TestSuite(s).run(elements=[s[1,1]+2*s[2], s[1]+3*s[1,1]]) + sage: TestSuite(s).run(skip=["_test_associativity", "_test_prod", '_test_construction']) # long time (7s on sage.math, 2011) Note: ``s.an_element()`` is of degree 4; so we skip ``_test_associativity`` and ``_test_prod`` which involve @@ -102,6 +108,24 @@ def __init__(self, Sym, base, scalar, prefix, basis_name, leading_coeff=None): self.register_coercion(SetMorphism(Hom(base, self), self._base_to_self)) base.register_coercion(SetMorphism(Hom(self, base), self._self_to_base)) + def construction(self): + """ + Return a pair ``(F, R)``, where ``F`` is a + :class:`SymmetricFunctionsFunctor` and `R` is a ring, such + that ``F(R)`` returns ``self``. + + EXAMPLES:: + + sage: from sage.combinat.sf.sfa import zee + sage: from sage.combinat.sf.orthotriang import SymmetricFunctionAlgebra_orthotriang + sage: Sym = SymmetricFunctions(QQ) + sage: m = Sym.m() + sage: s = SymmetricFunctionAlgebra_orthotriang(Sym, m, zee, 's', 'Schur') + sage: s.construction() + (SymmetricFunctionsFunctor[Schur], Rational Field) + """ + return OrthotriangBasisFunctor(self), self.base_ring() + def _base_to_self(self, x): """ Coerce a symmetric function in base ``x`` into ``self``. @@ -252,6 +276,58 @@ def product(self, left, right): return self(self._sf_base(left) * self._sf_base(right)) +from sage.combinat.sf.sfa import SymmetricFunctionsFunctor +class OrthotriangBasisFunctor(SymmetricFunctionsFunctor): + """ + A constructor for algebras of symmetric functions constructed by + orthogonality and triangularity. + + EXAMPLES:: + + sage: from sage.combinat.sf.sfa import zee + sage: from sage.combinat.sf.orthotriang import SymmetricFunctionAlgebra_orthotriang + sage: Sym = SymmetricFunctions(QQ) + sage: m = Sym.m() + sage: s = SymmetricFunctionAlgebra_orthotriang(Sym, m, zee, 's', 'Schur') + sage: s.construction() + (SymmetricFunctionsFunctor[Schur], Rational Field) + """ + def __init__(self, basis): + r""" + Initialise the functor. + + INPUT: + + - ``basis`` -- the basis of the symmetric function algebra + """ + self._basis_name = basis.basis_name() + self._sf_base = basis._sf_base + self._scalar = basis._scalar + self._leading_coeff = basis._leading_coeff + self._prefix = basis._prefix + super().__init__(basis, self._basis_name) + + def _apply_functor(self, R): + """ + Apply the functor to an object of ``self``'s domain. + + EXAMPLES:: + + sage: from sage.combinat.sf.sfa import zee + sage: from sage.combinat.sf.orthotriang import SymmetricFunctionAlgebra_orthotriang + sage: Sym = SymmetricFunctions(ZZ) + sage: m = Sym.m() + sage: s = SymmetricFunctionAlgebra_orthotriang(Sym, m, zee, 's', 'Schur functions') + sage: F, R = s.construction() # indirect doctest + sage: F(QQbar) + Symmetric Functions over Algebraic Field in the Schur functions basis + """ + from sage.combinat.sf.sf import SymmetricFunctions + return self._basis(SymmetricFunctions(R), self._sf_base.change_ring(R), + self._scalar, self._prefix, self._basis_name, + self._leading_coeff) + + # Backward compatibility for unpickling from sage.misc.persist import register_unpickle_override register_unpickle_override('sage.combinat.sf.orthotriang', 'SymmetricFunctionAlgebraElement_orthotriang', SymmetricFunctionAlgebra_orthotriang.Element) diff --git a/src/sage/combinat/sf/sf.py b/src/sage/combinat/sf/sf.py index ad86bfd6c7f..aab65028db6 100644 --- a/src/sage/combinat/sf/sf.py +++ b/src/sage/combinat/sf/sf.py @@ -908,7 +908,6 @@ def schur(self): return schur.SymmetricFunctionAlgebra_schur(self) s = schur Schur = schur # Currently needed by SymmetricFunctions.__init_extra__ - # and sfa.GradedSymmetricFunctionsBases.corresponding_basis_over def powersum(self): r""" @@ -976,8 +975,6 @@ def witt(self, coerce_h=True, coerce_e=False, coerce_p=False): from . import witt return witt.SymmetricFunctionAlgebra_witt(self, coerce_h=coerce_h, coerce_e=coerce_e, coerce_p=coerce_p) w = witt - # Currently needed by sfa.GradedSymmetricFunctionsBases.corresponding_basis_over - Witt = witt def irreducible_symmetric_group_character(self): r""" diff --git a/src/sage/combinat/sf/sfa.py b/src/sage/combinat/sf/sfa.py index de6498ec6f2..cee85400be9 100644 --- a/src/sage/combinat/sf/sfa.py +++ b/src/sage/combinat/sf/sfa.py @@ -170,21 +170,22 @@ BACKWARD INCOMPATIBLE CHANGES (:issue:`5457`): -The symmetric functions code has been refactored to take -advantage of the coercion systems. This introduced a couple of glitches: +The symmetric functions code has been refactored to take advantage of +the coercion systems. This introduced a couple of glitches, in +particular, on some bases changes, coefficients in Jack polynomials +are not normalized -- On some bases changes, coefficients in Jack polynomials are not normalized +However, conversions and coercions are now also defined between +symmetric functions over different coefficient rings:: -- Except in a few cases, conversions and coercions are only defined - between symmetric functions over the same coefficient ring. E.g. - the following does not work anymore:: + sage: S = SymmetricFunctions(QQ) + sage: S2 = SymmetricFunctions(QQ['t']) + sage: S3 = SymmetricFunctions(ZZ) + sage: S.m()[1] + S2.m()[2] + m[1] + m[2] - sage: s = SymmetricFunctions(QQ) - sage: s2 = SymmetricFunctions(QQ['t']) - sage: s([1]) + s2([2]) # todo: not implemented - - This feature will probably come back at some point through - improvements to the Sage coercion system. + sage: S.m()(S3.sp()[2,1]) + -m[1] + 2*m[1, 1, 1] + m[2, 1] Backward compatibility should be essentially retained. @@ -221,7 +222,6 @@ from sage.rings.polynomial.polynomial_element import Polynomial from sage.rings.polynomial.multi_polynomial import MPolynomial from sage.combinat.partition import _Partitions, Partitions, Partitions_n, Partition -from sage.categories.commutative_rings import CommutativeRings from sage.categories.hopf_algebras import HopfAlgebras from sage.categories.hopf_algebras_with_basis import HopfAlgebrasWithBasis from sage.categories.principal_ideal_domains import PrincipalIdealDomains @@ -625,6 +625,11 @@ def corresponding_basis_over(self, R): sage: Sym = SymmetricFunctions(QQ) sage: m = Sym.monomial() sage: m.corresponding_basis_over(ZZ) + doctest:warning + ... + DeprecationWarning: S.corresponding_basis_over(R) is deprecated. + Use S.change_ring(R) instead. + See https://github.com/sagemath/sage/issues/37220 for details. Symmetric Functions over Integer Ring in the monomial basis sage: Sym = SymmetricFunctions(CyclotomicField()) @@ -635,7 +640,8 @@ def corresponding_basis_over(self, R): sage: P = ZZ['q','t'] sage: Sym = SymmetricFunctions(P) sage: mj = Sym.macdonald().J() - sage: mj.corresponding_basis_over(Integers(13)) + sage: mj.corresponding_basis_over(Integers(13)['q','t']) + Symmetric Functions over Multivariate Polynomial Ring in q, t over Ring of integers modulo 13 in the Macdonald J basis TESTS: @@ -644,70 +650,72 @@ def corresponding_basis_over(self, R): sage: P = QQ['q','t'] sage: Sym = SymmetricFunctions(P) sage: Q = CyclotomicField()['q','t'] - sage: Sym.s().corresponding_basis_over(CyclotomicField()) + sage: Sym.s().change_ring(CyclotomicField()) Symmetric Functions over Universal Cyclotomic Field in the Schur basis - sage: Sym.p().corresponding_basis_over(CyclotomicField()) + sage: Sym.p().change_ring(CyclotomicField()) Symmetric Functions over Universal Cyclotomic Field in the powersum basis - sage: Sym.m().corresponding_basis_over(CyclotomicField()) + sage: Sym.m().change_ring(CyclotomicField()) Symmetric Functions over Universal Cyclotomic Field in the monomial basis - sage: Sym.e().corresponding_basis_over(CyclotomicField()) + sage: Sym.e().change_ring(CyclotomicField()) Symmetric Functions over Universal Cyclotomic Field in the elementary basis - sage: Sym.h().corresponding_basis_over(CyclotomicField()) + sage: Sym.h().change_ring(CyclotomicField()) Symmetric Functions over Universal Cyclotomic Field in the homogeneous basis - sage: Sym.f().corresponding_basis_over(CyclotomicField()) + sage: Sym.f().change_ring(CyclotomicField()) Symmetric Functions over Universal Cyclotomic Field in the forgotten basis - sage: Sym.w().corresponding_basis_over(CyclotomicField()) + sage: Sym.w().change_ring(CyclotomicField()) Symmetric Functions over Universal Cyclotomic Field in the Witt basis - sage: Sym.macdonald().P().corresponding_basis_over(CyclotomicField()) - sage: Sym.macdonald().Q().corresponding_basis_over(CyclotomicField()) - sage: Sym.macdonald().J().corresponding_basis_over(CyclotomicField()) - sage: Sym.macdonald().H().corresponding_basis_over(CyclotomicField()) - sage: Sym.macdonald().Ht().corresponding_basis_over(CyclotomicField()) - sage: Sym.macdonald().S().corresponding_basis_over(CyclotomicField()) - sage: Sym.macdonald(q=1).S().corresponding_basis_over(CyclotomicField()) - sage: Sym.macdonald(q=1,t=3).P().corresponding_basis_over(CyclotomicField()) - sage: Sym.hall_littlewood().P().corresponding_basis_over(CyclotomicField()) - sage: Sym.hall_littlewood().Q().corresponding_basis_over(CyclotomicField()) - sage: Sym.hall_littlewood().Qp().corresponding_basis_over(CyclotomicField()) - sage: Sym.hall_littlewood(t=1).P().corresponding_basis_over(CyclotomicField()) - sage: Sym.jack().J().corresponding_basis_over(CyclotomicField()) - sage: Sym.jack().P().corresponding_basis_over(CyclotomicField()) - sage: Sym.jack().Q().corresponding_basis_over(CyclotomicField()) - sage: Sym.jack().Qp().corresponding_basis_over(CyclotomicField()) - sage: Sym.jack(t=1).J().corresponding_basis_over(CyclotomicField()) - sage: Sym.zonal().corresponding_basis_over(CyclotomicField()) + sage: Sym.macdonald().P().change_ring(CyclotomicField()['q', 't']) + Symmetric Functions over Multivariate Polynomial Ring in q, t over Universal Cyclotomic Field in the Macdonald P basis + sage: Sym.macdonald().Q().change_ring(CyclotomicField()['q', 't']) + Symmetric Functions over Multivariate Polynomial Ring in q, t over Universal Cyclotomic Field in the Macdonald Q basis + sage: Sym.macdonald().J().change_ring(CyclotomicField()['q', 't']) + Symmetric Functions over Multivariate Polynomial Ring in q, t over Universal Cyclotomic Field in the Macdonald J basis + sage: Sym.macdonald().H().change_ring(CyclotomicField()['q', 't']) + Symmetric Functions over Multivariate Polynomial Ring in q, t over Universal Cyclotomic Field in the Macdonald H basis + sage: Sym.macdonald().Ht().change_ring(CyclotomicField()['q', 't']) + Symmetric Functions over Multivariate Polynomial Ring in q, t over Universal Cyclotomic Field in the Macdonald Ht basis + sage: Sym.macdonald().S().change_ring(CyclotomicField()['q', 't']) + Symmetric Functions over Multivariate Polynomial Ring in q, t over Universal Cyclotomic Field in the Macdonald S basis + sage: Sym.macdonald(q=1).S().change_ring(CyclotomicField()['t']) + Symmetric Functions over Univariate Polynomial Ring in t over Universal Cyclotomic Field in the Macdonald S with q=1 basis + sage: Sym.macdonald(q=1,t=3).P().change_ring(CyclotomicField()) + Symmetric Functions over Universal Cyclotomic Field in the Macdonald P with q=1 and t=3 basis + sage: Sym.hall_littlewood().P().change_ring(CyclotomicField()['t']) + Symmetric Functions over Univariate Polynomial Ring in t over Universal Cyclotomic Field in the Hall-Littlewood P basis + sage: Sym.hall_littlewood().Q().change_ring(CyclotomicField()['t']) + Symmetric Functions over Univariate Polynomial Ring in t over Universal Cyclotomic Field in the Hall-Littlewood Q basis + sage: Sym.hall_littlewood().Qp().change_ring(CyclotomicField()['t']) + Symmetric Functions over Univariate Polynomial Ring in t over Universal Cyclotomic Field in the Hall-Littlewood Qp basis + sage: Sym.hall_littlewood(t=1).P().change_ring(CyclotomicField()) + Symmetric Functions over Universal Cyclotomic Field in the Hall-Littlewood P with t=1 basis + sage: Sym.jack().J().change_ring(CyclotomicField()['t']) + Symmetric Functions over Univariate Polynomial Ring in t over Universal Cyclotomic Field in the Jack J basis + sage: Sym.jack().P().change_ring(CyclotomicField()['t']) + Symmetric Functions over Univariate Polynomial Ring in t over Universal Cyclotomic Field in the Jack P basis + sage: Sym.jack().Q().change_ring(CyclotomicField()['t']) + Symmetric Functions over Univariate Polynomial Ring in t over Universal Cyclotomic Field in the Jack Q basis + sage: Sym.jack().Qp().change_ring(CyclotomicField()['t']) + Symmetric Functions over Univariate Polynomial Ring in t over Universal Cyclotomic Field in the Jack Qp basis + sage: Sym.jack(t=1).J().change_ring(CyclotomicField()) + Symmetric Functions over Universal Cyclotomic Field in the Jack J with t=1 basis + sage: Sym.zonal().change_ring(CyclotomicField()) Symmetric Functions over Universal Cyclotomic Field in the zonal basis - sage: Sym.llt(3).hspin().corresponding_basis_over(CyclotomicField()) - sage: Sym.llt(3).hcospin().corresponding_basis_over(CyclotomicField()) - sage: Sym.llt(3, t=1).hspin().corresponding_basis_over(CyclotomicField()) - sage: Sym.llt(3, t=1).hcospin().corresponding_basis_over(CyclotomicField()) - - .. TODO:: - - This function is an ugly hack using strings. It should be - rewritten as soon as the bases of ``SymmetricFunctions`` are - put on a more robust and systematic footing. + sage: Sym.llt(3).hspin().change_ring(CyclotomicField()['t']) + Symmetric Functions over Univariate Polynomial Ring in t over Universal Cyclotomic Field in the level 3 LLT spin basis + sage: Sym.llt(3).hcospin().change_ring(CyclotomicField()['t']) + Symmetric Functions over Univariate Polynomial Ring in t over Universal Cyclotomic Field in the level 3 LLT cospin basis + sage: Sym.llt(3, t=1).hspin().change_ring(CyclotomicField()) + Symmetric Functions over Universal Cyclotomic Field in the level 3 LLT spin with t=1 basis + sage: Sym.llt(3, t=1).hcospin().change_ring(CyclotomicField()) + Symmetric Functions over Universal Cyclotomic Field in the level 3 LLT cospin with t=1 basis """ - from sage.combinat.sf.sf import SymmetricFunctions - from sage.misc.call import attrcall + from sage.misc.superseded import deprecation + deprecation(37220, 'S.corresponding_basis_over(R) is deprecated.' + ' Use S.change_ring(R) instead.') try: - return attrcall(self._basis)(SymmetricFunctions(R)) - except AttributeError: # or except (AttributeError, ValueError): + return self.change_ring(R) + except NotImplementedError: return None - #Alternative code proposed by Florent Hivert, which sadly fails for the - #forgotten basis (which reduces differently than the other ones): - #try: - # parentred1 = self._reduction - # parentred2 = parentred1[1][0]._reduction - # parentred2prime = tuple([parentred2[0], tuple([R]), parentred2[2]]) - # from sage.structure.unique_representation import unreduce - # parent2 = unreduce(*parentred2prime) - # parentred1prime = tuple([parentred1[0], tuple([parent2]), parentred1[2]]) - # return unreduce(*parentred1prime) - #except (AttributeError, ValueError): - # return None - #This code relied heavily on the construction of bases of - #``SymmetricFunctions`` and on their reduction. def skew_schur(self, x): """ @@ -1034,8 +1042,9 @@ def component(i, g): # == h_g[L_i] # Now let's try to find out what basis self is in, and # construct the corresponding basis of symmetric functions # over QQ. - corresponding_parent_over_QQ = self.corresponding_basis_over(QQ) - if corresponding_parent_over_QQ is None: + try: + corresponding_parent_over_QQ = self.change_ring(QQ) + except (NotImplementedError, TypeError): # This is the case where the corresponding basis # over QQ cannot be found. This can have two reasons: # Either the basis depends on variables (like the @@ -1051,7 +1060,7 @@ def component(i, g): # == h_g[L_i] corresponding_result = corresponding_parent_over_QQ.gessel_reutenauer(lam) comp_base_ring = comp_parent.base_ring() result = comp_parent.sum_of_terms((nu, comp_base_ring(c)) - for nu, c in corresponding_result) + for nu, c in corresponding_result) return self(result) # just in case comp_parent != self. higher_lie_character = gessel_reutenauer @@ -1188,8 +1197,8 @@ def lehrer_solomon(self, lam): def component(i, g): # == h_g[L_i] or e_g[L_i] L_i = p.sum_of_terms(((_Partitions([d] * (i//d)), R(mu(d))) - for d in squarefree_divisors(i)), - distinct=True) / i + for d in squarefree_divisors(i)), + distinct=True) / i if not i % 2: return p(e[g]).plethysm(L_i.omega()) else: @@ -1205,8 +1214,9 @@ def component(i, g): # == h_g[L_i] or e_g[L_i] # Now let's try to find out what basis self is in, and # construct the corresponding basis of symmetric functions # over QQ. - corresponding_parent_over_QQ = self.corresponding_basis_over(QQ) - if corresponding_parent_over_QQ is None: + try: + corresponding_parent_over_QQ = self.change_ring(QQ) + except (NotImplementedError, TypeError): # This is the case where the corresponding basis # over QQ cannot be found. This can have two reasons: # Either the basis depends on variables (like the @@ -1222,7 +1232,7 @@ def component(i, g): # == h_g[L_i] or e_g[L_i] corresponding_result = corresponding_parent_over_QQ.lehrer_solomon(lam) comp_base_ring = comp_parent.base_ring() result = comp_parent.sum_of_terms((nu, comp_base_ring(c)) - for nu, c in corresponding_result) + for nu, c in corresponding_result) return self(result) # just in case comp_parent != self. whitney_homology_character = lehrer_solomon @@ -1766,11 +1776,11 @@ def is_unit(self): return len(m) <= 1 and self.coefficient([]).is_unit() -# SymmetricFunctionsBases.Filtered = FilteredSymmetricFunctionsBases -# SymmetricFunctionsBases.Graded = GradedSymmetricFunctionsBases +#SymmetricFunctionsBases.Filtered = FilteredSymmetricFunctionsBases +#SymmetricFunctionsBases.Graded = GradedSymmetricFunctionsBases ##################################################################### -# ABC for bases of the symmetric functions +## ABC for bases of the symmetric functions class SymmetricFunctionAlgebra_generic(CombinatorialFreeModule): r""" @@ -1788,7 +1798,6 @@ class SymmetricFunctionAlgebra_generic(CombinatorialFreeModule): sage: s(m([2,1])) -2*s[1, 1, 1] + s[2, 1] """ - def __init__(self, Sym, basis_name=None, prefix=None, graded=True): r""" Initializes the symmetric function algebra. @@ -1818,8 +1827,7 @@ def __init__(self, Sym, basis_name=None, prefix=None, graded=True): except (TypeError, ValueError): raise ValueError("R must have a unit element") - if basis_name is not None: - self._basis = basis_name + self._basis_name = basis_name if prefix is not None: self._prefix = prefix self._sym = Sym @@ -2845,7 +2853,7 @@ def basis_name(self): sage: f.basis_name() 'forgotten' """ - return self._basis + return self._basis_name def get_print_style(self): r""" @@ -3015,6 +3023,36 @@ def coproduct_by_coercion(self, elt): return self.tensor_square().sum(coeff * tensor([self(s[x]), self(s[y])]) for ((x,y), coeff) in s(elt).coproduct()) + def construction(self): + """ + Return a pair ``(F, R)``, where ``F`` is a + :class:`SymmetricFunctionsFunctor` and `R` is a ring, such + that ``F(R)`` returns ``self``. + + EXAMPLES:: + + sage: s = SymmetricFunctions(ZZ).s() + sage: s.construction() + (SymmetricFunctionsFunctor[Schur], Integer Ring) + """ + return (SymmetricFunctionsFunctor(self, self.basis_name()), + self.base_ring()) + + def change_ring(self, R): + r""" + Return the base change of ``self`` to `R`. + + EXAMPLES:: + + sage: s = SymmetricFunctions(ZZ).s() + sage: s.change_ring(QQ) + Symmetric Functions over Rational Field in the Schur basis + """ + if R is self.base_ring(): + return self + functor, _ = self.construction() + return functor(R) + class SymmetricFunctionAlgebra_generic_Element(CombinatorialFreeModule.Element): r""" @@ -3035,7 +3073,6 @@ class SymmetricFunctionAlgebra_generic_Element(CombinatorialFreeModule.Element): m[1, 1, 1] + m[2, 1] + m[3] sage: m.set_print_style('lex') """ - def factor(self): """ Return the factorization of this symmetric function. @@ -3091,7 +3128,7 @@ def factor(self): poly = _to_polynomials([self], self.base_ring())[0] factors = poly.factor() - unit = factors.unit() + unit = self.base_ring()(factors.unit()) if factors.universe() == self.base_ring(): return Factorization(factors, unit=unit) factors = [(_from_polynomial(factor, M), exponent) @@ -4087,8 +4124,9 @@ def itensor(self, x): # Now let's try to find out what basis self is in, and # construct the corresponding basis of symmetric functions # over QQ. - corresponding_parent_over_QQ = parent.corresponding_basis_over(QQ) - if corresponding_parent_over_QQ is None: + try: + corresponding_parent_over_QQ = parent.change_ring(QQ) + except (NotImplementedError, TypeError): # This is the case where the corresponding basis # over QQ cannot be found. This can have two reasons: # Either the basis depends on variables (like the @@ -4286,7 +4324,7 @@ def reduced_kronecker_product(self, x): comp_x = comp_parent(x) # Now, comp_self and comp_x are the same as self and x, but in the # Schur basis, which we call comp_parent. - schur_Q = comp_parent.corresponding_basis_over(QQ) + schur_Q = comp_parent.change_ring(QQ) # schur_Q is the Schur basis of the symmetric functions over QQ. result = comp_parent.zero() for lam, a in comp_self: @@ -4728,8 +4766,9 @@ def f(lam, mu): return parent(p._apply_multi_module_morphism(p(self),p(x),f)) comp_parent = parent comp_self = self - corresponding_parent_over_QQ = parent.corresponding_basis_over(QQ) - if corresponding_parent_over_QQ is None: + try: + corresponding_parent_over_QQ = parent.change_ring(QQ) + except (NotImplementedError, TypeError): comp_parent = parent.realization_of().schur() comp_self = comp_parent(self) from sage.combinat.sf.sf import SymmetricFunctions @@ -5886,7 +5925,7 @@ def hl_creation_operator(self, nu, t=None): elif isinstance(nu, list) and all(isinstance(a, (int,Integer)) for a in nu): return P(s.sum(t**la.size() * c * d * s(la) * s._repeated_bernstein_creation_operator_on_basis(ga, nu) - for ((la, mu), c) in s(self).coproduct() + for ((la,mu),c) in s(self).coproduct() for (ga, d) in s(mu).plethysm((1-t)*s[1]) )) else: raise ValueError("nu must be a list of integers") @@ -6379,6 +6418,123 @@ def exponential_specialization(self, t=None, q=1): SymmetricFunctionAlgebra_generic.Element = SymmetricFunctionAlgebra_generic_Element +from sage.categories.pushout import ConstructionFunctor +from sage.categories.commutative_rings import CommutativeRings +from sage.categories.functor import Functor + +class SymmetricFunctionsFunctor(ConstructionFunctor): + """ + A constructor for algebras of symmetric functions. + + EXAMPLES:: + + sage: s = SymmetricFunctions(QQ).s() + sage: s.construction() + (SymmetricFunctionsFunctor[Schur], Rational Field) + """ + rank = 9 + + def __init__(self, basis, name): + r""" + Initialise the functor. + + INPUT: + + - ``basis`` -- the basis of the symmetric function algebra + - ``name`` -- the name of the basis + + .. NOTE:: + + The codomain of this functor could actually be + :class:`CommutativeAlgebras` over the given ring, but + parameterized functors are currently not available. + + EXAMPLES:: + + sage: from sage.combinat.sf.sfa import SymmetricFunctionsFunctor + sage: B = SymmetricFunctions(ZZ).s() + sage: SymmetricFunctionsFunctor(type(B), B.basis_name()) + SymmetricFunctionsFunctor[Schur] + """ + self._basis = basis.__class__.__base__ + self._name = name + Functor.__init__(self, CommutativeRings(), CommutativeRings()) + + def _apply_functor(self, R): + """ + Apply the functor to an object of ``self``'s domain. + + EXAMPLES:: + + sage: Sym = SymmetricFunctions(QQ) + sage: B = SymmetricFunctions(ZZ).s() + sage: F, R = B.construction() # indirect doctest + sage: F(QQbar) + Symmetric Functions over Algebraic Field in the Schur basis + """ + from sage.combinat.sf.sf import SymmetricFunctions + return self._basis(SymmetricFunctions(R)) + + def _apply_functor_to_morphism(self, f): + """ + Apply the functor ``self`` to the ring morphism `f`. + + EXAMPLES:: + + sage: s = SymmetricFunctions(QQ).s() + sage: F, R = s.construction() + sage: F(ZZ.hom(GF(3))) # indirect doctest + Generic morphism: + From: Symmetric Functions over Integer Ring in the Schur basis + To: Symmetric Functions over Finite Field of size 3 in the Schur basis + + sage: R. = ZZ[] + sage: P = SymmetricFunctions(R).jack().P() + sage: F, R = P.construction() + sage: F(ZZ["t"].hom(GF(3)["t"])) + Generic morphism: + From: Symmetric Functions over Univariate Polynomial Ring in t over Integer Ring in the Jack P basis + To: Symmetric Functions over Univariate Polynomial Ring in t over Finite Field of size 3 in the Jack P basis + + sage: R. = ZZ[] + sage: H = SymmetricFunctions(R).macdonald().H() + sage: F, R = H.construction() + sage: F(ZZ["q", "t"].hom(GF(3)["q", "t"])) # known bug + """ + dom = self(f.domain()) + codom = self(f.codomain()) + + def action(x): + return codom._from_dict({a: f(b) + for a, b in x.monomial_coefficients().items()}) + return dom.module_morphism(function=action, codomain=codom) + + def __eq__(self, other): + """ + EXAMPLES:: + + sage: B1 = SymmetricFunctions(QQ).schur() + sage: B2 = SymmetricFunctions(ZZ).s() + sage: B1.construction()[0] == B2.construction()[0] + True + """ + if not isinstance(other, type(self)): + return False + return self._basis == other._basis and self._name == other._name + + def _repr_(self): + """ + Return a string representation of ``self``. + + EXAMPLES:: + + sage: w = SymmetricFunctions(ZZ).witt() + sage: F, R = w.construction() + sage: F + SymmetricFunctionsFunctor[Witt] + """ + return "SymmetricFunctionsFunctor[" + self._name + "]" + ################### def _lmax(x): diff --git a/src/sage/combinat/sf/witt.py b/src/sage/combinat/sf/witt.py index 138b2647826..2a22ccec58b 100644 --- a/src/sage/combinat/sf/witt.py +++ b/src/sage/combinat/sf/witt.py @@ -396,8 +396,14 @@ class SymmetricFunctionAlgebra_witt(multiplicative.SymmetricFunctionAlgebra_mult ....: #this holds for all odd i and is easily proven by induction True """ + @staticmethod + def __classcall__(cls, Sym, coerce_h=True, coerce_e=False, coerce_p=False): + """ + Normalize the arguments. + """ + return super().__classcall__(cls, Sym, coerce_h, coerce_e, coerce_p) - def __init__(self, Sym, coerce_h=True, coerce_e=False, coerce_p=False): + def __init__(self, Sym, coerce_h, coerce_e, coerce_p): """ Initialize ``self``. @@ -609,7 +615,7 @@ def _precompute_h(self, n): by choosing a ground ring unlikely to appear elsewhere:: sage: Sym = SymmetricFunctions(ZZ['hell', 'yeah']) - sage: w = Sym.Witt() + sage: w = Sym.witt() sage: l = lambda c: [ (i[0],[j for j in sorted(i[1].items())]) for i in sorted(c.items())] sage: l(w._h_to_self_cache) [] @@ -673,7 +679,7 @@ def _precompute_e(self, n): by choosing a ground ring unlikely to appear elsewhere:: sage: Sym = SymmetricFunctions(ZZ['hell', 'yeah']) - sage: w = Sym.Witt(coerce_e=True) + sage: w = Sym.witt(coerce_e=True) sage: l = lambda c: [ (i[0],[j for j in sorted(i[1].items())]) for i in sorted(c.items())] sage: l(w._e_to_self_cache) [] @@ -736,7 +742,7 @@ def _precompute_p(self, n): by choosing a ground ring unlikely to appear elsewhere:: sage: Sym = SymmetricFunctions(QQ['hell', 'yeah']) - sage: w = Sym.Witt(coerce_h=False, coerce_e=True, coerce_p=True) + sage: w = Sym.witt(coerce_h=False, coerce_e=True, coerce_p=True) sage: l = lambda c: [ (i[0],[j for j in sorted(i[1].items())]) for i in sorted(c.items())] sage: l(w._p_to_self_cache) []