From 9e7475626f8a8652774ce448146b2b1fd51d61b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20Chapoton?= Date: Mon, 29 Sep 2025 19:53:54 +0200 Subject: [PATCH] switch to n_components in schemes --- .../schemes/product_projective/morphism.py | 6 +- src/sage/schemes/product_projective/point.py | 16 +-- .../product_projective/rational_point.py | 4 +- src/sage/schemes/product_projective/space.py | 111 ++++++++++-------- .../schemes/product_projective/subscheme.py | 10 +- 5 files changed, 81 insertions(+), 66 deletions(-) diff --git a/src/sage/schemes/product_projective/morphism.py b/src/sage/schemes/product_projective/morphism.py index e2ebb4e1834..0fa80663aef 100644 --- a/src/sage/schemes/product_projective/morphism.py +++ b/src/sage/schemes/product_projective/morphism.py @@ -285,7 +285,7 @@ def __eq__(self, right): return False PP = self.parent().codomain() - n = PP.num_components() + n = PP.n_components() dim = [ P.ngens() for P in PP ] dim_prefix = [0,dim[0]] @@ -332,7 +332,7 @@ def __ne__(self, right): return True PP = self.parent().codomain() - n = PP.num_components() + n = PP.n_components() dim = [ P.ngens() for P in PP ] dim_prefix = [0,dim[0]] @@ -393,7 +393,7 @@ def is_morphism(self): f = self.change_ring(T.base_ring().fraction_field()) T = T.change_ring(T.base_ring().fraction_field()) - for i in range(S.num_components()): + for i in range(S.n_components()): t = S[i].dimension_relative() + 1 X = T.subscheme(list(f)[m : m + t]) if X.dimension() > -1: diff --git a/src/sage/schemes/product_projective/point.py b/src/sage/schemes/product_projective/point.py index 7cbe0065de5..d1545c35953 100644 --- a/src/sage/schemes/product_projective/point.py +++ b/src/sage/schemes/product_projective/point.py @@ -215,7 +215,7 @@ def __copy__(self): sage: P == Q True """ - P = [copy(self[i]) for i in range(self.codomain().ambient_space().num_components())] + P = [copy(self[i]) for i in range(self.codomain().ambient_space().n_components())] return (self.codomain().point(P, False)) def __iter__(self): @@ -250,7 +250,7 @@ def __len__(self): 4 """ image = self.codomain().ambient_space() - return image.dimension() + image.num_components() + return image.dimension() + image.n_components() def __hash__(self): """ @@ -308,7 +308,7 @@ def normalize_coordinates(self): sage: P (1 : 2 : 3 , 2 : 1 : 3) """ - for i in range(self.codomain().ambient_space().num_components()): + for i in range(self.codomain().ambient_space().n_components()): self[i].normalize_coordinates() def dehomogenize(self, L): @@ -352,7 +352,7 @@ def dehomogenize(self, L): PP = self.codomain() A = PP.affine_patch(L) pt = [] - for i in range(PP.ambient_space().num_components()): + for i in range(PP.ambient_space().n_components()): pt.extend(self[i].dehomogenize(L[i])) return A(pt) @@ -377,9 +377,9 @@ def scale_by(self, t): """ if not isinstance(t, (tuple, list)): raise TypeError("%s must be a list or tuple" % t) - if len(t) != self.codomain().ambient_space().num_components(): + if len(t) != self.codomain().ambient_space().n_components(): raise TypeError("%s must have same number of components as %r" % (t, self)) - for i in range(self.codomain().ambient_space().num_components()): + for i in range(self.codomain().ambient_space().n_components()): self[i].scale_by(t[i]) def change_ring(self, R, **kwds): @@ -463,7 +463,7 @@ def global_height(self, prec=None): if K not in NumberFields() and K != ZZ and not isinstance(K, (sage.rings.abc.Order, sage.rings.abc.AlgebraicField)): raise TypeError("must be over a number field or a number field order or QQbar") - n = self.codomain().ambient_space().num_components() + n = self.codomain().ambient_space().n_components() return max(self[i].global_height(prec=prec) for i in range(n)) def local_height(self, v, prec=None): @@ -501,7 +501,7 @@ def local_height(self, v, prec=None): if K not in NumberFields(): raise TypeError("must be over a number field or a number field order") - n = self.codomain().ambient_space().num_components() + n = self.codomain().ambient_space().n_components() return max(self[i].local_height(v, prec=prec) for i in range(n)) diff --git a/src/sage/schemes/product_projective/rational_point.py b/src/sage/schemes/product_projective/rational_point.py index 1e714998169..97c16beb769 100644 --- a/src/sage/schemes/product_projective/rational_point.py +++ b/src/sage/schemes/product_projective/rational_point.py @@ -132,7 +132,7 @@ def enum_product_projective_rational_field(X, B): raise TypeError("codomain must be product of projective space over the rational field") R = X.codomain().ambient_space() - m = R.num_components() + m = R.n_components() iters = [R[i].points_of_bounded_height(bound=B) for i in range(m)] dim = [R[i].dimension_relative() + 1 for i in range(m)] @@ -356,7 +356,7 @@ def sieve(X, bound): N = P.ngens() dim_scheme = X.dimension() - num_comp = P.num_components() + num_comp = P.n_components() comp_dim_relative = [P[i].dimension_relative() + 1 for i in range(num_comp)] dim_prefix = [0, comp_dim_relative[0]] # prefixes dim list diff --git a/src/sage/schemes/product_projective/space.py b/src/sage/schemes/product_projective/space.py index f183d2676aa..d8d37b420ef 100644 --- a/src/sage/schemes/product_projective/space.py +++ b/src/sage/schemes/product_projective/space.py @@ -29,7 +29,7 @@ Defining x0, x1, x2, y0, y1, y2 """ -#***************************************************************************** +# *************************************************************************** # Copyright (C) 2014 Volker Braun # Copyright (C) 2014 Ben Hutz # @@ -37,8 +37,8 @@ # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. -# http://www.gnu.org/licenses/ -#***************************************************************************** +# https://www.gnu.org/licenses/ +# *************************************************************************** from sage.misc.cachefunc import cached_method from sage.misc.misc_c import prod @@ -134,7 +134,7 @@ def ProductProjectiveSpaces(n, R=None, names='x'): N = [] R = None for PS in n: - if not isinstance(PS,ProjectiveSpace_ring): + if not isinstance(PS, ProjectiveSpace_ring): raise TypeError("must be a list of projective spaces or (dimensions, base ring, names)") if R is None: R = PS.base_ring() @@ -150,7 +150,7 @@ def ProductProjectiveSpaces(n, R=None, names='x'): X = ProductProjectiveSpaces_ring(N, R, names) X._components = n else: - if not isinstance(n,(list, tuple)): + if not isinstance(n, (list, tuple)): raise ValueError("need list or tuple of dimensions") if R not in CommutativeRings(): raise ValueError("must be a commutative ring") @@ -165,7 +165,7 @@ def ProductProjectiveSpaces(n, R=None, names='x'): for name, dim in zip(name_list, n): names += normalize_names(dim + 1, name) else: - n_vars = sum(1+d for d in n) + n_vars = sum(1 + d for d in n) names = normalize_names(n_vars, name_list) if isinstance(R, FiniteField): X = ProductProjectiveSpaces_finite_field(n, R, names) @@ -242,13 +242,14 @@ def __init__(self, N, R=QQ, names=None): self._dims = N start = 0 self._components = [] - for i in range(len(N)): - self._components.append(ProjectiveSpace(N[i],R,names[start:start+N[i]+1])) - start += N[i]+1 + for i, Ni in enumerate(N): + self._components.append(ProjectiveSpace(Ni, R, + names[start:start + Ni + 1])) + start += Ni + 1 # Note that the coordinate ring should really be the tensor product of # the component coordinate rings. But we just deal with them as # multihomogeneous polynomial rings. - self._coordinate_ring = PolynomialRing(R,sum(N) + len(N),names) + self._coordinate_ring = PolynomialRing(R, sum(N) + len(N), names) self._assign_names(names) def _repr_(self): @@ -414,7 +415,7 @@ def __pow__(self, m): mm = int(m) if mm != m: raise ValueError("m must be an integer") - return ProductProjectiveSpaces(self.dimension_relative_components()*mm, self.base_ring()) + return ProductProjectiveSpaces(self.dimension_relative_components() * mm, self.base_ring()) def __mul__(self, right): r""" @@ -468,7 +469,7 @@ def __mul__(self, right): elif isinstance(right, ProjectiveSpace_ring): return ProductProjectiveSpaces(self.components() + [right]) elif isinstance(right, AlgebraicScheme_subscheme): - AS = self*right.ambient_space() + AS = self * right.ambient_space() CR = AS.coordinate_ring() n = self.ambient_space().coordinate_ring().ngens() @@ -523,7 +524,7 @@ def dimension_absolute(self): """ base = self.base_scheme() if base.is_noetherian(): - return sum([self[i].dimension_relative() + base.dimension() for i in range(self.num_components())]) + return sum([self[i].dimension_relative() + base.dimension() for i in range(self.n_components())]) raise NotImplementedError("cannot compute the dimension of this scheme.") dimension = dimension_absolute @@ -558,12 +559,12 @@ def dimension_absolute_components(self): """ base = self.base_scheme() if base.is_noetherian(): - return [self[i].dimension_relative() + base.dimension() for i in range(self.num_components())] + return [self[i].dimension_relative() + base.dimension() for i in range(self.n_components())] raise NotImplementedError("cannot compute the dimension of this scheme.") dimension_components = dimension_absolute_components - def num_components(self): + def n_components(self) -> int: r""" Return the number of components of this space. @@ -571,12 +572,22 @@ def num_components(self): EXAMPLES:: + sage: T = ProductProjectiveSpaces([1, 1, 1], GF(5), 'x') + sage: T.n_components() + 3 + + TESTS: + + The old method name is kept as an alias:: + sage: T = ProductProjectiveSpaces([1, 1, 1], GF(5), 'x') sage: T.num_components() 3 """ return len(self._components) + num_components = n_components + def ngens(self): r""" Return the number of generators of this space. @@ -618,8 +629,8 @@ def _factors(self, v): splitv = [] dims = self._dims for i in range(len(dims)): - splitv.append(v[index:index+dims[i]+1]) - index += dims[i]+1 + splitv.append(v[index:index + dims[i] + 1]) + index += dims[i] + 1 return splitv def _degree(self, polynomial): @@ -738,12 +749,12 @@ def _validate(self, polynomials): """ if not isinstance(polynomials, (list, tuple)): raise TypeError('the argument polynomials=%s must be a list or tuple' % polynomials) - #check in the coordinate ring + # check in the coordinate ring source_ring = self.coordinate_ring() try: polynomials = [source_ring(poly) for poly in polynomials] except TypeError: - raise TypeError("polynomials (=%s) must be elements of %s" % (polynomials,source_ring)) + raise TypeError("polynomials (=%s) must be elements of %s" % (polynomials, source_ring)) for f in polynomials: self._degree(f) # raises a ValueError if not multi-homogeneous return polynomials @@ -800,13 +811,13 @@ def _check_satisfies_equations(self, v): n = [R(w) for w in v] except TypeError: raise TypeError('the components of v=%s must be elements of %s' % (v, R)) - #check if any of the component points are 0 + # check if any of the component points are 0 N = self._dims start = 0 for i in range(len(N)): - if v[start:start + N[i]+1] == [R(0)]*(N[i]+1): + if v[start:start + N[i] + 1] == [R.zero()] * (N[i] + 1): raise TypeError('the zero vector is not a point in projective space') - start += N[i]+1 + start += N[i] + 1 return True def _an_element_(self): @@ -927,7 +938,7 @@ def affine_patch(self, I, return_embedding=False): PP = self.ambient_space() N = PP._dims if len(I) != len(N): - raise ValueError('the argument I=%s must have %s entries' % (I,len(N))) + raise ValueError(f'the argument I={I} must have {len(N)} entries') I = tuple([int(i) for i in I]) # implicit type checking for i in range(len(I)): if I[i] < 0 or I[i] > N[i]: @@ -946,10 +957,10 @@ def affine_patch(self, I, return_embedding=False): v = list(AA.gens()) index = 0 for i in range(len(I)): - v.insert(index+I[i], 1) - index += N[i]+1 + v.insert(index + I[i], 1) + index += N[i] + 1 phi = AA.hom(v, self) - self.__affine_patches.update({I:(AA, phi)}) + self.__affine_patches.update({I: (AA, phi)}) if return_embedding: return phi else: @@ -1024,36 +1035,38 @@ def segre_embedding(self, PP=None, var='u'): : z1*z2*z5 : z1*z2*z6 : z1*z3*z5 : z1*z3*z6 : z1*z4*z5 : z1*z4*z6). """ N = self._dims - M = prod([n+1 for n in N]) - 1 + M = prod([n + 1 for n in N]) - 1 CR = self.coordinate_ring() - vars = list(self.coordinate_ring().variable_names()) + [var + str(i) for i in range(M+1)] - R = PolynomialRing(self.base_ring(), self.ngens()+M+1, vars, order='lex') + vars = list(self.coordinate_ring().variable_names()) + [var + str(i) for i in range(M + 1)] + R = PolynomialRing(self.base_ring(), self.ngens() + M + 1, + vars, order='lex') - #set-up the elimination for the segre embedding + # set-up the elimination for the Segre embedding mapping = [] k = self.ngens() - index = self.num_components()*[0] + index = self.n_components() * [0] for count in range(M + 1): - mapping.append(R.gen(k+count)-prod([CR(self[i].gen(index[i])) for i in range(len(index))])) - for i in range(len(index)-1, -1, -1): + mapping.append(R.gen(k + count) - prod([CR(self[i].gen(index[i])) + for i in range(len(index))])) + for i in range(len(index) - 1, -1, -1): if index[i] == N[i]: index[i] = 0 else: index[i] += 1 - break #only increment once + break # only increment once - #change the defining ideal of the subscheme into the variables + # change the defining ideal of the subscheme into the variables I = R.ideal(list(self.defining_polynomials()) + mapping) J = I.groebner_basis() s = set(R.gens()[:self.ngens()]) - n = len(J)-1 + n = len(J) - 1 L = [] while s.isdisjoint(J[n].variables()): L.append(J[n]) - n = n-1 + n -= 1 - #create new subscheme + # create new subscheme if PP is None: PS = ProjectiveSpace(self.base_ring(), M, R.variable_names()[self.ngens():]) Y = PS.subscheme(L) @@ -1061,21 +1074,21 @@ def segre_embedding(self, PP=None, var='u'): if PP.dimension_relative() != M: raise ValueError("projective Space %s must be dimension %s") % (PP, M) S = PP.coordinate_ring() - psi = R.hom([0]*k + list(S.gens()), S) + psi = R.hom([0] * k + list(S.gens()), S) L = [psi(l) for l in L] Y = PP.subscheme(L) - #create embedding for points + # create embedding for points mapping = [] - index = self.num_components()*[0] + index = self.n_components() * [0] for count in range(M + 1): mapping.append(prod([CR(self[i].gen(index[i])) for i in range(len(index))])) - for i in range(len(index)-1, -1, -1): + for i in range(len(index) - 1, -1, -1): if index[i] == N[i]: index[i] = 0 else: index[i] += 1 - break #only increment once + break # only increment once phi = self.hom(mapping, Y) return phi @@ -1191,11 +1204,13 @@ def points_of_bounded_height(self, **kwds): B = kwds.pop('bound') tol = kwds.pop('tolerance', 1e-2) prec = kwds.pop('precision', 53) - m = self.num_components() - iters = [ self[i].points_of_bounded_height(bound=B, tolerance=tol, precision=prec) for i in range(m) ] + m = self.n_components() + iters = [self[i].points_of_bounded_height(bound=B, tolerance=tol, + precision=prec) + for i in range(m)] dim = [self[i].dimension_relative() + 1 for i in range(m)] - dim_prefix = [0, dim[0]] # prefixes dim list + dim_prefix = [0, dim[0]] # prefixes dim list for i in range(1, len(dim)): dim_prefix.append(dim_prefix[i] + dim[i]) @@ -1216,7 +1231,7 @@ def points_of_bounded_height(self, **kwds): i = 0 except StopIteration: iters[i] = self[i].points_of_bounded_height(bound=B, tolerance=tol, precision=prec) - pt = next(iters[i]) # reset + pt = next(iters[i]) # reset for j in range(dim[i]): P[dim_prefix[i] + j] = pt[j] i += 1 @@ -1257,7 +1272,7 @@ def __iter__(self): L = [next(x) for x in iters] # put at zero yield self(L) j = 0 - while j < self.num_components(): + while j < self.n_components(): try: L[j] = next(iters[j]) yield self(L) diff --git a/src/sage/schemes/product_projective/subscheme.py b/src/sage/schemes/product_projective/subscheme.py index 898e6703151..b24df7c5df5 100644 --- a/src/sage/schemes/product_projective/subscheme.py +++ b/src/sage/schemes/product_projective/subscheme.py @@ -134,7 +134,7 @@ def segre_embedding(self, PP=None): #set-up the elimination for the segre embedding mapping = [] k = AS.ngens() - index = AS.num_components()*[0] + index = AS.n_components()*[0] for count in range(M + 1): mapping.append(R.gen(k+count)-prod([CR(AS[i].gen(index[i])) for i in range(len(index))])) for i in range(len(index)-1, -1, -1): @@ -168,7 +168,7 @@ def segre_embedding(self, PP=None): #create embedding for points mapping = [] - index = AS.num_components()*[0] + index = AS.n_components()*[0] for count in range(M + 1): mapping.append(prod([CR(AS[i].gen(index[i])) for i in range(len(index))])) for i in range(len(index)-1, -1, -1): @@ -236,7 +236,7 @@ def dimension(self): for PS in PP.components()): self.__dimension = -1 else: - self.__dimension = I.dimension() - PP.num_components() + self.__dimension = I.dimension() - PP.n_components() except TypeError: #cannot compute radical for this base ring phi = self.segre_embedding() self.__dimension = phi.codomain().defining_ideal().dimension() - 1 @@ -394,7 +394,7 @@ def intersection_multiplicity(self, X, P): # find an affine chart of the ambient space of this subscheme that contains P indices = [] aff_pt = [] - for i in range(PP.num_components()): + for i in range(PP.n_components()): Q = P[i] j = 0 while Q[j] == 0: @@ -452,7 +452,7 @@ def multiplicity(self, P): # find an affine chart of the ambient space of this subscheme that contains P indices = [] aff_pt = [] - for i in range(PP.num_components()): + for i in range(PP.n_components()): Q = P[i] j = 0 while Q[j] == 0: