def __init__(self, R): """ The Hopf algebra of quasi-symmetric functions. See ``QuasiSymmetricFunctions`` for full documentation. EXAMPLES:: sage: QuasiSymmetricFunctions(QQ) Quasisymmetric functions over the Rational Field sage: TestSuite(QuasiSymmetricFunctions(QQ)).run() """ assert R in Rings() self._base = R # Won't be needed once CategoryObject won't override base_ring category = GradedHopfAlgebras(R) # TODO: .Commutative() Parent.__init__(self, category=category.WithRealizations()) # Bases Monomial = self.Monomial() Fundamental = self.Fundamental() dualImmaculate = self.dualImmaculate() # Change of bases Fundamental.module_morphism(Monomial.sum_of_finer_compositions, codomain=Monomial, category=category).register_as_coercion() Monomial.module_morphism( Fundamental.alternating_sum_of_finer_compositions, codomain=Fundamental, category=category).register_as_coercion() #This changes dualImmaculate into Monomial dualImmaculate.module_morphism( dualImmaculate._to_Monomial_on_basis, codomain=Monomial, category=category).register_as_coercion() #This changes Monomial into dualImmaculate Monomial.module_morphism(dualImmaculate._from_Monomial_on_basis, codomain=dualImmaculate, category=category).register_as_coercion() # Embedding of Sym into QSym in the monomial bases Sym = SymmetricFunctions(self.base_ring()) Sym_m_to_M = Sym.m().module_morphism( Monomial.sum_of_partition_rearrangements, triangular='upper', inverse_on_support=Monomial._comp_to_par, codomain=Monomial, category=category) Sym_m_to_M.register_as_coercion() self.to_symmetric_function = Sym_m_to_M.section()
def __init__(self, R): """ The Hopf algebra of quasi-symmetric functions. See ``QuasiSymmetricFunctions`` for full documentation. EXAMPLES:: sage: QuasiSymmetricFunctions(QQ) Quasisymmetric functions over the Rational Field sage: TestSuite(QuasiSymmetricFunctions(QQ)).run() """ assert R in Rings() self._base = R # Won't be needed once CategoryObject won't override base_ring category = GradedHopfAlgebras(R) # TODO: .Commutative() Parent.__init__(self, category = category.WithRealizations()) # Bases Monomial = self.Monomial() Fundamental = self.Fundamental() dualImmaculate = self.dualImmaculate() # Change of bases Fundamental.module_morphism(Monomial.sum_of_finer_compositions, codomain=Monomial, category=category ).register_as_coercion() Monomial .module_morphism(Fundamental.alternating_sum_of_finer_compositions, codomain=Fundamental, category=category ).register_as_coercion() #This changes dualImmaculate into Monomial dualImmaculate.module_morphism(dualImmaculate._to_Monomial_on_basis, codomain = Monomial, category = category ).register_as_coercion() #This changes Monomial into dualImmaculate Monomial.module_morphism(dualImmaculate._from_Monomial_on_basis, codomain = dualImmaculate, category = category ).register_as_coercion() # Embedding of Sym into QSym in the monomial bases Sym = SymmetricFunctions(self.base_ring()) Sym_m_to_M = Sym.m().module_morphism(Monomial.sum_of_partition_rearrangements, triangular='upper', inverse_on_support=Monomial._comp_to_par, codomain=Monomial, category=category) Sym_m_to_M.register_as_coercion() self.to_symmetric_function = Sym_m_to_M.section()
def polarizationSpace(P, generators, verbose=False, row_symmetry=None, use_commutativity=False, side="down"): """ Starting from polynomials (generators)of the polynomial ring in one set of variables (possibly with additional inert variables), constructs the space obtained by polarization. The possible values for row_symmetry : - "permutation" : the action of the symmetric group on the rows - "euler+intersection" or "decompose" or "multipolarization" for stategies on lie algebras INPUT: - `P` -- a diagonal polynomial ring (or assymmetric version) - `generators`: polynomials in one set of variables (and possibly inert variables) OUTPUT: `F` -- a Subspace EXAMPLES:: sage: load("derivative_space.py") sage: P = DiagonalPolynomialRing(QQ, 3, 2, inert=1) sage: mu = Partition([3]) sage: basis = DerivativeHarmonicSpace(QQ, mu.size()).basis_by_shape(Partition([2,1])) sage: generators = {} sage: for gen in basis : ....: d = P.multidegree((P(gen))) ....: if d in generators.keys(): ....: generators[d] += [P(gen)] ....: else: ....: generators[d] = [P(gen)] sage: generators {(2, 0): [1/3*x00^2 - 2/3*x00*x01 + 2/3*x01*x02 - 1/3*x02^2], (1, 0): [-2*x00 + 2*x02]} sage: S = polarizationSpace(P, generators) sage: S.basis() {(0, 1): (x10 - x12,), (2, 0): (-1/2*x00^2 + x00*x01 - x01*x02 + 1/2*x02^2,), (1, 0): (x00 - x02,), (1, 1): (x00*x10 - x01*x10 - x00*x11 + x02*x11 + x01*x12 - x02*x12,), (0, 2): (1/2*x10^2 - x10*x11 + x11*x12 - 1/2*x12^2,)} sage: basis = DerivativeVandermondeSpaceWithInert(QQ, mu).basis_by_shape(Partition([1,1,1])) sage: generators = {P.multidegree(P(gen)): [P(gen) for gen in g] for (d,g) in basis.iteritems()} sage: generators {(3, 0): [-x00^2*x01 + x00*x01^2 + x00^2*x02 - x01^2*x02 - x00*x02^2 + x01*x02^2]} sage: S = polarizationSpace(P, generators) sage: S.basis() {(1, 2): (-1/2*x01*x10^2 + 1/2*x02*x10^2 - x00*x10*x11 + x01*x10*x11 + 1/2*x00*x11^2 - 1/2*x02*x11^2 + x00*x10*x12 - x02*x10*x12 - x01*x11*x12 + x02*x11*x12 - 1/2*x00*x12^2 + 1/2*x01*x12^2,), (3, 0): (x00^2*x01 - x00*x01^2 - x00^2*x02 + x01^2*x02 + x00*x02^2 - x01*x02^2,), (0, 3): (x10^2*x11 - x10*x11^2 - x10^2*x12 + x11^2*x12 + x10*x12^2 - x11*x12^2,), (1, 1): (-x01*x10 + x02*x10 + x00*x11 - x02*x11 - x00*x12 + x01*x12,), (2, 1): (-x00*x01*x10 + 1/2*x01^2*x10 + x00*x02*x10 - 1/2*x02^2*x10 - 1/2*x00^2*x11 + x00*x01*x11 - x01*x02*x11 + 1/2*x02^2*x11 + 1/2*x00^2*x12 - 1/2*x01^2*x12 - x00*x02*x12 + x01*x02*x12,)} sage: mu = Partition([2,1]) sage: basis = DerivativeVandermondeSpaceWithInert(QQ, mu).basis_by_shape(Partition([2,1])) sage: generators = {P.multidegree(P(gen)): [P(gen) for gen in g] for (d,g) in basis.iteritems()} sage: generators {(0, 0): [-theta00 + theta02]} sage: S = polarizationSpace(P, generators) sage: S.basis() {(0, 0): (theta00 - theta02,)} """ S = SymmetricFunctions(QQ) s = S.s() m = S.m() r = P._r if isinstance(P, DiagonalAntisymmetricPolynomialRing): antisymmetries = P._antisymmetries else: antisymmetries = None if row_symmetry in ("euler+intersection", "decompose", "multipolarization") : # The hilbert series will be directly expressed in terms of the # dimensions of the highest weight spaces, thus as a symmetric # function in the Schur basis def hilbert_parent(dimensions): return s.sum_of_terms([Partition(d), c] for d,c in dimensions.iteritems() if c) elif row_symmetry == "permutation": def hilbert_parent(dimensions): return s(m.sum_of_terms([Partition(d), c] for d,c in dimensions.iteritems()) ).restrict_partition_lengths(r, exact=False) else: def hilbert_parent(dimensions): return s(S.from_polynomial(P._hilbert_parent(dimensions)) ).restrict_partition_lengths(r,exact=False) operators = polarization_operators_by_multidegree(P, side=side, row_symmetry=row_symmetry, min_degree=1 if row_symmetry and row_symmetry!="permutation" else 0) #ajout operateurs Steenrod #for i in range(1, r): # for d in [2,3]: # operators[P._grading_set((-d+1 if j==i else 0 for j in range(0,r)))] = [functools.partial(P.steenrod_op, i=i, k=d)] if row_symmetry == "euler+intersection": operators[P._grading_set.zero()] = [ functools.partial(lambda v,i: P.polarization(P.polarization(v, i+1, i, 1, antisymmetries=antisymmetries), i, i+1, 1, antisymmetries=antisymmetries), i=i) for i in range(r-1)] elif row_symmetry == "decompose": def post_compose(f): return lambda x: [q for (q,word) in P.highest_weight_vectors_decomposition(f(x))] operators = {d: [post_compose(op) for op in ops]for d, ops in operators.iteritems()} elif row_symmetry == "multipolarization": F = HighestWeightSubspace(generators, ambient=self, add_degrees=add_degree, degree=P.multidegree, hilbert_parent = hilbert_parent, antisymmetries=antisymmetries, verbose=verbose) return F operators_by_degree = {} for degree,ops in operators.iteritems(): d = sum(degree) operators_by_degree.setdefault(d,[]) operators_by_degree[d].extend(ops) ranks = {} for d, ops in operators_by_degree.iteritems(): ranker = rank_from_list(ops) for op in ops: ranks[op] = (d, ranker(op)) ranker = ranks.__getitem__ def extend_word(word, op): new_word = word + [ranker(op)] if use_commutativity and sorted(new_word) != new_word: return None return new_word if row_symmetry == "permutation": add_deg = add_degree_symmetric else: add_deg = add_degree F = Subspace(generators, operators=operators, add_degrees=add_deg, degree=P.multidegree, hilbert_parent = hilbert_parent, extend_word=extend_word, verbose=verbose) F._antisymmetries = antisymmetries return F
def higher_specht(R, P, Q=None, harmonic=False, use_antisymmetry=False): """ Return a basis element of the coinvariants INPUT: - `R` -- a polynomial ring - `P` -- a standard tableau of some shape `\lambda`, or a partition `\lambda` - `Q` -- a standard tableau of shape `\lambda` (default: the initial tableau of shape `\lambda`) - ``harmonic`` -- a boolean (default False) The family `(H_{P,Q})_{P,Q}` is a basis of the space of `R_{S_n}` coinvariants in `R` which is compatible with the action of the symmetric group: namely, for each `P`, the family `(H_{P,Q})_Q` forms the basis of an `S_n`-irreducible module `V_{P}` of type `\lambda`. If `P` is a partition `\lambda` or equivalently the initial tableau of shape `\lambda`, then `H_{P,Q}` is the usual Specht polynomial, and `V_P` the Specht module. EXAMPLES:: sage: Tableaux.options.convention="french" sage: R = PolynomialRing(QQ, 'x,y,z') sage: for la in Partitions(3): ....: for P in StandardTableaux(la): ....: for Q in StandardTableaux(la): ....: print(ascii_art(la, P, Q, factor(higher_specht(R, P, Q)), sep=" ")) ....: print *** 1 2 3 1 2 3 2 * 3 <built-in function print> * 2 2 ** 1 3 1 3 (-1) * z * (x - y) <built-in function print> * 2 3 ** 1 3 1 2 (-1) * y * (x - z) <built-in function print> * 3 2 ** 1 2 1 3 (-2) * (x - y) <built-in function print> * 3 3 ** 1 2 1 2 (-2) * (x - z) <built-in function print> * 3 3 * 2 2 * 1 1 (y - z) * (-x + y) * (x - z) <built-in function print> sage: factor(higher_specht(R, Partition([2,1]))) (-2) * (x - z) sage: for la in Partitions(3): ....: for P in StandardTableaux(la): ....: print(ascii_art(la, P, factor(higher_specht(R, P)), sep=" ")) ....: print *** 1 2 3 2 * 3 <built-in function print> * 2 ** 1 3 (-1) * y * (x - z) <built-in function print> * 3 ** 1 2 (-2) * (x - z) <built-in function print> * 3 * 2 * 1 (y - z) * (-x + y) * (x - z) <built-in function print> sage: R = PolynomialRing(QQ, 'x,y,z') sage: for la in Partitions(3): ....: for P in StandardTableaux(la): ....: for Q in StandardTableaux(la): ....: print(ascii_art(la, P, Q, factor(higher_specht(R, P, Q, harmonic=True)), sep=" ")) ....: print *** 1 2 3 1 2 3 2 * 3 <built-in function print> * 2 2 ** 1 3 1 3 (-1/3) * (-x - y + 2*z) * (x - y) <built-in function print> * 2 3 ** 1 3 1 2 (-1/3) * (-x + 2*y - z) * (x - z) <built-in function print> * 3 2 ** 1 2 1 3 (-2) * (x - y) <built-in function print> * 3 3 ** 1 2 1 2 (-2) * (x - z) <built-in function print> * 3 3 * 2 2 * 1 1 (y - z) * (-x + y) * (x - z) <built-in function print> sage: R = PolynomialRing(QQ, 'x,y,z') sage: for la in Partitions(3): ....: for P in StandardTableaux(la): ....: for Q in StandardTableaux(la): ....: print(ascii_art(la, P, Q, factor(higher_specht(R, P, Q, harmonic="dual")), sep=" ")) ....: print *** 1 2 3 1 2 3 2^2 * 3 <built-in function print> * 2 2 ** 1 3 1 3 (-2) * (-x^2 - 2*x*y + 2*y^2 + 4*x*z - 2*y*z - z^2) <built-in function print> * 2 3 ** 1 3 1 2 (-2) * (x^2 - 4*x*y + y^2 + 2*x*z + 2*y*z - 2*z^2) <built-in function print> * 3 2 ** 1 2 1 3 (-2) * (-x + 2*y - z) <built-in function print> * 3 3 ** 1 2 1 2 (-2) * (x + y - 2*z) <built-in function print> * 3 3 * 2 2 * 1 1 (6) * (y - z) * (-x + y) * (x - z) <built-in function print> This caught two bugs:: sage: R = DerivativeHarmonicSpace(QQ, 6) sage: for mu in Partitions(6): # long time ....: for t in StandardTableaux(mu): ....: p = R.higher_specht(t, harmonic=True, use_antisymmetry=True) """ if not isinstance(P, StandardTableau): P = Partition(P).initial_tableau() n = P.size() assert (n == R.ngens()), "Given partition doesn't have the right size." if Q is None: Q = P.shape().initial_tableau() if harmonic == "dual": # Computes an harmonic polynomial obtained by applying h as # differential operator on the van der mond P = P.conjugate() Q = Q.conjugate() # Is this really what we want? h = higher_specht(R, P, Q) vdm = higher_specht(R, Partition([1] * n).initial_tableau()) return polynomial_derivative(h, vdm) elif harmonic: # TODO: normalization n = R.ngens() Sym = SymmetricFunctions(R.base_ring()) m = Sym.m() p = Sym.p() d = P.cocharge() B = [higher_specht(R, P, Q, use_antisymmetry=use_antisymmetry)] + \ [higher_specht(R, P2, Q, use_antisymmetry=use_antisymmetry) * m[nu].expand(n, R.gens()) for P2 in StandardTableaux(P.shape()) if P2.cocharge() < d for nu in Partitions(d-P2.cocharge(), max_length=n)] if use_antisymmetry: antisymmetries = antisymmetries_of_tableau(Q) B = [antisymmetric_normal(b, n, 1, antisymmetries) for b in B] operators = [p[k].expand(n, R.gens()) for k in range(1, n + 1)] if use_antisymmetry: def action(e, f): return antisymmetric_normal(polynomial_derivative(e, f), n, 1, antisymmetries) else: action = polynomial_derivative ann = annihilator_basis(B, operators, action=action, side='left') assert len(ann) == 1 return ann[0] exponents = index_filling(P) X = R.gens() m = R.prod(X[i - 1]**d for (d, i) in zip(exponents.entries(), Q.entries())) return apply_young_idempotent(m, Q, use_antisymmetry=use_antisymmetry)