diff --git a/src/sage/categories/schemes.py b/src/sage/categories/schemes.py index 305a134c381..3577c38db57 100644 --- a/src/sage/categories/schemes.py +++ b/src/sage/categories/schemes.py @@ -206,8 +206,8 @@ def _repr_object_names(self): Category of schemes over Integer Ring """ # To work around the name of the class (schemes_over_base) - from sage.schemes.generic.spec import is_Spec - if is_Spec(self.base_scheme()): + from sage.schemes.generic.scheme import is_AffineScheme + if is_AffineScheme(self.base_scheme()): return "schemes over %s" % self.base_scheme().coordinate_ring() else: return "schemes over %s" % self.base_scheme() diff --git a/src/sage/schemes/affine/affine_space.py b/src/sage/schemes/affine/affine_space.py index a72a7ffe3d5..fb6b8eee470 100644 --- a/src/sage/schemes/affine/affine_space.py +++ b/src/sage/schemes/affine/affine_space.py @@ -163,6 +163,7 @@ def __init__(self, n, R, names): names = normalize_names(n, names) AmbientSpace.__init__(self, n, R) self._assign_names(names) + AffineScheme.__init__(self, self.coordinate_ring(), R) def __iter__(self): """ diff --git a/src/sage/schemes/generic/homset.py b/src/sage/schemes/generic/homset.py index 3b1414a2711..86547dd06db 100644 --- a/src/sage/schemes/generic/homset.py +++ b/src/sage/schemes/generic/homset.py @@ -47,9 +47,7 @@ from sage.rings.finite_rings.constructor import is_FiniteField from sage.rings.commutative_ring import is_CommutativeRing - -from sage.schemes.generic.scheme import is_Scheme -from sage.schemes.generic.spec import Spec, is_Spec +from sage.schemes.generic.scheme import AffineScheme, is_AffineScheme from sage.schemes.generic.morphism import ( SchemeMorphism, SchemeMorphism_structure_map, @@ -123,7 +121,7 @@ class SchemeHomsetFactory(UniqueFactory): """ def create_key_and_extra_args(self, X, Y, category=None, base=ZZ, - check=True): + check=True, as_point_homset=False): """ Create a key that uniquely determines the Hom-set. @@ -154,29 +152,28 @@ def create_key_and_extra_args(self, X, Y, category=None, base=ZZ, sage: SHOMfactory = SchemeHomsetFactory('test') sage: key, extra = SHOMfactory.create_key_and_extra_args(A3,A2,check=False) sage: key - (..., ..., Category of schemes over Integer Ring) + (..., ..., Category of schemes over Integer Ring, False) sage: extra {'Y': Affine Space of dimension 2 over Rational Field, 'X': Affine Space of dimension 3 over Rational Field, 'base_ring': Integer Ring, 'check': False} """ - if not is_Scheme(X) and is_CommutativeRing(X): - X = Spec(X) - if not is_Scheme(Y) and is_CommutativeRing(Y): - Y = Spec(Y) - if is_Spec(base): + if is_CommutativeRing(X): + X = AffineScheme(X) + if is_CommutativeRing(Y): + Y = AffineScheme(Y) + if is_AffineScheme(base): base_spec = base base_ring = base.coordinate_ring() elif is_CommutativeRing(base): - base_spec = Spec(base) + base_spec = AffineScheme(base) base_ring = base else: - raise ValueError( - 'The base must be a commutative ring or its spectrum.') + raise ValueError('base must be a commutative ring or its spectrum') if not category: from sage.categories.schemes import Schemes category = Schemes(base_spec) - key = tuple([id(X), id(Y), category]) + key = tuple([id(X), id(Y), category, as_point_homset]) extra = {'X':X, 'Y':Y, 'base_ring':base_ring, 'check':check} return key, extra @@ -200,8 +197,8 @@ def create_object(self, version, key, **extra_args): True sage: from sage.schemes.generic.homset import SchemeHomsetFactory sage: SHOMfactory = SchemeHomsetFactory('test') - sage: SHOMfactory.create_object(0, [id(A3),id(A2),A3.category()], check=True, - ... X=A3, Y=A2, base_ring=QQ) + sage: SHOMfactory.create_object(0, [id(A3), id(A2), A3.category(), False], + ....: check=True, X=A3, Y=A2, base_ring=QQ) Set of morphisms From: Affine Space of dimension 3 over Rational Field To: Affine Space of dimension 2 over Rational Field @@ -210,7 +207,7 @@ def create_object(self, version, key, **extra_args): X = extra_args.pop('X') Y = extra_args.pop('Y') base_ring = extra_args.pop('base_ring') - if is_Spec(X): + if len(key) >= 4 and key[3]: # as_point_homset=True return Y._point_homset(X, Y, category=category, base=base_ring, **extra_args) try: return X._homset(X, Y, category=category, base=base_ring, **extra_args) @@ -266,8 +263,8 @@ def __reduce__(self): sage: loads(Hom.dumps()) == Hom True """ - #return SchemeHomset.reduce_data(self) - return SchemeHomset, (self.domain(), self.codomain(), self.homset_category()) + return SchemeHomset, (self.domain(), self.codomain(), self.homset_category(), + self.base_ring(), False, False) def __call__(self, *args, **kwds): r""" @@ -329,7 +326,7 @@ def natural_map(self): """ X = self.domain() Y = self.codomain() - if is_Spec(Y) and Y.coordinate_ring() == X.base_ring(): + if is_AffineScheme(Y) and Y.coordinate_ring() == X.base_ring(): return SchemeMorphism_structure_map(self) raise NotImplementedError @@ -354,7 +351,9 @@ def _element_constructor_(self, x, check=True): To: Rational Field sage: H = Hom(Spec(QQ, ZZ), Spec(ZZ)); H - Set of rational points of Spectrum of Integer Ring + Set of morphisms + From: Spectrum of Rational Field + To: Spectrum of Integer Ring sage: phi = H(f); phi Affine Scheme morphism: @@ -440,10 +439,24 @@ def __init__(self, X, Y, category=None, check=True, base=ZZ): sage: SchemeHomset_points(Spec(QQ), AffineSpace(ZZ,2)) Set of rational points of Affine Space of dimension 2 over Rational Field """ - if check and not is_Spec(X): + if check and not is_AffineScheme(X): raise ValueError('The domain must be an affine scheme.') SchemeHomset_generic.__init__(self, X, Y, category=category, check=check, base=base) + def __reduce__(self): + """ + Used in pickling. + + EXAMPLES:: + + sage: A2 = AffineSpace(QQ,2) + sage: Hom = A2(QQ) + sage: loads(Hom.dumps()) == Hom + True + """ + return SchemeHomset, (self.domain(), self.codomain(), self.homset_category(), + self.base_ring(), False, True) + def _element_constructor_(self, *v, **kwds): """ The element contstructor. @@ -549,8 +562,8 @@ def value_ring(self): Rational Field """ dom = self.domain() - if not is_Spec(dom): - raise ValueError("value rings are defined for Spec domains only!") + if not is_AffineScheme(dom): + raise ValueError("value rings are defined for affine domains only") return dom.coordinate_ring() def cardinality(self): diff --git a/src/sage/schemes/generic/point.py b/src/sage/schemes/generic/point.py index ad9c4d87c50..4e89b6be1ff 100644 --- a/src/sage/schemes/generic/point.py +++ b/src/sage/schemes/generic/point.py @@ -120,10 +120,10 @@ def __init__(self, S, P, check=False): """ INPUT: + - ``S`` -- an affine scheme - - ``S`` - an affine scheme - - - ``P`` - a prime ideal of the coordinate ring of S + - ``P`` -- a prime ideal of the coordinate ring of `S`, or + anything that can be converted into such an ideal TESTS:: @@ -146,8 +146,9 @@ def __init__(self, S, P, check=False): Point on Projective Space of dimension 2 over Rational Field defined by the Ideal (-x^2 + y*z) of Multivariate Polynomial Ring in x, y, z over Rational Field """ R = S.coordinate_ring() - from sage.rings.ideal import Ideal - P = Ideal(R, P) + from sage.rings.ideal import is_Ideal + if not (is_Ideal(P) and P.ring() is R): + P = R.ideal(P) # ideally we would have check=True by default, but # unfortunately is_prime() is only implemented in a small # number of cases diff --git a/src/sage/schemes/generic/scheme.py b/src/sage/schemes/generic/scheme.py index 96a32ce62b3..d2f399fe82b 100644 --- a/src/sage/schemes/generic/scheme.py +++ b/src/sage/schemes/generic/scheme.py @@ -101,7 +101,6 @@ def __init__(self, X=None, category=None): sage: TestSuite(X).run(skip = ["_test_an_element", "_test_elements", ... "_test_some_elements", "_test_category"]) # See #7946 """ - from sage.schemes.generic.spec import is_Spec from sage.schemes.generic.morphism import is_SchemeMorphism if X is None: @@ -331,10 +330,9 @@ def point_homset(self, S=None): """ if S is None: S = self.base_ring() - from sage.schemes.generic.spec import Spec - SpecS = Spec(S, self.base_ring()) + SpecS = AffineScheme(S, self.base_ring()) from sage.schemes.generic.homset import SchemeHomset - return SchemeHomset(SpecS, self) + return SchemeHomset(SpecS, self, as_point_homset=True) def point(self, v, check=True): """ @@ -342,10 +340,10 @@ def point(self, v, check=True): INPUT: - - ``v`` -- anything that defines a point. + - ``v`` -- anything that defines a point - - ``check`` -- boolean (optional, default=``True``). Whether - to check the defining data for consistency. + - ``check`` -- boolean (optional, default: ``True``); whether + to check the defining data for consistency OUTPUT: @@ -476,8 +474,7 @@ def base_scheme(self): if hasattr(self, '_base_morphism'): self._base_scheme = self._base_morphism.codomain() elif hasattr(self, '_base_ring'): - from sage.schemes.generic.spec import Spec - self._base_scheme = Spec(self._base_ring) + self._base_scheme = AffineScheme(self._base_ring) else: from sage.schemes.generic.spec import SpecZ self._base_scheme = SpecZ @@ -512,12 +509,12 @@ def base_morphism(self): return self._base_morphism except AttributeError: from sage.categories.schemes import Schemes - from sage.schemes.generic.spec import Spec, SpecZ + from sage.schemes.generic.spec import SpecZ SCH = Schemes() if hasattr(self, '_base_scheme'): self._base_morphism = self.Hom(self._base_scheme, category=SCH).natural_map() elif hasattr(self, '_base_ring'): - self._base_morphism = self.Hom(Spec(self._base_ring), category=SCH).natural_map() + self._base_morphism = self.Hom(AffineScheme(self._base_ring), category=SCH).natural_map() else: self._base_morphism = self.Hom(SpecZ, category=SCH).natural_map() return self._base_morphism @@ -616,14 +613,14 @@ def hom(self, x, Y=None, check=True): INPUT: - - ``x`` -- anything hat determines a scheme morphism. If ``x`` - is a scheme, try to determine a natural map to ``x``. + - ``x`` -- anything that determines a scheme morphism; if + ``x`` is a scheme, try to determine a natural map to ``x`` - - ``Y`` -- the codomain scheme (optional). If ``Y`` is not - given, try to determine ``Y`` from context. + - ``Y`` -- the codomain scheme (optional); if ``Y`` is not + given, try to determine ``Y`` from context - - ``check`` -- boolean (optional, default=``True``). Whether - to check the defining data for consistency. + - ``check`` -- boolean (optional, default: ``True``); whether + to check the defining data for consistency OUTPUT: @@ -643,7 +640,7 @@ def hom(self, x, Y=None, check=True): return self.Hom(x).natural_map() else: raise TypeError("unable to determine codomain") - return self.Hom(Y)(x, check) + return self.Hom(Y)(x, check=check) def _Hom_(self, Y, category=None, check=True): """ @@ -651,12 +648,12 @@ def _Hom_(self, Y, category=None, check=True): INPUT: - - ``Y`` -- a scheme. The codomain of the Hom-set. + - ``Y`` -- a scheme; the codomain of the Hom-set - - ``category`` -- a category (optional). The category of the - Hom-set. + - ``category`` -- a category (optional); the category of the + Hom-set - - ``check`` -- boolean (optional, default=``True``). Whether + - ``check`` -- boolean (optional, default: ``True``); whether to check the defining data for consistency. OUTPUT: @@ -668,19 +665,21 @@ def _Hom_(self, Y, category=None, check=True): sage: P = ProjectiveSpace(ZZ, 3) sage: S = Spec(ZZ) sage: S._Hom_(P) - Set of rational points of Projective Space of dimension 3 over Integer Ring + Set of morphisms + From: Spectrum of Integer Ring + To: Projective Space of dimension 3 over Integer Ring TESTS:: sage: S._Hom_(P).__class__ - + sage: E = EllipticCurve('37a1') sage: Hom(E, E).__class__ sage: Hom(Spec(ZZ), Spec(ZZ)).__class__ - + """ from sage.schemes.generic.homset import SchemeHomset return SchemeHomset(self, Y, category=category, check=check) @@ -796,22 +795,378 @@ def is_AffineScheme(x): class AffineScheme(Scheme): """ - An abstract affine scheme. + Class for general affine schemes. + + TESTS:: + + sage: from sage.schemes.generic.scheme import AffineScheme + sage: A = QQ['t'] + sage: X_abs = AffineScheme(A); X_abs + Spectrum of Univariate Polynomial Ring in t over Rational Field + sage: X_rel = AffineScheme(A, QQ); X_rel + Spectrum of Univariate Polynomial Ring in t over Rational Field + + sage: X_abs == X_rel + True + sage: X_abs.base_ring() + Integer Ring + sage: X_rel.base_ring() + Rational Field + + .. SEEALSO:: + + For affine spaces over a base ring and subschemes thereof, see + :class:`sage.schemes.generic.algebraic_scheme.AffineSpace`. + """ + def __init__(self, R, S=None, category=None): + """ + Construct the affine scheme with coordinate ring `R`. + + INPUT: + + - ``R`` -- commutative ring + + - ``S`` -- (optional) commutative ring admitting a natural map + to ``R`` + + OUTPUT: + + The spectrum of `R`, i.e. the unique affine scheme with + coordinate ring `R` as a scheme over the base ring `S`. + + EXAMPLES:: + + sage: from sage.schemes.generic.scheme import AffineScheme + sage: A. = PolynomialRing(QQ) + sage: X = AffineScheme(A, QQ) + sage: X + Spectrum of Multivariate Polynomial Ring in x, y over Rational Field + sage: X.category() + Category of schemes over Rational Field + + The standard way to construct an affine scheme is to use the + :func:`~sage.schemes.generic.spec.Spec` functor:: + + sage: S = Spec(ZZ) + sage: S + Spectrum of Integer Ring + sage: S.category() + Category of schemes + sage: type(S) + + """ + from sage.categories.commutative_rings import CommutativeRings + if not R in CommutativeRings(): + raise TypeError("R (={}) must be a commutative ring".format(R)) + self.__R = R + if not S is None: + if not S in CommutativeRings(): + raise TypeError("S (={}) must be a commutative ring".format(S)) + if not R.has_coerce_map_from(S): + raise ValueError("There must be a natural map S --> R, but S = {} and R = {}".format(S, R)) + Scheme.__init__(self, S, category=category) + + def __setstate__(self, state): + """ + Needed to unpickle old Spec objects. + + The name-mangled attribute ``__R`` used to be in a class + called ``Spec``; we have to translate this mangled name. + + TESTS:: + + sage: S = Spec(QQ) + sage: loads(dumps(S)) + Spectrum of Rational Field + """ + if '_Spec__R' in state: + state['_AffineScheme__R'] = state.pop('_Spec__R') + super(AffineScheme, self).__setstate__(state) + + def _cmp_(self, X): + """ + Compare ``self`` and ``X``. + + Affine schemes are compared using comparison of the + underlying rings. + + INPUT: + + - ``X`` -- anything + + OUTPUT: + + ``+1``, ``0``, or ``-1``. + + EXAMPLES:: + + sage: Spec(QQ) == Spec(QQ) + True + sage: Spec(QQ) == Spec(ZZ) + False + sage: Spec(QQ) == 5 + False + sage: Spec(GF(5)) < Spec(GF(7)) + True + sage: Spec(GF(7)) < Spec(GF(5)) + False + + TESTS:: + + sage: Spec(QQ).__cmp__(Spec(ZZ)) + 1 + """ + return cmp(self.__R, X.coordinate_ring()) + + def __hash__(self): + """ + Return the hash value. + + OUTPUT: + + A 32/64-bit hash value, depending on architecture. + + TESTS:: + + sage: hash(Spec(ZZ)) + -1667718069 # 32-bit + -5659298568736299957 # 64-bit + + sage: hash(Spec(QQ['x','y','z'])) + -804171295 # 32-bit + -4893002889606114847 # 64-bit + """ + # R is the only defining data, but we'd like to avoid collisions with it. + return hash("Spec") ^ hash(self.__R) + + def _repr_(self): + """ + Return a string representation of ``self``. + + OUTPUT: + + A string. + + EXAMPLES:: + + sage: Spec(PolynomialRing(QQ, 3, 'x')) + Spectrum of Multivariate Polynomial Ring in x0, x1, x2 over Rational Field + + TESTS:: + + sage: Spec(PolynomialRing(QQ, 3, 'x'))._repr_() + 'Spectrum of Multivariate Polynomial Ring in x0, x1, x2 over Rational Field' + """ + return "Spectrum of {}".format(self.__R) + + def _latex_(self): + r""" + Return a LaTeX representation of ``self``. + + OUTPUT: + + A string. + + EXAMPLES:: + + sage: S = Spec(PolynomialRing(ZZ, 2, 'x')) + sage: S + Spectrum of Multivariate Polynomial Ring in x0, x1 over Integer Ring + sage: S._latex_() + '\\mathrm{Spec}(\\Bold{Z}[x_{0}, x_{1}])' + """ + return "\\mathrm{{Spec}}({})".format(self.__R._latex_()) + + def __call__(self, *args): + """ + Construct a scheme-valued or topological point of ``self``. + + INPUT/OUTPUT: + + The argument ``x`` must be one of the following: + + - a prime ideal of the coordinate ring; the output will + be the corresponding point of `X` + + - a ring or a scheme `S`; the output will be the set `X(S)` of + `S`-valued points on `X` + + EXAMPLES:: + + sage: S = Spec(ZZ) + sage: P = S(ZZ.ideal(3)); P + Point on Spectrum of Integer Ring defined by the Principal ideal (3) of Integer Ring + sage: type(P) + + sage: S(ZZ.ideal(next_prime(1000000))) + Point on Spectrum of Integer Ring defined by the Principal ideal (1000003) of Integer Ring + + sage: R. = QQ[] + sage: S = Spec(R) + sage: P = S(R.ideal(x, y, z)); P + Point on Spectrum of Multivariate Polynomial Ring + in x, y, z over Rational Field defined by the Ideal (x, y, z) + of Multivariate Polynomial Ring in x, y, z over Rational Field + + This indicates the fix of :trac:`12734`:: + + sage: S = Spec(ZZ) + sage: S(ZZ) + Set of rational points of Spectrum of Integer Ring + + Note the difference between the previous example and the + following one:: + + sage: S(S) + Set of morphisms + From: Spectrum of Integer Ring + To: Spectrum of Integer Ring + """ + if len(args) == 1: + from sage.rings.ideal import is_Ideal + x = args[0] + if is_Ideal(x) and x.ring() is self.coordinate_ring(): + from sage.schemes.generic.point import SchemeTopologicalPoint_prime_ideal + return SchemeTopologicalPoint_prime_ideal(self, x) + + return super(AffineScheme, self).__call__(*args) + + def _an_element_(self): + r""" + Return an element of the spectrum of the ring. + + OUTPUT: + + A point of the affine scheme ``self``. + + EXAMPLES:: + + sage: Spec(QQ).an_element() + Point on Spectrum of Rational Field defined by the Principal ideal (0) of Rational Field + sage: Spec(ZZ).an_element() # random output + Point on Spectrum of Integer Ring defined by the Principal ideal (811) of Integer Ring + """ + if self.coordinate_ring() is ZZ: + from sage.rings.arith import random_prime + return self(ZZ.ideal(random_prime(1000))) + return self(self.coordinate_ring().zero_ideal()) + + def coordinate_ring(self): + """ + Return the underlying ring of this scheme. + + OUTPUT: + + A commutative ring. + + EXAMPLES:: + + sage: Spec(QQ).coordinate_ring() + Rational Field + sage: Spec(PolynomialRing(QQ, 3, 'x')).coordinate_ring() + Multivariate Polynomial Ring in x0, x1, x2 over Rational Field + """ + return self.__R + + def is_noetherian(self): + """ + Return ``True`` if ``self`` is Noetherian, ``False`` otherwise. + + EXAMPLES:: + + sage: Spec(ZZ).is_noetherian() + True + """ + return self.__R.is_noetherian() + + def dimension_absolute(self): + """ + Return the absolute dimension of this scheme. + + OUTPUT: + + Integer. + + EXAMPLES:: + + sage: S = Spec(ZZ) + sage: S.dimension_absolute() + 1 + sage: S.dimension() + 1 + """ + return self.__R.krull_dimension() + + dimension = dimension_absolute + + def dimension_relative(self): + """ + Return the relative dimension of this scheme over its base. + + OUTPUT: + + Integer. + + EXAMPLES:: + + sage: S = Spec(ZZ) + sage: S.dimension_relative() + 0 + """ + return self.__R.krull_dimension() - self.base_ring().krull_dimension() + + def base_extend(self, R): + """ + Extend the base ring/scheme. + + INPUT: + + - ``R`` -- an affine scheme or a commutative ring + + EXAMPLES:: + + sage: Spec_ZZ = Spec(ZZ); Spec_ZZ + Spectrum of Integer Ring + sage: Spec_ZZ.base_extend(QQ) + Spectrum of Rational Field + """ + from sage.categories.commutative_rings import CommutativeRings + if R in CommutativeRings(): + return AffineScheme(self.coordinate_ring().base_extend(R), self.base_ring()) + if not self.base_scheme() == R.base_scheme(): + raise ValueError('the new base scheme must be a scheme over the old base scheme') + return AffineScheme(self.coordinate_ring().base_extend(new_base.coordinate_ring()), + self.base_ring()) + + def _point_homset(self, *args, **kwds): + """ + Construct a point Hom-set. + + For internal use only. See :mod:`morphism` for more details. + + EXAMPLES:: + + sage: Spec(QQ)._point_homset(Spec(QQ), Spec(ZZ)) + Set of rational points of Spectrum of Integer Ring + """ + from sage.schemes.affine.affine_homset import SchemeHomset_points_spec + return SchemeHomset_points_spec(*args, **kwds) + def hom(self, x, Y=None): r""" Return the scheme morphism from ``self`` to ``Y`` defined by ``x``. INPUT: - - ``x`` -- anything hat determines a scheme morphism. If ``x`` - is a scheme, try to determine a natural map to ``x``. + - ``x`` -- anything that determines a scheme morphism; if + ``x`` is a scheme, try to determine a natural map to ``x`` - - ``Y`` -- the codomain scheme (optional). If ``Y`` is not - given, try to determine ``Y`` from context. + - ``Y`` -- the codomain scheme (optional); if ``Y`` is not + given, try to determine ``Y`` from context - - ``check`` -- boolean (optional, default=``True``). Whether - to check the defining data for consistency. + - ``check`` -- boolean (optional, default: ``True``); whether + to check the defining data for consistency OUTPUT: @@ -834,7 +1189,7 @@ def hom(self, x, Y=None): TESTS: - We can construct a morphism to an affine curve (trac #7956):: + We can construct a morphism to an affine curve (:trac:`7956`):: sage: S. = QQ[] sage: A1. = AffineSpace(QQ,1) @@ -845,13 +1200,9 @@ def hom(self, x, Y=None): To: Affine Curve over Rational Field defined by p - 2 Defn: Defined on coordinates by sending (r) to (2, r) - """ if is_Scheme(x): return self.Hom(x).natural_map() - if Y is None: - if is_RingHomomorphism(x): - import spec - Y = spec.Spec(x.domain()) + if Y is None and is_RingHomomorphism(x): + Y = AffineScheme(x.domain()) return Scheme.hom(self, x, Y) - diff --git a/src/sage/schemes/generic/spec.py b/src/sage/schemes/generic/spec.py index 09d0b3d7901..2f7ddb4440c 100644 --- a/src/sage/schemes/generic/spec.py +++ b/src/sage/schemes/generic/spec.py @@ -1,5 +1,11 @@ """ -Spectrum of a ring as affine scheme. +The Spec functor + +AUTHORS: + +- William Stein (2006): initial implementation + +- Peter Bruin (2014): rewrite Spec as a functor """ #******************************************************************************* @@ -8,53 +14,24 @@ # http://www.gnu.org/licenses/ #******************************************************************************* -from sage.rings.commutative_ring import is_CommutativeRing +from sage.categories.functor import Functor from sage.rings.integer_ring import ZZ +from sage.schemes.generic.scheme import AffineScheme, is_AffineScheme +from sage.structure.unique_representation import UniqueRepresentation -from sage.schemes.generic.scheme import AffineScheme -from sage.schemes.generic.point import SchemeTopologicalPoint_prime_ideal - - -def is_Spec(X): - """ - Test whether ``X`` is a Spec. - - INPUT: - - - ``X`` -- anything. - - OUTPUT: - - Boolean. - - EXAMPLES:: - - sage: from sage.schemes.generic.spec import is_Spec - sage: is_Spec(QQ^3) - False - sage: X = Spec(QQ); X - Spectrum of Rational Field - sage: is_Spec(X) - True - """ - return isinstance(X, Spec) - -class Spec(AffineScheme): +def Spec(R, S=None): r""" - The spectrum of a commutative ring, as a scheme. + Apply the Spec functor to `R`. - .. note:: + INPUT: - Calling ``Spec(R)`` twice produces two distinct (but equal) - schemes, which is important for gluing to construct more - general schemes. + - ``R`` -- either a commutative ring or a ring homomorphism - INPUT: + - ``S`` -- a commutative ring (optional), the base ring - - ``R`` -- a commutative ring. + OUTPUT: - - ``S`` -- a commutative ring (optional, default:`\ZZ`). The base - ring. + - ``AffineScheme`` -- the affine scheme `\mathrm{Spec}(R)` EXAMPLES:: @@ -66,8 +43,9 @@ class Spec(AffineScheme): Spectrum of Multivariate Polynomial Ring in x0, x1, x2 over Rational Field sage: X = Spec(PolynomialRing(GF(49,'a'), 3, 'x')); X Spectrum of Multivariate Polynomial Ring in x0, x1, x2 over Finite Field in a of size 7^2 - sage: TestSuite(X).run(skip = ["_test_an_element", "_test_elements", - ... "_test_some_elements"]) + sage: TestSuite(X).run(skip=["_test_an_element", "_test_elements", "_test_some_elements"]) + + Applying ``Spec`` twice gives equal but non-identical output:: sage: A = Spec(ZZ); B = Spec(ZZ) sage: A is B @@ -80,12 +58,11 @@ class Spec(AffineScheme): sage: Spec(5) Traceback (most recent call last): ... - TypeError: R (=5) must be a commutative ring + TypeError: x (=5) is not in Category of commutative rings sage: Spec(FreeAlgebra(QQ,2, 'x')) Traceback (most recent call last): ... - TypeError: R (=Free Algebra on 2 generators (x0, x1) over - Rational Field) must be a commutative ring + TypeError: x (=Free Algebra on 2 generators (x0, x1) over Rational Field) is not in Category of commutative rings TESTS:: @@ -103,298 +80,112 @@ class Spec(AffineScheme): sage: Spec(RDF,QQ).base_scheme() Spectrum of Rational Field """ - def __init__(self, R, S=None): - """ - Construct the spectrum of the ring ``R``. - - See :class:`Spec` for details. - - EXAMPLES:: + return SpecFunctor(S)(R) - sage: Spec(ZZ) - Spectrum of Integer Ring - """ - if not is_CommutativeRing(R): - raise TypeError("R (=%s) must be a commutative ring"%R) - self.__R = R - if not S is None: - if not is_CommutativeRing(S): - raise TypeError("S (=%s) must be a commutative ring"%S) - try: - S.hom(R) - except TypeError: - raise ValueError("There must be a natural map S --> R, but S = %s and R = %s"%(S,R)) - AffineScheme.__init__(self, S) - - def _cmp_(self, X): - """ - Compare ``self`` and ``X``. - - Spec's are compared with self using comparison of the - underlying rings. If X is not a Spec, then the result is - platform-dependent (either self < X or X < self, but never - self == X). - - INPUT: - - - ``X`` -- anything. - - OUTPUT: - - ``+1``, ``0``, or ``-1``. - - EXAMPLES:: - - sage: Spec(QQ) == Spec(QQ) - True - sage: Spec(QQ) == Spec(ZZ) - False - sage: Spec(QQ) == 5 - False - sage: Spec(GF(5)) < Spec(GF(7)) - True - sage: Spec(GF(7)) < Spec(GF(5)) - False - - TESTS:: - - sage: Spec(QQ).__cmp__(Spec(ZZ)) - 1 - """ - return cmp(self.__R, X.coordinate_ring()) - - def __hash__(self): - """ - Return the hash value. - - OUTPUT: - - A 32/64-bit hash value, depending on architecture. - - TESTS:: - - sage: hash(Spec(ZZ)) - -1667718069 # 32-bit - -5659298568736299957 # 64-bit - - sage: hash(Spec(QQ['x','y','z'])) - -804171295 # 32-bit - -4893002889606114847 # 64-bit - """ - # R is the only defining data, but we'd like to avoid collisions with it. - return hash("Spec") ^ hash(self.__R) +class SpecFunctor(Functor, UniqueRepresentation): + """ + The Spec functor. + """ + def __init__(self, base_ring=None): + """ + EXAMPLE:: + + sage: from sage.schemes.generic.spec import SpecFunctor + sage: SpecFunctor() + Spec functor from Category of commutative rings to Category of schemes + sage: SpecFunctor(QQ) + Spec functor from Category of commutative rings to + Category of schemes over Rational Field + """ + from sage.categories.all import CommutativeAlgebras, CommutativeRings, Schemes + + if base_ring is None: + domain = CommutativeRings() + codomain = Schemes() + elif base_ring in CommutativeRings(): + # We would like to use CommutativeAlgebras(base_ring) as + # the domain; we use CommutativeRings() instead because + # currently many algebras are not yet considered to be in + # CommutativeAlgebras(base_ring) by the category framework. + domain = CommutativeRings() + codomain = Schemes(AffineScheme(base_ring)) + else: + raise TypeError('base (= {}) must be a commutative ring'.format(base_ring)) + self._base_ring = base_ring + super(SpecFunctor, self).__init__(domain, codomain) def _repr_(self): """ Return a string representation of ``self``. - OUTPUT: - - String. - EXAMPLES:: - sage: Spec(PolynomialRing(QQ, 3, 'x')) - Spectrum of Multivariate Polynomial Ring in x0, x1, x2 over Rational Field - - TESTS:: - - sage: Spec(PolynomialRing(QQ, 3, 'x'))._repr_() - 'Spectrum of Multivariate Polynomial Ring in x0, x1, x2 over Rational Field' + sage: from sage.schemes.generic.spec import SpecFunctor + sage: SpecFunctor(QQ) + Spec functor from Category of commutative rings to + Category of schemes over Rational Field """ - return "Spectrum of %s"%self.__R + return 'Spec functor from {} to {}'.format(self.domain(), self.codomain()) def _latex_(self): - """ - LaTeX representation of this Spec. - - OUTPUT: - - String. - - EXAMPLES:: - - sage: S = Spec(PolynomialRing(ZZ, 2, 'x')) - sage: S - Spectrum of Multivariate Polynomial Ring in x0, x1 over Integer Ring - sage: S._latex_() - '\\mathrm{Spec}(\\Bold{Z}[x_{0}, x_{1}])' - """ - return "\\mathrm{Spec}(%s)" % self.__R._latex_() - - def __call__(self, x): - """ - Call syntax for Spec. - - INPUT/OUTPUT: - - The argument ``x`` must be one of the following: - - - a prime ideal of the coordinate ring; the output will - be the corresponding point of X - - - an element (or list of elements) of the coordinate ring - which generates a prime ideal; the output will be the - corresponding point of X - - - a ring or a scheme S; the output will be the set X(S) of - S-valued points on X - - EXAMPLES:: - - sage: S = Spec(ZZ) - sage: P = S(3); P - Point on Spectrum of Integer Ring defined by the Principal ideal (3) of Integer Ring - sage: type(P) - - sage: S(ZZ.ideal(next_prime(1000000))) - Point on Spectrum of Integer Ring defined by the Principal ideal (1000003) of Integer Ring - - sage: R. = QQ[] - sage: S = Spec(R) - sage: P = S(R.ideal(x, y, z)); P - Point on Spectrum of Multivariate Polynomial Ring - in x, y, z over Rational Field defined by the Ideal (x, y, z) - of Multivariate Polynomial Ring in x, y, z over Rational Field - - This indicates the fix of :trac:`12734`:: - sage: S = Spec(ZZ) - sage: S(ZZ) - Set of rational points of Spectrum of Integer Ring - sage: S(S) - Set of rational points of Spectrum of Integer Ring - """ - if is_CommutativeRing(x): - return self.point_homset(x) - from sage.schemes.generic.scheme import is_Scheme - if is_Scheme(x): - return x.Hom(self) - - return SchemeTopologicalPoint_prime_ideal(self, x) - - def _an_element_(self): r""" - Return an element of the spectrum of the ring. - - OUTPUT: - - A point of the affine scheme ``self``. - - EXAMPLES:: - - sage: Spec(QQ).an_element() - Point on Spectrum of Rational Field defined by the Principal ideal (0) of Rational Field - sage: Spec(ZZ).an_element() # random output - Point on Spectrum of Integer Ring defined by the Principal ideal (811) of Integer Ring - """ - if self.coordinate_ring() is ZZ: - from sage.rings.arith import random_prime - return self(random_prime(1000)) - return self(0) - - def coordinate_ring(self): - """ - Return the underlying ring of this scheme. - - OUTPUT: - - A commutative ring. + Return a LaTeX representation of ``self``. EXAMPLES:: - sage: Spec(QQ).coordinate_ring() - Rational Field - sage: Spec(PolynomialRing(QQ, 3, 'x')).coordinate_ring() - Multivariate Polynomial Ring in x0, x1, x2 over Rational Field + sage: from sage.schemes.generic.spec import SpecFunctor + sage: latex(SpecFunctor()) + \mathrm{Spec}\colon \mathbf{CommutativeRings} \longrightarrow \mathbf{Schemes} """ - return self.__R + return r'\mathrm{{Spec}}\colon {} \longrightarrow {}'.format( + self.domain()._latex_(), self.codomain()._latex_()) - def is_noetherian(self): + def _apply_functor(self, A): """ - Test whether ``self`` is Noetherian. - - OUTPUT: - - Boolean. Return True if this scheme is Noetherian. + Apply the Spec functor to the commutative ring ``A``. EXAMPLES:: - sage: Spec(ZZ).is_noetherian() - True + sage: from sage.schemes.generic.spec import SpecFunctor + sage: F = SpecFunctor() + sage: F(RR) # indirect doctest + Spectrum of Real Field with 53 bits of precision """ - return self.__R.is_noetherian() + return AffineScheme(A, self._base_ring) - def dimension_absolute(self): + def _apply_functor_to_morphism(self, f): """ - Return the absolute dimension of this scheme. - - OUTPUT: - - Integer. + Apply the Spec functor to the ring homomorphism ``f``. EXAMPLES:: - sage: S = Spec(ZZ) - sage: S.dimension_absolute() - 1 - sage: S.dimension() - 1 - """ - return self.__R.krull_dimension() - - dimension = dimension_absolute + sage: from sage.schemes.generic.spec import SpecFunctor + sage: F = SpecFunctor(GF(7)) + sage: A. = GF(7)[] + sage: B. = GF(7)[] + sage: f = A.hom((t^2, t^3)) + sage: Spec(f) # indirect doctest + Affine Scheme morphism: + From: Spectrum of Univariate Polynomial Ring in t over Finite Field of size 7 + To: Spectrum of Multivariate Polynomial Ring in x, y over Finite Field of size 7 + Defn: Ring morphism: + From: Multivariate Polynomial Ring in x, y over Finite Field of size 7 + To: Univariate Polynomial Ring in t over Finite Field of size 7 + Defn: x |--> t^2 + y |--> t^3 + """ + A = f.domain() + B = f.codomain() + return self(B).hom(f, self(A)) - def dimension_relative(self): - """ - Return the relative dimension of this scheme over its base. - - OUTPUT: - - Integer. - - EXAMPLES:: - - sage: S = Spec(ZZ) - sage: S.dimension_relative() - 0 - """ - return self.__R.krull_dimension() - self.base_ring().krull_dimension() - def base_extend(self, R): - """ - Extend the base ring/scheme. - - INPUT: - - - ``R`` -- an affine scheme or a commutative ring. - - EXAMPLES:: - - sage: Spec_ZZ = Spec(ZZ); Spec_ZZ - Spectrum of Integer Ring - sage: Spec_ZZ.base_extend(QQ) - Spectrum of Rational Field - """ - if is_CommutativeRing(R): - return Spec(self.coordinate_ring().base_extend(R), self.base_ring()) - if not self.base_scheme() == R.base_scheme(): - raise ValueError('The new base scheme must be a scheme over the old base scheme.') - return Spec(self.coordinate_ring().base_extend(new_base.coordinate_ring()), - self.base_ring()) - - def _point_homset(self, *args, **kwds): - """ - Construct a point Hom-set. - - For internal use only. See :mod:`morphism` for more details. +SpecZ = Spec(ZZ) - EXAMPLES:: - sage: Spec(QQ)._point_homset(Spec(QQ), Spec(ZZ)) - Set of rational points of Spectrum of Integer Ring - """ - from sage.schemes.affine.affine_homset import SchemeHomset_points_spec - return SchemeHomset_points_spec(*args, **kwds) +# Compatibility with older versions of this module +from sage.misc.superseded import deprecated_function_alias +is_Spec = deprecated_function_alias(16158, is_AffineScheme) -SpecZ = Spec(ZZ) +from sage.structure.sage_object import register_unpickle_override +register_unpickle_override('sage.schemes.generic.spec', 'Spec', AffineScheme) diff --git a/src/sage/schemes/hyperelliptic_curves/jacobian_homset.py b/src/sage/schemes/hyperelliptic_curves/jacobian_homset.py index 5272a3cf599..cd8007fce24 100644 --- a/src/sage/schemes/hyperelliptic_curves/jacobian_homset.py +++ b/src/sage/schemes/hyperelliptic_curves/jacobian_homset.py @@ -54,7 +54,6 @@ from sage.schemes.generic.homset import SchemeHomset_points from sage.schemes.generic.morphism import is_SchemeMorphism -from sage.schemes.generic.spec import Spec, is_Spec from jacobian_morphism import JacobianMorphism_divisor_class_field class JacobianHomset_divisor_classes(SchemeHomset_points): @@ -170,8 +169,9 @@ def value_ring(self): """ Returns S for a homset X(T) where T = Spec(S). """ + from sage.schemes.generic.scheme import is_AffineScheme T = self.domain() - if is_Spec(T): + if is_AffineScheme(T): return T.coordinate_ring() else: raise TypeError("Domain of argument must be of the form Spec(S).")