def __init__(self, base_ring=QQ['t'], prefix='S'): r""" Initialize ``self``. EXAMPLES:: sage: S = ShiftingOperatorAlgebra(QQ['t']) sage: TestSuite(S).run() """ indices = ShiftingSequenceSpace() cat = Algebras(base_ring).WithBasis() CombinatorialFreeModule.__init__(self, base_ring, indices, prefix=prefix, bracket=False, category=cat) # Setup default conversions sym = SymmetricFunctions(base_ring) self._sym_h = sym.h() self._sym_s = sym.s() self._sym_h.register_conversion( self.module_morphism(self._supp_to_h, codomain=self._sym_h)) self._sym_s.register_conversion( self.module_morphism(self._supp_to_s, codomain=self._sym_s))
def __init__(self, R): """ Initialize ``self``. EXAMPLES:: sage: TestSuite(SymmetricFunctionsNonCommutingVariables(QQ).dual()).run() """ 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 w = self.w() # Embedding of Sym in the homogeneous bases into DNCSym in the w basis Sym = SymmetricFunctions(self.base_ring()) Sym_h_to_w = Sym.h().module_morphism( w.sum_of_partitions, triangular='lower', inverse_on_support=w._set_par_to_par, codomain=w, category=category) Sym_h_to_w.register_as_coercion() self.to_symmetric_function = Sym_h_to_w.section()
def K_k_Schur_non_commutative_variables(self,la): r""" Returns the K-`k`-Schur function, as embedded inside the affine zero Hecke algebra. INPUT: - ``la`` -- A `k`-bounded Partition OUTPUT: - An element of the affine zero Hecke algebra. EXAMPLES:: sage: g = SymmetricFunctions(QQ).kBoundedSubspace(3,1).K_kschur() sage: g.K_k_Schur_non_commutative_variables([2,1]) T3*T1*T0 + T1*T2*T0 + T3*T2*T0 - T2*T0 + T0*T1*T0 + T2*T0*T1 + T0*T3*T0 + T2*T0*T3 + T0*T3*T1 + T2*T3*T2 - T3*T1 + T2*T3*T1 + T3*T1*T2 + T1*T2*T1 sage: g.K_k_Schur_non_commutative_variables([]) 1 sage: g.K_k_Schur_non_commutative_variables([4,1]) Traceback (most recent call last): ... ValueError: Partition should be 3-bounded """ SF = SymmetricFunctions(self.base_ring()) h = SF.h() S = h(self._g_to_kh_on_basis(la)).support() return sum(h(self._g_to_kh_on_basis(la)).coefficient(x)*self.homogeneous_basis_noncommutative_variables_zero_Hecke(x) for x in S)
def _cl_term(n, R=RationalField()): """ Compute the order-n term of the cycle index series of the virtual species `\Omega`, the compositional inverse of the species `E^{+}` of nonempty sets. EXAMPLES:: sage: from sage.combinat.species.generating_series import _cl_term sage: [_cl_term(i) for i in range(4)] [0, p[1], -1/2*p[1, 1] - 1/2*p[2], 1/3*p[1, 1, 1] - 1/3*p[3]] """ n = Integer(n) #check that n is an integer p = SymmetricFunctions(R).power() res = p.zero() if n == 1: res = p([1]) elif n > 1: res = 1 / n * ((-1)**(n - 1) * p([1])**n - sum(d * p([Integer(n / d)]).plethysm(_cl_term(d, R)) for d in divisors(n)[:-1])) return res
def __init__(self, R): """ Initialize ``self``. EXAMPLES:: sage: NCSymD1 = SymmetricFunctionsNonCommutingVariablesDual(FiniteField(23)) sage: NCSymD2 = SymmetricFunctionsNonCommutingVariablesDual(Integers(23)) sage: TestSuite(SymmetricFunctionsNonCommutingVariables(QQ).dual()).run() """ # change the line below to assert(R in Rings()) once MRO issues from #15536, #15475 are resolved assert(R in Fields() or R in Rings()) # side effect of this statement assures MRO exists for R 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 w = self.w() # Embedding of Sym in the homogeneous bases into DNCSym in the w basis Sym = SymmetricFunctions(self.base_ring()) Sym_h_to_w = Sym.h().module_morphism(w.sum_of_partitions, triangular='lower', inverse_on_support=w._set_par_to_par, codomain=w, category=category) Sym_h_to_w.register_as_coercion() self.to_symmetric_function = Sym_h_to_w.section()
def __init__(self, w, n, x=None): r""" EXAMPLES:: sage: B = crystals.AffineFactorization([[3,2],[2]],4,x=0,k=3) Traceback (most recent call last): ... ValueError: x cannot be in reduced word of s0*s3*s2 sage: B = crystals.AffineFactorization([[3,2],[2]],4,k=3) sage: B.x 1 sage: B.w s0*s3*s2 sage: B.k 3 sage: B.n 4 TESTS:: sage: W = WeylGroup(['A',3,1], prefix='s') sage: w = W.from_reduced_word([2,3,2,1]) sage: B = crystals.AffineFactorization(w,3) sage: TestSuite(B).run() """ Parent.__init__(self, category=ClassicalCrystals()) self.n = n self.k = w.parent().n - 1 self.w = w cartan_type = CartanType(['A', n - 1]) self._cartan_type = cartan_type from sage.combinat.sf.sf import SymmetricFunctions from sage.rings.rational_field import QQ Sym = SymmetricFunctions(QQ) s = Sym.schur() support = s(w.stanley_symmetric_function()).support() support = [[0] * (n - len(mu)) + [mu[len(mu) - i - 1] for i in range(len(mu))] for mu in support] generators = [ tuple(p) for mu in support for p in affine_factorizations(w, n, mu) ] #generators = [tuple(p) for p in affine_factorizations(w, n)] self.module_generators = [self(t) for t in generators] if x is None: if generators: x = min( set(range(self.k + 1)).difference( set(sum([i.reduced_word() for i in generators[0]], [])))) else: x = 0 if x in set(w.reduced_word()): raise ValueError("x cannot be in reduced word of {}".format(w)) self.x = x
def k_schur_noncommutative_variables(self, la): r""" In type `A^{(1)}` this is the `k`-Schur function in noncommutative variables defined by Thomas Lam. REFERENCES: .. [Lam2005] T. Lam, Affine Stanley symmetric functions, Amer. J. Math. 128 (2006), no. 6, 1553--1586. This function is currently only defined in type `A^{(1)}`. INPUT: - ``la`` -- a partition with first part bounded by the rank of the Weyl group EXAMPLES:: sage: A = NilCoxeterAlgebra(WeylGroup(['A',3,1])) sage: A.k_schur_noncommutative_variables([2,2]) u[0,3,1,0] + u[3,1,2,0] + u[1,2,0,1] + u[3,2,0,3] + u[2,0,3,1] + u[2,3,1,2] TESTS:: sage: A = NilCoxeterAlgebra(WeylGroup(['A',3,1])) sage: A.k_schur_noncommutative_variables([]) 1 sage: A.k_schur_noncommutative_variables([1,2]) Traceback (most recent call last): ... AssertionError: [1, 2] is not a partition. sage: A.k_schur_noncommutative_variables([4,2]) Traceback (most recent call last): ... AssertionError: [4, 2] is not a 3-bounded partition. sage: C = NilCoxeterAlgebra(WeylGroup(['C',3,1])) sage: C.k_schur_noncommutative_variables([2,2]) Traceback (most recent call last): ... AssertionError: Weyl Group of type ['C', 3, 1] (as a matrix group acting on the root space) is not affine type A. """ assert self._cartan_type[0] == 'A' and len( self._cartan_type) == 3 and self._cartan_type[ 2] == 1, "%s is not affine type A." % (self._W) assert la in Partitions(), "%s is not a partition." % (la) assert (len(la) == 0 or la[0] < self._W.n ), "%s is not a %s-bounded partition." % (la, self._W.n - 1) Sym = SymmetricFunctions(self._base_ring) h = Sym.homogeneous() ks = Sym.kschur(self._n - 1, 1) f = h(ks[la]) return sum( f.coefficient(x) * self.homogeneous_noncommutative_variables(x) for x in f.support())
def k_schur_noncommutative_variables(self, la): r""" In type `A^{(1)}` this is the `k`-Schur function in noncommutative variables defined by Thomas Lam. REFERENCES: .. [Lam2005] T. Lam, Affine Stanley symmetric functions, Amer. J. Math. 128 (2006), no. 6, 1553--1586. This function is currently only defined in type `A^{(1)}`. INPUT: - ``la`` -- a partition with first part bounded by the rank of the Weyl group EXAMPLES:: sage: A = NilCoxeterAlgebra(WeylGroup(['A',3,1])) sage: A.k_schur_noncommutative_variables([2,2]) u[0,3,1,0] + u[3,1,2,0] + u[1,2,0,1] + u[3,2,0,3] + u[2,0,3,1] + u[2,3,1,2] TESTS:: sage: A = NilCoxeterAlgebra(WeylGroup(['A',3,1])) sage: A.k_schur_noncommutative_variables([]) 1 sage: A.k_schur_noncommutative_variables([1,2]) Traceback (most recent call last): ... AssertionError: [1, 2] is not a partition. sage: A.k_schur_noncommutative_variables([4,2]) Traceback (most recent call last): ... AssertionError: [4, 2] is not a 3-bounded partition. sage: C = NilCoxeterAlgebra(WeylGroup(['C',3,1])) sage: C.k_schur_noncommutative_variables([2,2]) Traceback (most recent call last): ... AssertionError: Weyl Group of type ['C', 3, 1] (as a matrix group acting on the root space) is not affine type A. """ assert self._cartan_type[0] == 'A' and len(self._cartan_type) == 3 and self._cartan_type[2] == 1, "%s is not affine type A."%(self._W) assert la in Partitions(), "%s is not a partition."%(la) assert (len(la) == 0 or la[0] < self._W.n), "%s is not a %s-bounded partition."%(la, self._W.n-1) Sym = SymmetricFunctions(self._base_ring) h = Sym.homogeneous() ks = Sym.kschur(self._n-1,1) f = h(ks[la]) return sum(f.coefficient(x)*self.homogeneous_noncommutative_variables(x) for x in f.support())
def __init__(self, R, k, t=None): """ EXAMPLES:: sage: kSchurFunctions(QQ, 3).base_ring() doctest:1: DeprecationWarning: Deprecation warning: Please use SymmetricFunctions(QQ).kschur() instead! See http://trac.sagemath.org/5457 for details. Univariate Polynomial Ring in t over Rational Field sage: kSchurFunctions(QQ, 3, t=1).base_ring() Rational Field sage: ks3 = kSchurFunctions(QQ, 3) sage: ks3 == loads(dumps(ks3)) True """ self.k = k self._name = "k-Schur Functions at level %s" % k self._prefix = "ks%s" % k self._element_class = kSchurFunctions_t.Element if t is None: R = R['t'] self.t = R.gen() elif t not in R: raise ValueError, "t (=%s) must be in R (=%s)" % (t, R) else: self.t = R(t) if str(t) != 't': self._name += " with t=%s" % self.t self._s_to_self_cache = s_to_k_cache.get(k, {}) self._self_to_s_cache = k_to_s_cache.get(k, {}) # This is an abuse, since kschur functions do not form a basis of Sym from sage.combinat.sf.sf import SymmetricFunctions Sym = SymmetricFunctions(R) sfa.SymmetricFunctionAlgebra_generic.__init__(self, Sym) # so we need to take some counter measures self._basis_keys = sage.combinat.partition.Partitions(max_part=k) # The following line is just a temporary workaround to keep # the repr of those k-schur as they were before #13404; since # they are deprecated, there is no need to bother about them. self.rename(self._name + " over %s" % self.base_ring()) self._s = Sym.s() # temporary until Hom(GradedHopfAlgebrasWithBasis work better) category = sage.categories.all.ModulesWithBasis(self.base_ring()) # This really should be a conversion, not a coercion (it can fail) 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 __init__(self, w, n, x = None): r""" EXAMPLES:: sage: B = crystals.AffineFactorization([[3,2],[2]],4,x=0,k=3) Traceback (most recent call last): ... ValueError: x cannot be in reduced word of s0*s3*s2 sage: B = crystals.AffineFactorization([[3,2],[2]],4,k=3) sage: B.x 1 sage: B.w s0*s3*s2 sage: B.k 3 sage: B.n 4 TESTS:: sage: W = WeylGroup(['A',3,1], prefix='s') sage: w = W.from_reduced_word([2,3,2,1]) sage: B = crystals.AffineFactorization(w,3) sage: TestSuite(B).run() """ Parent.__init__(self, category = ClassicalCrystals()) self.n = n self.k = w.parent().n-1 self.w = w cartan_type = CartanType(['A',n-1]) self._cartan_type = cartan_type from sage.combinat.sf.sf import SymmetricFunctions from sage.rings.all import QQ Sym = SymmetricFunctions(QQ) s = Sym.schur() support = s(w.stanley_symmetric_function()).support() support = [ [0]*(n-len(mu))+[mu[len(mu)-i-1] for i in range(len(mu))] for mu in support] generators = [tuple(p) for mu in support for p in affine_factorizations(w,n,mu)] #generators = [tuple(p) for p in affine_factorizations(w, n)] self.module_generators = [self(t) for t in generators] if x is None: if generators != []: x = min( set(range(self.k+1)).difference(set( sum([i.reduced_word() for i in generators[0]],[])))) else: x = 0 if x in set(w.reduced_word()): raise ValueError("x cannot be in reduced word of {}".format(w)) self.x = x
def __init__(self, R, k, t=None): """ EXAMPLES:: sage: kSchurFunctions(QQ, 3).base_ring() doctest:1: DeprecationWarning: Deprecation warning: Please use SymmetricFunctions(QQ).kschur() instead! See http://trac.sagemath.org/5457 for details. Univariate Polynomial Ring in t over Rational Field sage: kSchurFunctions(QQ, 3, t=1).base_ring() Rational Field sage: ks3 = kSchurFunctions(QQ, 3) sage: ks3 == loads(dumps(ks3)) True """ self.k = k self._name = "k-Schur Functions at level %s"%k self._prefix = "ks%s"%k self._element_class = kSchurFunctions_t.Element if t is None: R = R['t'] self.t = R.gen() elif t not in R: raise ValueError, "t (=%s) must be in R (=%s)"%(t,R) else: self.t = R(t) if str(t) != 't': self._name += " with t=%s"%self.t self._s_to_self_cache = s_to_k_cache.get(k, {}) self._self_to_s_cache = k_to_s_cache.get(k, {}) # This is an abuse, since kschur functions do not form a basis of Sym from sage.combinat.sf.sf import SymmetricFunctions Sym = SymmetricFunctions(R) sfa.SymmetricFunctionAlgebra_generic.__init__(self, Sym) # so we need to take some counter measures self._basis_keys = sage.combinat.partition.Partitions(max_part=k) # The following line is just a temporary workaround to keep # the repr of those k-schur as they were before #13404; since # they are deprecated, there is no need to bother about them. self.rename(self._name+" over %s"%self.base_ring()) self._s = Sym.s() # temporary until Hom(GradedHopfAlgebrasWithBasis work better) category = sage.categories.all.ModulesWithBasis(self.base_ring()) # This really should be a conversion, not a coercion (it can fail) 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 __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 factorize(f, n=0): """ Return the factorization of the tensor product `f` w.r.t the right symmetric functions. The right symmetric functions have their supports in the partitions on `n`. INPUT: - ``f`` -- a sum of tensor products on symmetric functions - ``n`` -- an Integer EXAMPLES:: sage: factorize(E_mu(Partition([3,1])), 4) [((3, 1), s[]), ((1, 1, 1, 1), s[1, 1] + s[3]), ((2, 2), s[1]), ((2, 1, 1), s[1] + s[2]), ((4,), 0)] TODO : Delete n and correct code and worksheets """ SymmetricFunctions(QQ).s() supp = sorted(f.support()) n = f.support().pop()[1].size() result = {} res = [] for mu in Partitions(n): result[mu] = [] for (a, b), c in zip(supp, f.coefficients()): if b == mu: result[mu] += [(a, c)] result2 = [(tuple(mu), sum(c * s(nu) for (nu, c) in result[mu])) for mu in result.keys()] return result2
def to_symmetric_function(self): r""" Takes a quasi-symmetric function, expressed in the monomial basis, and returns its symmetric realization, when possible, expressed in the monomial basis of symmetric functions. OUTPUT: - If ``self`` is a symmetric function, then the expansion in the monomial basis of the symmetric functions is returned. Otherwise an error is raised. EXAMPLES:: sage: QSym = QuasiSymmetricFunctions(QQ) sage: M = QSym.Monomial() sage: (M[3,2] + M[2,3] + M[4,1]).to_symmetric_function() Traceback (most recent call last): ... ValueError: M[2, 3] + M[3, 2] + M[4, 1] is not a symmetric function sage: (M[3,2] + M[2,3] + 2*M[4,1] + 2*M[1,4]).to_symmetric_function() m[3, 2] + 2*m[4, 1] sage: m = SymmetricFunctions(QQ).m() sage: M(m[3,1,1]).to_symmetric_function() m[3, 1, 1] sage: (M(m[2,1])*M(m[2,1])).to_symmetric_function()-m[2,1]*m[2,1] 0 TESTS:: sage: (M(0)).to_symmetric_function() 0 sage: (M([])).to_symmetric_function() m[] sage: (2*M([])).to_symmetric_function() 2*m[] """ m = SymmetricFunctions(self.parent().base_ring()).monomial() if self.is_symmetric(): return m.sum_of_terms( [(I, coeff) for (I, coeff) in self if list(I) in Partitions()], distinct=True) else: raise ValueError, "%s is not a symmetric function" % self
def charpoly(self, g, var='x'): r""" Determines the characteristic polynomial `\det(I-gT)` """ if self.degree() == 0: return QQ.one() from sage.combinat.sf.sf import SymmetricFunctions S = SymmetricFunctions(QQ) p = S.powersum() e = S.elementary() deg = self.degree() traces = [self(g ** n) for n in range(1, deg+1)] x = PolynomialRing(QQ, var).gen() cp = x ** deg for n in range(deg): mc = p(e[n+1]).monomial_coefficients() cp += (-1) ** (n+1) * x ** (deg-1-n) * sum(mc[k] * prod(traces[j-1] for j in k) for k in mc.keys()) return cp
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 to_symmetric_function( self ): r""" Takes a quasi-symmetric function, expressed in the monomial basis, and returns its symmetric realization, when possible, expressed in the monomial basis of symmetric functions. OUTPUT: - If ``self`` is a symmetric function, then the expansion in the monomial basis of the symmetric functions is returned. Otherwise an error is raised. EXAMPLES:: sage: QSym = QuasiSymmetricFunctions(QQ) sage: M = QSym.Monomial() sage: (M[3,2] + M[2,3] + M[4,1]).to_symmetric_function() Traceback (most recent call last): ... ValueError: M[2, 3] + M[3, 2] + M[4, 1] is not a symmetric function sage: (M[3,2] + M[2,3] + 2*M[4,1] + 2*M[1,4]).to_symmetric_function() m[3, 2] + 2*m[4, 1] sage: m = SymmetricFunctions(QQ).m() sage: M(m[3,1,1]).to_symmetric_function() m[3, 1, 1] sage: (M(m[2,1])*M(m[2,1])).to_symmetric_function()-m[2,1]*m[2,1] 0 TESTS:: sage: (M(0)).to_symmetric_function() 0 sage: (M([])).to_symmetric_function() m[] sage: (2*M([])).to_symmetric_function() 2*m[] """ m = SymmetricFunctions(self.parent().base_ring()).monomial() if self.is_symmetric(): return m.sum_of_terms([(I, coeff) for (I, coeff) in self if list(I) in Partitions()], distinct=True) else: raise ValueError, "%s is not a symmetric function"%self
def _DualGrothendieck(self,la): r""" Returns the expansion of the K-`k`-Schur function in the homogeneous basis. This method is here for caching purposes. INPUT: - ``la`` -- A `k`-bounded partition. OUTPUT: - A symmetric function in the homogeneous basis. EXAMPLES:: sage: g = SymmetricFunctions(QQ).kBoundedSubspace(3,1).K_kschur() sage: g._DualGrothendieck(Partition([2,1])) h[2] + h[2, 1] - h[3] sage: g._DualGrothendieck(Partition([])) h[] sage: g._DualGrothendieck(Partition([4,1])) 0 """ m = la.size() h = SymmetricFunctions(self.base_ring()).h() M = self._DualGrothMatrix(m) vec = [] for i in range(m+1): for x in Partitions(m-i, max_part=self.k): if x == la: vec.append(1) else: vec.append(0) from sage.modules.free_module_element import vector vec = vector(vec) sol = M.solve_right(vec) new_function = h.zero() count = 0 for i in range(m+1): for x in Partitions(m-i, max_part=self.k): new_function+= h(x) * sol[count] count += 1 return new_function
def _DualGrothMatrix(self, m): r""" Returns the change of basis matrix between the K_kschur basis and the `k`-bounded homogeneous basis. INPUT: - ``m`` -- An integer OUTPUT: - A matrix. EXAMPLES:: sage: g = SymmetricFunctions(QQ).kBoundedSubspace(3,1).K_kschur() sage: g._DualGrothMatrix(3) [ 1 1 1 0 0 0 0] [ 0 1 2 0 0 0 0] [ 0 0 1 0 0 0 0] [ 0 -1 -2 1 1 0 0] [ 0 0 -2 0 1 0 0] [ 0 0 1 0 -1 1 0] [ 0 0 0 0 0 0 1] sage: g._DualGrothMatrix(0) [1] """ new_mat = [] Sym = SymmetricFunctions(self.base_ring()) Q = Sym.kBoundedQuotient(self.k,t=1) mon = Q.km() G = Q.AffineGrothendieckPolynomial for i in range(m+1): for x in Partitions(m-i, max_part = self.k): f = mon(G(x,m)) vec = [] for j in range(m+1): for y in Partitions(m-j, max_part = self.k): vec.append(f.coefficient(y)) new_mat.append(vec) from sage.matrix.constructor import Matrix return Matrix(new_mat)
def to_symmetric_function(self): r""" Return the image of ``self`` under the natural projection map to `Sym`. The natural projection map `FSym \to Sym` sends each standard tableau `t` to the Schur function `s_\lambda`, where `\lambda` is the shape of `t`. This map is a surjective Hopf algebra homomorphism. EXAMPLES:: sage: FSym = algebras.FSym(QQ) sage: G = FSym.G() sage: t = StandardTableau([[1,3],[2,4],[5]]) sage: G[t].to_symmetric_function() s[2, 2, 1] """ s = SymmetricFunctions(self.parent().base_ring()).s() return s.sum_of_terms((t.shape(), coeff) for t, coeff in self)
def __init__(self, R): """ EXAMPLES:: sage: from sage.combinat.species.generating_series import CycleIndexSeriesRing sage: R = CycleIndexSeriesRing(QQ); R Cycle Index Series Ring over Symmetric Functions over Rational Field in the powersum basis sage: R == loads(dumps(R)) True """ R = SymmetricFunctions(R).power() LazyPowerSeriesRing.__init__(self, R, CycleIndexSeries)
def _exp_term(n, R = RationalField()): """ Compute the order-n term of the cycle index series of the species `E` of sets. EXAMPLES:: sage: from sage.combinat.species.generating_series import _exp_term sage: [_exp_term(i) for i in range(4)] [p[], p[1], 1/2*p[1, 1] + 1/2*p[2], 1/6*p[1, 1, 1] + 1/2*p[2, 1] + 1/3*p[3]] """ p = SymmetricFunctions(R).power() return sum(p(part) / part.aut() for part in Partitions(n))
def _multiply_basis(self, part1, part2): """ TESTS:: sage: s = sage.combinat.combinatorial_algebra.TestAlgebra(QQ) sage: a = s([2]) sage: a._mul_(a) #indirect doctest s[2, 2] + s[3, 1] + s[4] """ from sage.combinat.sf.sf import SymmetricFunctions S = SymmetricFunctions(self.base_ring()).schur() return self.sum_of_terms(S(part1) * S(part2))
def charpoly_reverse(self, g, var='x'): r""" Determines the characteristic polynomial `\det(I-gT)` sage: from sage.rings.number_field.galois_group import GaloisGroup_v3 sage: from sage.rings.number_field.artin_representation import ArtinRepresentation sage: K = NumberField(x^3 - 2, 'a') sage: G = GaloisGroup_v3(K, names='b2') sage: chi = ArtinRepresentation(G, [2, 0, -1]) sage: L = G.splitting_field() sage: for p in prime_range(5, 50): ... print p, chi.charpoly_reverse(G.artin_symbol(L.primes_above(p)[0])) 5 -x^2 + 1 7 x^2 + x + 1 11 -x^2 + 1 13 x^2 + x + 1 17 -x^2 + 1 19 x^2 + x + 1 23 -x^2 + 1 29 -x^2 + 1 31 x^2 - 2*x + 1 37 x^2 + x + 1 41 -x^2 + 1 43 x^2 - 2*x + 1 47 -x^2 + 1 """ if self.degree() == 0: return QQ.one() from sage.combinat.sf.sf import SymmetricFunctions S = SymmetricFunctions(QQ) p = S.powersum() e = S.elementary() deg = self.degree() traces = [self(g ** n) for n in range(1, deg+1)] x = PolynomialRing(QQ, var).gen() cp = QQ.one() for n in range(deg): mc = p(e[n+1]).monomial_coefficients() cp += (-1) ** (n+1) * x ** (n+1) * sum(mc[k] * prod(traces[j-1] for j in k) for k in mc.keys()) return cp
def to_symmetric_function(self): r""" Take a function in the `\mathbf{w}` basis, and return its symmetric realization, when possible, expressed in the homogeneous basis of symmetric functions. OUTPUT: - If ``self`` is a symmetric function, then the expansion in the homogeneous basis of the symmetric functions is returned. Otherwise an error is raised. EXAMPLES:: sage: w = SymmetricFunctionsNonCommutingVariables(QQ).dual().w() sage: elt = w[[1],[2,3]] + w[[1,2],[3]] + w[[1,3],[2]] sage: elt.to_symmetric_function() h[2, 1] sage: elt = w.sum_of_partitions([2,1,1]) / 2 sage: elt.to_symmetric_function() 1/2*h[2, 1, 1] TESTS:: sage: w = SymmetricFunctionsNonCommutingVariables(QQ).dual().w() sage: w(0).to_symmetric_function() 0 sage: w([]).to_symmetric_function() h[] sage: (2*w([])).to_symmetric_function() 2*h[] """ if not self.is_symmetric(): raise ValueError("not a symmetric function") h = SymmetricFunctions(self.parent().base_ring()).homogeneous() d = {A.shape(): c for A, c in self} return h.sum_of_terms( [(AA, cc / prod(map(factorial, AA.to_exp()))) for AA, cc in d.items()], distinct=True)
def _cl_term(n, R = RationalField()): r""" Compute the order-n term of the cycle index series of the virtual species `\Omega`, the compositional inverse of the species `E^{+}` of nonempty sets. EXAMPLES:: sage: from sage.combinat.species.generating_series import _cl_term sage: [_cl_term(i) for i in range(4)] [0, p[1], -1/2*p[1, 1] - 1/2*p[2], 1/3*p[1, 1, 1] - 1/3*p[3]] """ n = Integer(n) # check that n is an integer p = SymmetricFunctions(R).power() res = p.zero() if n == 1: res = p([1]) elif n > 1: res = 1/n * ((-1)**(n-1) * p([1])**n - sum(d * p([n // d]).plethysm(_cl_term(d, R)) for d in divisors(n)[:-1])) return res
def to_symmetric_function(self): r""" Take a function in the `\mathbf{w}` basis, and return its symmetric realization, when possible, expressed in the homogeneous basis of symmetric functions. OUTPUT: - If ``self`` is a symmetric function, then the expansion in the homogeneous basis of the symmetric functions is returned. Otherwise an error is raised. EXAMPLES:: sage: w = SymmetricFunctionsNonCommutingVariables(QQ).dual().w() sage: elt = w[[1],[2,3]] + w[[1,2],[3]] + w[[1,3],[2]] sage: elt.to_symmetric_function() h[2, 1] sage: elt = w.sum_of_partitions([2,1,1]) / 2 sage: elt.to_symmetric_function() 1/2*h[2, 1, 1] TESTS:: sage: w = SymmetricFunctionsNonCommutingVariables(QQ).dual().w() sage: w(0).to_symmetric_function() 0 sage: w([]).to_symmetric_function() h[] sage: (2*w([])).to_symmetric_function() 2*h[] """ if not self.is_symmetric(): raise ValueError("not a symmetric function") h = SymmetricFunctions(self.parent().base_ring()).homogeneous() d = {A.shape(): c for A, c in self} return h.sum_of_terms( [(AA, cc / prod(map(factorial, AA.to_exp()))) for AA, cc in d.items()], distinct=True )
def _cis_iterator(self, base_ring): """ EXAMPLES:: sage: L = species.LinearOrderSpecies() sage: g = L.cycle_index_series() sage: g.coefficients(5) [p[], p[1], p[1, 1], p[1, 1, 1], p[1, 1, 1, 1]] """ from sage.combinat.sf.sf import SymmetricFunctions p = SymmetricFunctions(base_ring).power() for n in _integers_from(0): yield p([1]*n)
def __init__(self, R): """ Initialize ``self``. EXAMPLES:: sage: TestSuite(SymmetricFunctionsNonCommutingVariables(QQ).dual()).run() """ 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 w = self.w() # Embedding of Sym in the homogeneous bases into DNCSym in the w basis Sym = SymmetricFunctions(self.base_ring()) Sym_h_to_w = Sym.h().module_morphism( w.sum_of_partitions, triangular="lower", inverse_on_support=w._set_par_to_par, codomain=w, category=category ) Sym_h_to_w.register_as_coercion() self.to_symmetric_function = Sym_h_to_w.section()
def _cis_gen(self, base_ring): """ EXAMPLES:: sage: S = species.SetSpecies() sage: g = S._cis_gen(QQ) sage: [next(g) for i in range(5)] [0, p[1], 1/2*p[2], 1/3*p[3], 1/4*p[4]] """ from sage.combinat.sf.sf import SymmetricFunctions p = SymmetricFunctions(base_ring).power() yield p(0) for n in _integers_from(1): yield p([n])/n
def jacobi_trudi(self): """ EXAMPLES:: sage: SkewPartition([[3,2,1],[2,1]]).jacobi_trudi() [h[1] 0 0] [h[3] h[1] 0] [h[5] h[3] h[1]] sage: SkewPartition([[4,3,2],[2,1]]).jacobi_trudi() [h[2] h[] 0] [h[4] h[2] h[]] [h[6] h[4] h[2]] """ p = self.outer() q = self.inner() from sage.combinat.sf.sf import SymmetricFunctions if len(p) == 0 and len(q) == 0: return MatrixSpace(SymmetricFunctions(QQ).homogeneous(), 0)(0) nn = len(p) h = SymmetricFunctions(QQ).homogeneous() H = MatrixSpace(h, nn) q = q + [0]*int(nn-len(q)) m = [] for i in range(1,nn+1): row = [] for j in range(1,nn+1): v = p[j-1]-q[i-1]-j+i if v < 0: row.append(h(0)) elif v == 0: row.append(h([])) else: row.append(h([v])) m.append(row) return H(m)
def __init__(self, base_ring, q, prefix='I'): """ Initialize ``self``. EXAMPLES:: sage: R.<q> = ZZ[] sage: I = HallAlgebra(R, q).monomial_basis() sage: TestSuite(I).run() sage: R = PolynomialRing(ZZ, 'q').fraction_field() sage: q = R.gen() sage: I = HallAlgebra(R, q).monomial_basis() sage: TestSuite(I).run() sage: R.<q> = LaurentPolynomialRing(ZZ) sage: I = HallAlgebra(R, q).monomial_basis() sage: TestSuite(I).run() """ self._q = q try: q_inverse = q**-1 if not q_inverse in base_ring: hopf_structure = False else: hopf_structure = True except Exception: hopf_structure = False if hopf_structure: category = HopfAlgebrasWithBasis(base_ring) else: category = AlgebrasWithBasis(base_ring) CombinatorialFreeModule.__init__(self, base_ring, Partitions(), prefix=prefix, bracket=False, category=category) # Coercions if hopf_structure: e = SymmetricFunctions(base_ring).e() f = lambda la: q**sum(-((r * (r - 1)) // 2) for r in la) M = self.module_morphism(diagonal=f, codomain=e) M.register_as_coercion() (~M).register_as_coercion()
def _cis_iterator(self, base_ring): r""" The cycle index series of the species of cyclic permutations is given by .. MATH:: -\sum_{k=1}^\infty \phi(k)/k * log(1 - x_k) which is equal to .. MATH:: \sum_{n=1}^\infty \frac{1}{n} * \sum_{k|n} \phi(k) * x_k^{n/k} . EXAMPLES:: sage: P = species.CycleSpecies() sage: cis = P.cycle_index_series() sage: cis.coefficients(7) [0, p[1], 1/2*p[1, 1] + 1/2*p[2], 1/3*p[1, 1, 1] + 2/3*p[3], 1/4*p[1, 1, 1, 1] + 1/4*p[2, 2] + 1/2*p[4], 1/5*p[1, 1, 1, 1, 1] + 4/5*p[5], 1/6*p[1, 1, 1, 1, 1, 1] + 1/6*p[2, 2, 2] + 1/3*p[3, 3] + 1/3*p[6]] """ from sage.combinat.sf.sf import SymmetricFunctions p = SymmetricFunctions(base_ring).power() zero = base_ring(0) yield zero for n in _integers_from(1): res = zero for k in divisors(n): res += euler_phi(k) * p([k])**(n // k) res /= n yield self._weight * res
def cardinality(self): r""" The number of integer matrices with the prescribed row sums and columns sums. EXAMPLES:: sage: from sage.combinat.integer_matrices import IntegerMatrices sage: IntegerMatrices([2,5], [3,2,2]).cardinality() 6 sage: IntegerMatrices([1,1,1,1,1], [1,1,1,1,1]).cardinality() 120 sage: IntegerMatrices([2,2,2,2], [2,2,2,2]).cardinality() 282 sage: IntegerMatrices([4], [3]).cardinality() 0 sage: len(IntegerMatrices([0,0], [0]).list()) 1 This method computes the cardinality using symmetric functions. Below are the same examples, but computed by generating the actual matrices:: sage: from sage.combinat.integer_matrices import IntegerMatrices sage: len(IntegerMatrices([2,5], [3,2,2]).list()) 6 sage: len(IntegerMatrices([1,1,1,1,1], [1,1,1,1,1]).list()) 120 sage: len(IntegerMatrices([2,2,2,2], [2,2,2,2]).list()) 282 sage: len(IntegerMatrices([4], [3]).list()) 0 sage: len(IntegerMatrices([0], [0]).list()) 1 """ from sage.combinat.sf.sf import SymmetricFunctions from sage.combinat.partition import Partition h = SymmetricFunctions(ZZ).homogeneous() row_partition = Partition(sorted(self._row_sums, reverse=True)) col_partition = Partition(sorted(self._col_sums, reverse=True)) return h[row_partition].scalar(h[col_partition])
def _cis_gen(self, base_ring, n): """ EXAMPLES:: sage: P = species.PermutationSpecies() sage: g = P._cis_gen(QQ, 2) sage: [g.next() for i in range(10)] [p[], 0, p[2], 0, p[2, 2], 0, p[2, 2, 2], 0, p[2, 2, 2, 2], 0] """ from sage.combinat.sf.sf import SymmetricFunctions p = SymmetricFunctions(base_ring).power() pn = p([n]) n = n - 1 yield p(1) for k in _integers_from(1): for i in range(n): yield base_ring(0) yield pn**k
#!/usr/bin/env python # -*- coding: utf-8 -*- from pypersist import persist from sage.misc.misc import attrcall from sage.categories.tensor import tensor from sage.misc.latex import latex from diagonal_polynomial_ring import * from subspace import * from young_idempotent import * from add_degree import * from diagram import * from sage.combinat.sf.sf import SymmetricFunctions m = SymmetricFunctions(QQ).m() s = SymmetricFunctions(QQ).s() # Workaround #25491 which prevents early unpickling of tensor products # of symmetric functions from sage.categories.hopf_algebras_with_basis import HopfAlgebrasWithBasis HopfAlgebrasWithBasis.TensorProducts ############################################################################## # Vandermonde like determinant ############################################################################## def vandermonde(gamma, r=0): """ Let `gamma` be a diagram of $n$ cells and $x = (x_1, x_2, \dots, x_n)$ and $\theta = (\theta_1, \theta_2, \dots, \theta_n)$ two sets of n variables.
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 GL_irreducible_character(n, mu, KK): r""" Return the character of the irreducible module indexed by ``mu`` of `GL(n)` over the field ``KK``. INPUT: - ``n`` -- a positive integer - ``mu`` -- a partition of at most ``n`` parts - ``KK`` -- a field OUTPUT: a symmetric function which should be interpreted in ``n`` variables to be meaningful as a character EXAMPLES: Over `\QQ`, the irreducible character for `\mu` is the Schur function associated to `\mu`, plus garbage terms (Schur functions associated to partitions with more than `n` parts):: sage: from sage.algebras.schur_algebra import GL_irreducible_character sage: sbasis = SymmetricFunctions(QQ).s() sage: z = GL_irreducible_character(2, [2], QQ) sage: sbasis(z) s[2] sage: z = GL_irreducible_character(4, [3, 2], QQ) sage: sbasis(z) -5*s[1, 1, 1, 1, 1] + s[3, 2] Over a Galois field, the irreducible character for `\mu` will in general be smaller. In characteristic `p`, for a one-part partition `(r)`, where `r = a_0 + p a_1 + p^2 a_2 + \dots`, the result is (see [GreenPoly]_, after 5.5d) the product of `h[a_0], h[a_1]( pbasis[p]), h[a_2] ( pbasis[p^2]), \dots,` which is consistent with the following :: sage: from sage.algebras.schur_algebra import GL_irreducible_character sage: GL_irreducible_character(2, [7], GF(3)) m[4, 3] + m[6, 1] + m[7] """ mbasis = SymmetricFunctions(QQ).m() r = sum(mu) M = SchurTensorModule(KK, n, r) A = M._schur SGA = M._sga # make ST the superstandard tableau of shape mu from sage.combinat.tableau import from_shape_and_word ST = from_shape_and_word(mu, range(1, r + 1), convention="English") # make ell the reading word of the highest weight tableau of shape mu ell = [i + 1 for i, l in enumerate(mu) for dummy in range(l)] e = M.basis()[tuple(ell)] # the element e_l # This is the notation `\{X\}` from just before (5.3a) of [GreenPoly]_. S = SGA._indices BracC = SGA._from_dict({S(x.tuple()): x.sign() for x in ST.column_stabilizer()}, remove_zeros=False) f = e * BracC # M.action_by_symmetric_group_algebra(e, BracC) # [Green, Theorem 5.3b] says that a basis of the Carter-Lusztig # module V_\mu is given by taking this f, and multiplying by all # xi_{i,ell} with ell as above and i semistandard. carter_lusztig = [] for T in SemistandardTableaux(mu, max_entry=n): i = tuple(flatten(T)) schur_rep = schur_representative_from_index(i, tuple(ell)) y = A.basis()[schur_rep] * e # M.action_by_Schur_alg(A.basis()[schur_rep], e) carter_lusztig.append(y.to_vector()) # Therefore, we now have carter_lusztig as a list giving the basis # of `V_\mu` # We want to think of expressing this character as a sum of monomial # symmetric functions. # We will determine a basis element for each m_\lambda in the # character, and we want to keep track of them by \lambda. # That means that we only want to pick out the basis elements above for # those semistandard words whose content is a partition. contents = Partitions(r, max_length=n).list() # all partitions of r, length at most n # JJ will consist of a list for each element of `contents`, # recording the list # of semistandard tableaux words with that content # graded_basis will consist of the a corresponding basis element graded_basis = [] JJ = [] for i in range(len(contents)): graded_basis.append([]) JJ.append([]) for T in SemistandardTableaux(mu, max_entry=n): i = tuple(flatten(T)) # Get the content of T con = [0] * n for a in i: con[a - 1] += 1 try: P = Partition(con) P_index = contents.index(P) JJ[P_index].append(i) schur_rep = schur_representative_from_index(i, tuple(ell)) x = A.basis()[schur_rep] * f # M.action_by_Schur_alg(A.basis()[schur_rep], f) graded_basis[P_index].append(x.to_vector()) except ValueError: pass # There is an inner product on the Carter-Lusztig module V_\mu; its # maximal submodule is exactly the kernel of the inner product. # Now, for each possible partition content, we look at the graded piece of # that degree, and we record how these elements pair with each of the # elements of carter_lusztig. # The kernel of this pairing is the part of this graded piece which is # not in the irreducible module for \mu. length = len(carter_lusztig) phi = mbasis.zero() for aa in range(len(contents)): mat = [] for kk in range(len(JJ[aa])): temp = [] for j in range(length): temp.append(graded_basis[aa][kk].inner_product(carter_lusztig[j])) mat.append(temp) angle = Matrix(mat) phi += (len(JJ[aa]) - angle.nullity()) * mbasis(contents[aa]) return phi
def cycle_index(self, parent = None): r""" INPUT: - ``self`` - a permutation group `G` - ``parent`` -- a free module with basis indexed by partitions, or behave as such, with a ``term`` and ``sum`` method (default: the symmetric functions over the rational field in the p basis) Returns the *cycle index* of `G`, which is a gadget counting the elements of `G` by cycle type, averaged over the group: .. math:: P = \frac{1}{|G|} \sum_{g\in G} p_{ \operatorname{cycle\ type}(g) } EXAMPLES: Among the permutations of the symmetric group `S_4`, there is the identity, 6 cycles of length 2, 3 products of two cycles of length 2, 8 cycles of length 3, and 6 cycles of length 4:: sage: S4 = SymmetricGroup(4) sage: P = S4.cycle_index() sage: 24 * P p[1, 1, 1, 1] + 6*p[2, 1, 1] + 3*p[2, 2] + 8*p[3, 1] + 6*p[4] If `l = (l_1,\dots,l_k)` is a partition, ``|G| P[l]`` is the number of elements of `G` with cycles of length `(p_1,\dots,p_k)`:: sage: 24 * P[ Partition([3,1]) ] 8 The cycle index plays an important role in the enumeration of objects modulo the action of a group (Polya enumeration), via the use of symmetric functions and plethysms. It is therefore encoded as a symmetric function, expressed in the powersum basis:: sage: P.parent() Symmetric Functions over Rational Field in the powersum basis This symmetric function can have some nice properties; for example, for the symmetric group `S_n`, we get the complete symmetric function `h_n`:: sage: S = SymmetricFunctions(QQ); h = S.h() sage: h( P ) h[4] TODO: add some simple examples of Polya enumeration, once it will be easy to expand symmetric functions on any alphabet. Here are the cycle indices of some permutation groups:: sage: 6 * CyclicPermutationGroup(6).cycle_index() p[1, 1, 1, 1, 1, 1] + p[2, 2, 2] + 2*p[3, 3] + 2*p[6] sage: 60 * AlternatingGroup(5).cycle_index() p[1, 1, 1, 1, 1] + 15*p[2, 2, 1] + 20*p[3, 1, 1] + 24*p[5] sage: for G in TransitiveGroups(5): # optional - database_gap # long time ... G.cardinality() * G.cycle_index() p[1, 1, 1, 1, 1] + 4*p[5] p[1, 1, 1, 1, 1] + 5*p[2, 2, 1] + 4*p[5] p[1, 1, 1, 1, 1] + 5*p[2, 2, 1] + 10*p[4, 1] + 4*p[5] p[1, 1, 1, 1, 1] + 15*p[2, 2, 1] + 20*p[3, 1, 1] + 24*p[5] p[1, 1, 1, 1, 1] + 10*p[2, 1, 1, 1] + 15*p[2, 2, 1] + 20*p[3, 1, 1] + 20*p[3, 2] + 30*p[4, 1] + 24*p[5] One may specify another parent for the result:: sage: F = CombinatorialFreeModule(QQ, Partitions()) sage: P = CyclicPermutationGroup(6).cycle_index(parent = F) sage: 6 * P B[[1, 1, 1, 1, 1, 1]] + B[[2, 2, 2]] + 2*B[[3, 3]] + 2*B[[6]] sage: P.parent() is F True This parent should have a ``term`` and ``sum`` method:: sage: CyclicPermutationGroup(6).cycle_index(parent = QQ) Traceback (most recent call last): ... AssertionError: `parent` should be (or behave as) a free module with basis indexed by partitions REFERENCES: .. [Ker1991] A. Kerber. Algebraic combinatorics via finite group actions, 2.2 p. 70. BI-Wissenschaftsverlag, Mannheim, 1991. AUTHORS: - Nicolas Borie and Nicolas M. Thiery TESTS:: sage: P = PermutationGroup([]); P Permutation Group with generators [()] sage: P.cycle_index() p[1] sage: P = PermutationGroup([[(1)]]); P Permutation Group with generators [()] sage: P.cycle_index() p[1] """ from sage.combinat.permutation import Permutation if parent is None: from sage.rings.rational_field import QQ from sage.combinat.sf.sf import SymmetricFunctions parent = SymmetricFunctions(QQ).powersum() else: assert hasattr(parent, "term") and hasattr(parent, "sum"), \ "`parent` should be (or behave as) a free module with basis indexed by partitions" base_ring = parent.base_ring() # TODO: use self.conjugacy_classes() once available from sage.interfaces.gap import gap CC = ([Permutation(self(C.Representative())).cycle_type(), base_ring(C.Size())] for C in gap(self).ConjugacyClasses()) return parent.sum( parent.term( partition, coeff ) for (partition, coeff) in CC)/self.cardinality()
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)
def cycle_index(self, parent = None): r""" Return the *cycle index* of ``self``. INPUT: - ``self`` - a permutation group `G` - ``parent`` -- a free module with basis indexed by partitions, or behave as such, with a ``term`` and ``sum`` method (default: the symmetric functions over the rational field in the `p` basis) The *cycle index* of a permutation group `G` (:wikipedia:`Cycle_index`) is a gadget counting the elements of `G` by cycle type, averaged over the group: .. MATH:: P = \frac{1}{|G|} \sum_{g\in G} p_{ \operatorname{cycle\ type}(g) } EXAMPLES: Among the permutations of the symmetric group `S_4`, there is the identity, 6 cycles of length 2, 3 products of two cycles of length 2, 8 cycles of length 3, and 6 cycles of length 4:: sage: S4 = SymmetricGroup(4) sage: P = S4.cycle_index() sage: 24 * P p[1, 1, 1, 1] + 6*p[2, 1, 1] + 3*p[2, 2] + 8*p[3, 1] + 6*p[4] If `l = (l_1,\dots,l_k)` is a partition, ``|G| P[l]`` is the number of elements of `G` with cycles of length `(p_1,\dots,p_k)`:: sage: 24 * P[ Partition([3,1]) ] 8 The cycle index plays an important role in the enumeration of objects modulo the action of a group (Pólya enumeration), via the use of symmetric functions and plethysms. It is therefore encoded as a symmetric function, expressed in the powersum basis:: sage: P.parent() Symmetric Functions over Rational Field in the powersum basis This symmetric function can have some nice properties; for example, for the symmetric group `S_n`, we get the complete symmetric function `h_n`:: sage: S = SymmetricFunctions(QQ); h = S.h() sage: h( P ) h[4] .. TODO:: Add some simple examples of Pólya enumeration, once it will be easy to expand symmetric functions on any alphabet. Here are the cycle indices of some permutation groups:: sage: 6 * CyclicPermutationGroup(6).cycle_index() p[1, 1, 1, 1, 1, 1] + p[2, 2, 2] + 2*p[3, 3] + 2*p[6] sage: 60 * AlternatingGroup(5).cycle_index() p[1, 1, 1, 1, 1] + 15*p[2, 2, 1] + 20*p[3, 1, 1] + 24*p[5] sage: for G in TransitiveGroups(5): # optional - database_gap # long time ....: G.cardinality() * G.cycle_index() p[1, 1, 1, 1, 1] + 4*p[5] p[1, 1, 1, 1, 1] + 5*p[2, 2, 1] + 4*p[5] p[1, 1, 1, 1, 1] + 5*p[2, 2, 1] + 10*p[4, 1] + 4*p[5] p[1, 1, 1, 1, 1] + 15*p[2, 2, 1] + 20*p[3, 1, 1] + 24*p[5] p[1, 1, 1, 1, 1] + 10*p[2, 1, 1, 1] + 15*p[2, 2, 1] + 20*p[3, 1, 1] + 20*p[3, 2] + 30*p[4, 1] + 24*p[5] Permutation groups with arbitrary domains are supported (see :trac:`22765`):: sage: G = PermutationGroup([['b','c','a']], domain=['a','b','c']) sage: G.cycle_index() 1/3*p[1, 1, 1] + 2/3*p[3] One may specify another parent for the result:: sage: F = CombinatorialFreeModule(QQ, Partitions()) sage: P = CyclicPermutationGroup(6).cycle_index(parent = F) sage: 6 * P B[[1, 1, 1, 1, 1, 1]] + B[[2, 2, 2]] + 2*B[[3, 3]] + 2*B[[6]] sage: P.parent() is F True This parent should be a module with basis indexed by partitions:: sage: CyclicPermutationGroup(6).cycle_index(parent = QQ) Traceback (most recent call last): ... ValueError: `parent` should be a module with basis indexed by partitions REFERENCES: - [Ke1991]_ AUTHORS: - Nicolas Borie and Nicolas M. Thiéry TESTS:: sage: P = PermutationGroup([]); P Permutation Group with generators [()] sage: P.cycle_index() p[1] sage: P = PermutationGroup([[(1)]]); P Permutation Group with generators [()] sage: P.cycle_index() p[1] """ from sage.categories.modules import Modules if parent is None: from sage.rings.rational_field import QQ from sage.combinat.sf.sf import SymmetricFunctions parent = SymmetricFunctions(QQ).powersum() elif not parent in Modules.WithBasis: raise ValueError("`parent` should be a module with basis indexed by partitions") base_ring = parent.base_ring() return parent.sum_of_terms([C.an_element().cycle_type(), base_ring(C.cardinality())] for C in self.conjugacy_classes() ) / self.cardinality()
def GL_irreducible_character(n, mu, KK): r""" Return the character of the irreducible module indexed by ``mu`` of `GL(n)` over the field ``KK``. INPUT: - ``n`` -- a positive integer - ``mu`` -- a partition of at most ``n`` parts - ``KK`` -- a field OUTPUT: a symmetric function which should be interpreted in ``n`` variables to be meaningful as a character EXAMPLES: Over `\QQ`, the irreducible character for `\mu` is the Schur function associated to `\mu`, plus garbage terms (Schur functions associated to partitions with more than `n` parts):: sage: from sage.algebras.schur_algebra import GL_irreducible_character sage: sbasis = SymmetricFunctions(QQ).s() sage: z = GL_irreducible_character(2, [2], QQ) sage: sbasis(z) s[2] sage: z = GL_irreducible_character(4, [3, 2], QQ) sage: sbasis(z) -5*s[1, 1, 1, 1, 1] + s[3, 2] Over a Galois field, the irreducible character for `\mu` will in general be smaller. In characteristic `p`, for a one-part partition `(r)`, where `r = a_0 + p a_1 + p^2 a_2 + \dots`, the result is (see [Gr2007]_, after 5.5d) the product of `h[a_0], h[a_1]( pbasis[p]), h[a_2] ( pbasis[p^2]), \dots,` which is consistent with the following :: sage: from sage.algebras.schur_algebra import GL_irreducible_character sage: GL_irreducible_character(2, [7], GF(3)) m[4, 3] + m[6, 1] + m[7] """ mbasis = SymmetricFunctions(QQ).m() r = sum(mu) M = SchurTensorModule(KK, n, r) A = M._schur SGA = M._sga #make ST the superstandard tableau of shape mu from sage.combinat.tableau import from_shape_and_word ST = from_shape_and_word(mu, list(range(1, r + 1)), convention='English') #make ell the reading word of the highest weight tableau of shape mu ell = [i + 1 for i, l in enumerate(mu) for dummy in range(l)] e = M.basis()[tuple(ell)] # the element e_l # This is the notation `\{X\}` from just before (5.3a) of [Gr2007]_. S = SGA._indices BracC = SGA._from_dict( {S(x.tuple()): x.sign() for x in ST.column_stabilizer()}, remove_zeros=False) f = e * BracC # M.action_by_symmetric_group_algebra(e, BracC) # [Green, Theorem 5.3b] says that a basis of the Carter-Lusztig # module V_\mu is given by taking this f, and multiplying by all # xi_{i,ell} with ell as above and i semistandard. carter_lusztig = [] for T in SemistandardTableaux(mu, max_entry=n): i = tuple(flatten(T)) schur_rep = schur_representative_from_index(i, tuple(ell)) y = A.basis( )[schur_rep] * e # M.action_by_Schur_alg(A.basis()[schur_rep], e) carter_lusztig.append(y.to_vector()) #Therefore, we now have carter_lusztig as a list giving the basis #of `V_\mu` #We want to think of expressing this character as a sum of monomial #symmetric functions. #We will determine a basis element for each m_\lambda in the #character, and we want to keep track of them by \lambda. #That means that we only want to pick out the basis elements above for #those semistandard words whose content is a partition. contents = Partitions(r, max_length=n).list() # all partitions of r, length at most n # JJ will consist of a list for each element of `contents`, # recording the list # of semistandard tableaux words with that content # graded_basis will consist of the a corresponding basis element graded_basis = [] JJ = [] for i in range(len(contents)): graded_basis.append([]) JJ.append([]) for T in SemistandardTableaux(mu, max_entry=n): i = tuple(flatten(T)) # Get the content of T con = [0] * n for a in i: con[a - 1] += 1 try: P = Partition(con) P_index = contents.index(P) JJ[P_index].append(i) schur_rep = schur_representative_from_index(i, tuple(ell)) x = A.basis( )[schur_rep] * f # M.action_by_Schur_alg(A.basis()[schur_rep], f) graded_basis[P_index].append(x.to_vector()) except ValueError: pass #There is an inner product on the Carter-Lusztig module V_\mu; its #maximal submodule is exactly the kernel of the inner product. #Now, for each possible partition content, we look at the graded piece of #that degree, and we record how these elements pair with each of the #elements of carter_lusztig. #The kernel of this pairing is the part of this graded piece which is #not in the irreducible module for \mu. length = len(carter_lusztig) phi = mbasis.zero() for aa in range(len(contents)): mat = [] for kk in range(len(JJ[aa])): temp = [] for j in range(length): temp.append(graded_basis[aa][kk].inner_product( carter_lusztig[j])) mat.append(temp) angle = Matrix(mat) phi += (len(JJ[aa]) - angle.nullity()) * mbasis(contents[aa]) return phi