def _induced_flags(self, n, tg, type_edges): flag_counts = {} flags = [] total = 0 for p in Tuples([0, 1], binomial(n, 2) - binomial(tg.n, 2)): edges = list(type_edges) c = 0 for i in range(tg.n + 1, n + 1): for j in range(1, i): if p[c] == 0: edges.append((i, j)) else: edges.append((j, i)) c += 1 ig = ThreeGraphFlag() ig.n = n ig.t = tg.n for s in Combinations(range(1, n + 1), 3): if self._variant: if ((s[1], s[0]) in edges and (s[0], s[2]) in edges) or ((s[2], s[0]) in edges and (s[0], s[1]) in edges): ig.add_edge(s) else: if ((s[0], s[1]) in edges and (s[1], s[2]) in edges and (s[2], s[0]) in edges) or ((s[0], s[2]) in edges and (s[2], s[1]) in edges and (s[1], s[0]) in edges): ig.add_edge(s) it = ig.induced_subgraph(range(1, tg.n + 1)) if tg.is_labelled_isomorphic(it): ig.make_minimal_isomorph() ghash = hash(ig) if ghash in flag_counts: flag_counts[ghash] += 1 else: flags.append(ig) flag_counts[ghash] = 1 total += 1 return [(f, flag_counts[hash(f)] / Integer(total)) for f in flags]
def tangents(self, P): r""" Return the tangents of this affine plane curve at the point ``P``. The point ``P`` must be a point on this curve. INPUT: - ``P`` -- a point on this curve. OUTPUT: - a list of polynomials in the coordinate ring of the ambient space of this curve. EXAMPLES:: sage: R.<a> = QQ[] sage: K.<b> = NumberField(a^2 - 3) sage: A.<x,y> = AffineSpace(K, 2) sage: C = Curve([(x^2 + y^2 - 2*x)^2 - x^2 - y^2], A) sage: Q = A([0,0]) sage: C.tangents(Q) [x + (-1/3*b)*y, x + (1/3*b)*y] :: sage: A.<x,y> = AffineSpace(QQ, 2) sage: C = A.curve([y^2 - x^3 - x^2]) sage: Q = A([0,0]) sage: C.tangents(Q) [x - y, x + y] :: sage: A.<x,y> = AffineSpace(QQ, 2) sage: C = A.curve([y*x - x^4 + 2*x^2]) sage: Q = A([1,1]) sage: C.tangents(Q) Traceback (most recent call last): ... TypeError: (=(1, 1)) is not a point on (=Affine Plane Curve over Rational Field defined by -x^4 + 2*x^2 + x*y) """ r = self.multiplicity(P) f = self.defining_polynomials()[0] vars = self.ambient_space().gens() deriv = [ f.derivative(vars[0], i).derivative(vars[1], r - i)(list(P)) for i in range(r + 1) ] from sage.arith.misc import binomial T = sum([ binomial(r, i) * deriv[i] * (vars[0] - P[0])**i * (vars[1] - P[1])**(r - i) for i in range(r + 1) ]) fact = T.factor() return [l[0] for l in fact]
def eqs_affine(x0, y0): r""" Make equation for the affine point x0, y0. Return a list of equations, each equation being a list of coefficients corresponding to the monomials in ``monomials``. """ eqs = [] for i in range(s): for j in range(s - i): eq = dict() for monomial in monomials: ihat = monomial[0] jhat = monomial[1] if ihat >= i and jhat >= j: icoeff = binomial(ihat, i) * x0**(ihat-i) \ if ihat > i else 1 jcoeff = binomial(jhat, j) * y0**(jhat-j) \ if jhat > j else 1 eq[monomial] = jcoeff * icoeff eqs.append([eq.get(monomial, 0) for monomial in monomials]) return eqs
def __init__(self, base_field, order, num_of_var): r""" TESTS: Note that the order given cannot be greater than (q-1). An error is raised if that happens:: sage: from sage.coding.reed_muller_code import QAryReedMullerCode sage: C = QAryReedMullerCode(GF(3), 4, 4) Traceback (most recent call last): ... ValueError: The order must be less than 3 The order and the number of variable must be integers:: sage: C = QAryReedMullerCode(GF(3),1.1,4) Traceback (most recent call last): ... ValueError: The order of the code must be an integer The base_field parameter must be a finite field:: sage: C = QAryReedMullerCode(QQ,1,4) Traceback (most recent call last): ... ValueError: the input `base_field` must be a FiniteField """ # input sanitization if base_field not in FiniteFields(): raise ValueError("the input `base_field` must be a FiniteField") if not (isinstance(order, (Integer, int))): raise ValueError("The order of the code must be an integer") if not (isinstance(num_of_var, (Integer, int))): raise ValueError("The number of variables must be an integer") q = base_field.cardinality() if (order >= q): raise ValueError("The order must be less than %s" % q) super(QAryReedMullerCode, self).__init__(base_field, q**num_of_var, "EvaluationVector", "Syndrome") self._order = order self._num_of_var = num_of_var self._dimension = binomial(num_of_var + order, order)
def zero_eigenvectors(self, tg, flags): rows = set() for p in Tuples([0, 1], binomial(tg.n, 2)): edges = [] c = 0 for i in range(1, tg.n + 1): for j in range(1, i): if p[c] == 0: edges.append((i, j)) else: edges.append((j, i)) c += 1 graphs = self._induced_flags(flags[0].n, tg, edges) row = [0 for f in flags] for pair in graphs: g, den = pair for i in range(len(flags)): if g.is_labelled_isomorphic(flags[i]): row[i] = den break rows.add(tuple(row)) return matrix_of_independent_rows(self._field, list(rows), len(flags))
def coproduct_on_basis(self, i): r""" The coproduct of a basis element. .. MATH:: \Delta(P_i) = \sum_{j=0}^i P_{i-j} \otimes P_j INPUT: - ``i`` -- a non-negative integer OUTPUT: - an element of the tensor square of ``self`` TESTS:: sage: H = GradedHopfAlgebrasWithBasis(QQ).Connected().example() sage: H.monomial(3).coproduct() P0 # P3 + 3*P1 # P2 + 3*P2 # P1 + P3 # P0 """ return self.sum_of_terms( ((i - j, j), binomial(i, j)) for j in range(i + 1))
def symbolic_matrix_power(M, n): r""" Return the symbolic power ``M^n`` of the unipotent matrix ``M``. EXAMPLES:: sage: from surface_dynamics.misc.linalg import symbolic_matrix_power sage: m = matrix(3, [1,1,1,0,1,1,0,0,1]) sage: n = polygen(QQ, 'n') sage: symbolic_matrix_power(m, n) [ 1 n 1/2*n^2 + 1/2*n] [ 0 1 n] [ 0 0 1] sage: m = matrix(2, [2,1,1,1]) sage: symbolic_matrix_power(m, n) Traceback (most recent call last): ... NotImplementedError: power only implemented for unipotent matrices """ d = M.nrows() I = M.parent().identity_matrix() N = M - M.parent().identity_matrix() char = N.charpoly() if any(char[i] for i in range(d)): raise NotImplementedError( 'power only implemented for unipotent matrices') result = I P = N p = 1 while P: result += binomial(n, p) * P P *= N p += 1 return result
def Chow_form(self): r""" Returns the Chow form associated to this subscheme. For a `k`-dimensional subvariety of `\mathbb{P}^N` of degree `D`. The `(N-k-1)`-dimensional projective linear subspaces of `\mathbb{P}^N` meeting `X` form a hypersurface in the Grassmannian `G(N-k-1,N)`. The homogeneous form of degree `D` defining this hypersurface in Plucker coordinates is called the Chow form of `X`. The base ring needs to be a number field, finite field, or `\QQbar`. ALGORITHM: For a `k`-dimension subscheme `X` consider the `k+1` linear forms `l_i = u_{i0}x_0 + \cdots + u_{in}x_n`. Let `J` be the ideal in the polynomial ring `K[x_i,u_{ij}]` defined by the equations of `X` and the `l_i`. Let `J'` be the saturation of `J` with respect to the irrelevant ideal of the ambient projective space of `X`. The elimination ideal `I = J' \cap K[u_{ij}]` is a principal ideal, let `R` be its generator. The Chow form is obtained by writing `R` as a polynomial in Plucker coordinates (i.e. bracket polynomials). [DalbecSturmfels]_. OUTPUT: a homogeneous polynomial. REFERENCES: .. [DalbecSturmfels] J. Dalbec and B. Sturmfels. Invariant methods in discrete and computational geometry, chapter Introduction to Chow forms, pages 37-58. Springer Netherlands, 1994. EXAMPLES:: sage: P.<x0,x1,x2,x3> = ProjectiveSpace(GF(17), 3) sage: X = P.subscheme([x3+x1,x2-x0,x2-x3]) sage: X.Chow_form() t0 - t1 + t2 + t3 :: sage: P.<x0,x1,x2,x3> = ProjectiveSpace(QQ,3) sage: X = P.subscheme([x3^2 -101*x1^2 - 3*x2*x0]) sage: X.Chow_form() t0^2 - 101*t2^2 - 3*t1*t3 :: sage: P.<x0,x1,x2,x3>=ProjectiveSpace(QQ,3) sage: X = P.subscheme([x0*x2-x1^2, x0*x3-x1*x2, x1*x3-x2^2]) sage: Ch = X.Chow_form(); Ch t2^3 + 2*t2^2*t3 + t2*t3^2 - 3*t1*t2*t4 - t1*t3*t4 + t0*t4^2 + t1^2*t5 sage: Y = P.subscheme_from_Chow_form(Ch, 1); Y Closed subscheme of Projective Space of dimension 3 over Rational Field defined by: x2^2*x3 - x1*x3^2, -x2^3 + x0*x3^2, -x2^2*x3 + x1*x3^2, x1*x2*x3 - x0*x3^2, 3*x1*x2^2 - 3*x0*x2*x3, -2*x1^2*x3 + 2*x0*x2*x3, -3*x1^2*x2 + 3*x0*x1*x3, x1^3 - x0^2*x3, x2^3 - x1*x2*x3, -3*x1*x2^2 + 2*x1^2*x3 + x0*x2*x3, 2*x0*x2^2 - 2*x0*x1*x3, 3*x1^2*x2 - 2*x0*x2^2 - x0*x1*x3, -x0*x1*x2 + x0^2*x3, -x0*x1^2 + x0^2*x2, -x1^3 + x0*x1*x2, x0*x1^2 - x0^2*x2 sage: I = Y.defining_ideal() sage: I.saturation(I.ring().ideal(list(I.ring().gens())))[0] Ideal (x2^2 - x1*x3, x1*x2 - x0*x3, x1^2 - x0*x2) of Multivariate Polynomial Ring in x0, x1, x2, x3 over Rational Field """ I = self.defining_ideal() P = self.ambient_space() R = P.coordinate_ring() N = P.dimension() + 1 d = self.dimension() # create the ring for the generic linear hyperplanes # u0x0 + u1x1 + ... SS = PolynomialRing(R.base_ring(), 'u', N * (d + 1), order='lex') vars = SS.variable_names() + R.variable_names() S = PolynomialRing(R.base_ring(), vars, order='lex') n = S.ngens() newcoords = [S.gen(n - N + t) for t in range(N)] # map the generators of the subscheme into the ring with the hyperplane variables phi = R.hom(newcoords, S) phi(self.defining_polynomials()[0]) # create the dim(X)+1 linear hyperplanes l = [] for i in range(d + 1): t = 0 for j in range(N): t += S.gen(N * i + j) * newcoords[j] l.append(t) # intersect the hyperplanes with X J = phi(I) + S.ideal(l) # saturate the ideal with respect to the irrelevant ideal J2 = J.saturation(S.ideal([phi(u) for u in R.gens()]))[0] # eliminate the original variables to be left with the hyperplane coefficients 'u' E = J2.elimination_ideal(newcoords) # create the plucker coordinates D = binomial(N, N - d - 1) #number of plucker coordinates tvars = [str('t') + str(i) for i in range(D)] #plucker coordinates T = PolynomialRing(R.base_ring(), tvars + list(S.variable_names()), order='lex') L = [] coeffs = [ T.gen(i) for i in range(0 + len(tvars), N * (d + 1) + len(tvars)) ] M = matrix(T, d + 1, N, coeffs) i = 0 for c in M.minors(d + 1): L.append(T.gen(i) - c) i += 1 # create the ideal that we can use for eliminating to get a polynomial # in the plucker coordinates (brackets) br = T.ideal(L) # create a mapping into a polynomial ring over the plucker coordinates # and the hyperplane coefficients psi = S.hom(coeffs + [0 for _ in range(N)], T) E2 = T.ideal([psi(u) for u in E.gens()] + br) # eliminate the hyperplane coefficients CH = E2.elimination_ideal(coeffs) # CH should be a principal ideal, but because of the relations among # the plucker coordinates, the elimination will probably have several generators # get the relations among the plucker coordinates rel = br.elimination_ideal(coeffs) # reduce CH with respect to the relations reduced = [] for f in CH.gens(): reduced.append(f.reduce(rel)) # find the principal generator # polynomial ring in just the plucker coordinates T2 = PolynomialRing(R.base_ring(), tvars) alp = T.hom(tvars + (N * (d + 1) + N) * [0], T2) # get the degrees of the reduced generators of CH degs = [u.degree() for u in reduced] mind = max(degs) # need the smallest degree form that did not reduce to 0 for d in degs: if d < mind and d > 0: mind = d ind = degs.index(mind) CF = reduced[ind] #this should be the Chow form of X # check that it is correct (i.e., it is a principal generator for CH + the relations) rel2 = rel + [CF] assert all(f in rel2 for f in CH.gens()), "did not find a principal generator" return alp(CF)
def _test_jacobi(self, **options): """ Test the Jacobi axiom of this Lie conformal algebra. INPUT: - ``options`` -- any keyword arguments acceptde by :meth:`_tester` EXAMPLES: By default, this method tests only the elements returned by ``self.some_elements()``:: sage: V = lie_conformal_algebras.Affine(QQ, 'B2') sage: V._test_jacobi() # long time (6 seconds) It works for super Lie conformal algebras too:: sage: V = lie_conformal_algebras.NeveuSchwarz(QQ) sage: V._test_jacobi() We can use specific elements by passing the ``elements`` keyword argument:: sage: V = lie_conformal_algebras.Affine(QQ, 'A1', names=('e', 'h', 'f')) sage: V.inject_variables() Defining e, h, f, K sage: V._test_jacobi(elements=(e, 2*f+h, 3*h)) TESTS:: sage: wrongdict = {('a', 'a'): {0: {('b', 0): 1}}, ('b', 'a'): {0: {('a', 0): 1}}} sage: V = LieConformalAlgebra(QQ, wrongdict, names=('a', 'b'), parity=(1, 0)) sage: V._test_jacobi() Traceback (most recent call last): ... AssertionError: {(0, 0): -3*a} != {} - {(0, 0): -3*a} + {} """ tester = self._tester(**options) S = tester.some_elements() from sage.misc.misc import some_tuples from sage.arith.misc import binomial pz = tester._instance.zero() for x, y, z in some_tuples(S, 3, tester._max_runs): brxy = x.bracket(y) brxz = x.bracket(z) bryz = y.bracket(z) br1 = {k: x.bracket(v) for k, v in bryz.items()} br2 = {k: v.bracket(z) for k, v in brxy.items()} br3 = {k: y.bracket(v) for k, v in brxz.items()} jac1 = {(j, k): v for k in br1 for j, v in br1[k].items()} jac3 = {(k, j): v for k in br3 for j, v in br3[k].items()} jac2 = {} for k, br in br2.items(): for j, v in br.items(): for r in range(j + 1): jac2[(k + r, j - r)] = (jac2.get( (k + r, j - r), pz) + binomial(k + r, r) * v) for k, v in jac2.items(): jac1[k] = jac1.get(k, pz) - v for k, v in jac3.items(): jac1[k] = jac1.get(k, pz) - v jacobiator = {k: v for k, v in jac1.items() if v} tester.assertDictEqual(jacobiator, {})
def Chow_form(self): r""" Returns the Chow form associated to this subscheme. For a `k`-dimensional subvariety of `\mathbb{P}^N` of degree `D`. The `(N-k-1)`-dimensional projective linear subspaces of `\mathbb{P}^N` meeting `X` form a hypersurface in the Grassmannian `G(N-k-1,N)`. The homogeneous form of degree `D` defining this hypersurface in Plucker coordinates is called the Chow form of `X`. The base ring needs to be a number field, finite field, or `\QQbar`. ALGORITHM: For a `k`-dimension subscheme `X` consider the `k+1` linear forms `l_i = u_{i0}x_0 + \cdots + u_{in}x_n`. Let `J` be the ideal in the polynomial ring `K[x_i,u_{ij}]` defined by the equations of `X` and the `l_i`. Let `J'` be the saturation of `J` with respect to the irrelevant ideal of the ambient projective space of `X`. The elimination ideal `I = J' \cap K[u_{ij}]` is a principal ideal, let `R` be its generator. The Chow form is obtained by writing `R` as a polynomial in Plucker coordinates (i.e. bracket polynomials). [DalbecSturmfels]_. OUTPUT: a homogeneous polynomial. REFERENCES: .. [DalbecSturmfels] J. Dalbec and B. Sturmfels. Invariant methods in discrete and computational geometry, chapter Introduction to Chow forms, pages 37-58. Springer Netherlands, 1994. EXAMPLES:: sage: P.<x0,x1,x2,x3> = ProjectiveSpace(GF(17), 3) sage: X = P.subscheme([x3+x1,x2-x0,x2-x3]) sage: X.Chow_form() t0 - t1 + t2 + t3 :: sage: P.<x0,x1,x2,x3> = ProjectiveSpace(QQ,3) sage: X = P.subscheme([x3^2 -101*x1^2 - 3*x2*x0]) sage: X.Chow_form() t0^2 - 101*t2^2 - 3*t1*t3 :: sage: P.<x0,x1,x2,x3>=ProjectiveSpace(QQ,3) sage: X = P.subscheme([x0*x2-x1^2, x0*x3-x1*x2, x1*x3-x2^2]) sage: Ch = X.Chow_form(); Ch t2^3 + 2*t2^2*t3 + t2*t3^2 - 3*t1*t2*t4 - t1*t3*t4 + t0*t4^2 + t1^2*t5 sage: Y = P.subscheme_from_Chow_form(Ch, 1); Y Closed subscheme of Projective Space of dimension 3 over Rational Field defined by: x2^2*x3 - x1*x3^2, -x2^3 + x0*x3^2, -x2^2*x3 + x1*x3^2, x1*x2*x3 - x0*x3^2, 3*x1*x2^2 - 3*x0*x2*x3, -2*x1^2*x3 + 2*x0*x2*x3, -3*x1^2*x2 + 3*x0*x1*x3, x1^3 - x0^2*x3, x2^3 - x1*x2*x3, -3*x1*x2^2 + 2*x1^2*x3 + x0*x2*x3, 2*x0*x2^2 - 2*x0*x1*x3, 3*x1^2*x2 - 2*x0*x2^2 - x0*x1*x3, -x0*x1*x2 + x0^2*x3, -x0*x1^2 + x0^2*x2, -x1^3 + x0*x1*x2, x0*x1^2 - x0^2*x2 sage: I = Y.defining_ideal() sage: I.saturation(I.ring().ideal(list(I.ring().gens())))[0] Ideal (x2^2 - x1*x3, x1*x2 - x0*x3, x1^2 - x0*x2) of Multivariate Polynomial Ring in x0, x1, x2, x3 over Rational Field """ I = self.defining_ideal() P = self.ambient_space() R = P.coordinate_ring() N = P.dimension()+1 d = self.dimension() #create the ring for the generic linear hyperplanes # u0x0 + u1x1 + ... SS = PolynomialRing(R.base_ring(), 'u', N*(d+1), order='lex') vars = SS.variable_names() + R.variable_names() S = PolynomialRing(R.base_ring(), vars, order='lex') n = S.ngens() newcoords = [S.gen(n-N+t) for t in range(N)] #map the generators of the subscheme into the ring with the hyperplane variables phi = R.hom(newcoords,S) phi(self.defining_polynomials()[0]) #create the dim(X)+1 linear hyperplanes l = [] for i in range(d+1): t = 0 for j in range(N): t += S.gen(N*i + j)*newcoords[j] l.append(t) #intersect the hyperplanes with X J = phi(I) + S.ideal(l) #saturate the ideal with respect to the irrelevant ideal J2 = J.saturation(S.ideal([phi(t) for t in R.gens()]))[0] #eliminate the original variables to be left with the hyperplane coefficients 'u' E = J2.elimination_ideal(newcoords) #create the plucker coordinates D = binomial(N,N-d-1) #number of plucker coordinates tvars = [str('t') + str(i) for i in range(D)] #plucker coordinates T = PolynomialRing(R.base_ring(), tvars+list(S.variable_names()), order='lex') L = [] coeffs = [T.gen(i) for i in range(0+len(tvars), N*(d+1)+len(tvars))] M = matrix(T,d+1,N,coeffs) i = 0 for c in M.minors(d+1): L.append(T.gen(i)-c) i += 1 #create the ideal that we can use for eliminating to get a polynomial #in the plucker coordinates (brackets) br = T.ideal(L) #create a mapping into a polynomial ring over the plucker coordinates #and the hyperplane coefficients psi = S.hom(coeffs + [0 for i in range(N)],T) E2 = T.ideal([psi(u) for u in E.gens()] +br) #eliminate the hyperplane coefficients CH = E2.elimination_ideal(coeffs) #CH should be a principal ideal, but because of the relations among #the plucker coordinates, the elimination will probably have several generators #get the relations among the plucker coordinates rel = br.elimination_ideal(coeffs) #reduce CH with respect to the relations reduced = [] for f in CH.gens(): reduced.append(f.reduce(rel)) #find the principal generator #polynomial ring in just the plucker coordinates T2 = PolynomialRing(R.base_ring(), tvars) alp = T.hom(tvars + (N*(d+1) +N)*[0], T2) #get the degrees of the reduced generators of CH degs = [u.degree() for u in reduced] mind = max(degs) #need the smallest degree form that did not reduce to 0 for d in degs: if d < mind and d >0: mind = d ind = degs.index(mind) CF = reduced[ind] #this should be the Chow form of X #check that it is correct (i.e., it is a principal generator for CH + the relations) rel2 = rel + [CF] assert all([f in rel2 for f in CH.gens()]), "did not find a principal generator" return(alp(CF))
def _virasoro(self, g, n, I): # TODO: we should use exponential notations for I if (g, n, I) in self._cache: return self._cache[(g, n, I)] Idict = defaultdict(int) for i in I[1:]: Idict[i] += 1 Ituple = sorted(Idict.items()) # set to True for debugging information verbose = False if verbose: print("Frec({}, {}, {}".format(g, n, I)) B = self.B C = self.C F = self.F if verbose: print("compute S1") J = I[1:] S1 = ZZ_0 for im, _ in Ituple: fac = Idict[im] J = [] for j, mult in Ituple: if j == im: J.extend([j] * (mult - 1)) else: J.extend([j] * mult) J = tuple(J) s = sum(J) # = i + j for (a, value) in B(g, n - s - 1, I[0], im): if verbose: print("[S1] B({}, {}, {}) F({}, {}, {})".format( I[0], im, a, g, n - 1, (a, ) + J)) S1 += fac * value * F(g, n - 1, (a, ) + J) if verbose: print("S1 = {}".format(S1)) if verbose: print("S2") S2 = ZZ_0 if g >= 1: # TODO: here the bound is actually for the sum since the new tuple # is (a, b) + I[1:]. I1 = I[1:] abbound = 3 * (g - 1) - 3 + (n + 1) - sum(I1) for (a, b, value) in C(I[0], abbound, abbound, abbound): if verbose: print("[S2] C({}, {}, {}) F({}, {}, {})".format( I[0], a, b, g - 1, n + 1, (a, b) + I1)) S2 += value * F(g - 1, n + 1, (a, b) + I1) if verbose: print("S2 = {}".format(S2)) if verbose: print("S3") S3 = ZZ_0 for n1 in range(n): n2 = n - n1 - 1 g1min = int(n1 < 2) g2min = int(n2 < 2) for M1 in IntegerListsLex(min_sum=n1, max_sum=n1, length=len(Ituple), ceiling=[v for k, v in Ituple]): I1 = [] I2 = [] fac = 1 for m, (k, v) in zip(M1, Ituple): I1.extend([k] * m) I2.extend([k] * (v - m)) fac *= binomial(v, m) I1 = tuple(I1) I2 = tuple(I2) s1 = sum(I1) s2 = sum(I2) # the above choices of combinations already forces the genus # ie, 3g1-3+n1 >= s1 and 3g2-3+n2 >= s2 # g1 >= (s1 + 3 - n1)/3 gg1min = max(g1min, (s1 - n1 + 4) // 3) gg2min = max(g2min, (s2 - n2 + 4) // 3) gg1max = g - gg2min for g1 in range(gg1min, gg1max + 1): g2 = g - g1 a1bound = 3 * g1 - 3 + (n1 + 1) - s1 a2bound = 3 * g2 - 3 + (n2 + 1) - s2 for (a1, a2, value) in C(I[0], a1bound, a2bound, a1bound + a2bound): f1 = F(g1, n1 + 1, (a1, ) + I1) f2 = F(g2, n2 + 1, (a2, ) + I2) if verbose: print( "[S3] C({}, {}, {}) F({}, {}, {}) F({}, {}, {})" .format(I[0], a1, a2, g1, n1 + 1, (a1, ) + I1, g2, n2 + 1, (a2, ) + I2)) S3 += fac * value * f1 * f2 if verbose: print("S3 = {}".format(S3)) value = S1 + (S2 + S3) / ZZ_2 if self._cache_all or I[0] >= 2: # We do not cache string/dilaton if _cache_all = False self._cache[(g, n, I)] = value return value
def principal_specialization(self, n=infinity, q=None): r""" Return the principal specialization of a symmetric function. The *principal specialization* of order `n` at `q` is the ring homomorphism `ps_{n,q}` from the ring of symmetric functions to another commutative ring `R` given by `x_i \mapsto q^{i-1}` for `i \in \{1,\dots,n\}` and `x_i \mapsto 0` for `i > n`. Here, `q` is a given element of `R`, and we assume that the variables of our symmetric functions are `x_1, x_2, x_3, \ldots`. (To be more precise, `ps_{n,q}` is a `K`-algebra homomorphism, where `K` is the base ring.) See Section 7.8 of [EnumComb2]_. The *stable principal specialization* at `q` is the ring homomorphism `ps_q` from the ring of symmetric functions to another commutative ring `R` given by `x_i \mapsto q^{i-1}` for all `i`. This is well-defined only if the resulting infinite sums converge; thus, in particular, setting `q = 1` in the stable principal specialization is an invalid operation. INPUT: - ``n`` (default: ``infinity``) -- a nonnegative integer or ``infinity``, specifying whether to compute the principal specialization of order ``n`` or the stable principal specialization. - ``q`` (default: ``None``) -- the value to use for `q`; the default is to create a ring of polynomials in ``q`` (or a field of rational functions in ``q``) over the given coefficient ring. For ``q=1`` and finite ``n`` we use the formula from Proposition 7.8.3 of [EnumComb2]_: .. MATH:: ps_{n,1}(m_\lambda) = \binom{n}{\ell(\lambda)} \binom{\ell(\lambda)}{m_1(\lambda), m_2(\lambda),\dots}, where `\ell(\lambda)` denotes the length of `\lambda`. In all other cases, we convert to complete homogeneous symmetric functions. EXAMPLES:: sage: m = SymmetricFunctions(QQ).m() sage: x = m[3,1] sage: x.principal_specialization(3) q^7 + q^6 + q^5 + q^3 + q^2 + q sage: x = 5*m[2] + 3*m[1] + 1 sage: x.principal_specialization(3, q=var("q")) -10*(q^3 - 1)*q/(q - 1) + 5*(q^3 - 1)^2/(q - 1)^2 + 3*(q^3 - 1)/(q - 1) + 1 TESTS:: sage: m.zero().principal_specialization(3) 0 """ if q == 1: if n == infinity: raise ValueError( "the stable principal specialization at q=1 is not defined" ) f = lambda partition: binomial(n, len( partition)) * multinomial(partition.to_exp()) return self.parent()._apply_module_morphism( self, f, q.parent()) # heuristically, it seems fastest to fall back to the # elementary basis - using the powersum basis would # introduce singularities, because it is not a Z-basis return self.parent().realization_of().elementary()( self).principal_specialization(n=n, q=q)