Skip to content

Commit

Permalink
Trac #16158: Make Spec into a functor
Browse files Browse the repository at this point in the history
Sage's `Spec` command currently produces a `Spec` object that derives
from, but is not the same as, an `AffineScheme`.  The goal of this
ticket is
- merge the existing `Spec` with `AffineScheme` by moving all existing
methods of `Spec` to `AffineScheme`;
- upgrade `Spec` to a functor from `CommutativeRings` to `Schemes` (or
`Schemes(A)` if a base ring ''A'' is specified), returning objects of
type `AffineScheme`.

Example of the new functionality:
{{{
sage: A.<x,y> = QQ[]
sage: Spec(A)
Spectrum of Multivariate Polynomial Ring in x, y over Rational Field
sage: type(Spec(A))
<class 'sage.schemes.generic.scheme.AffineScheme_with_category'>
sage: B.<t> = QQ[]
sage: f = A.hom((t^2, t^3))
sage: Spec(f)
Affine Scheme morphism:
  From: Spectrum of Univariate Polynomial Ring in t over Rational Field
  To:   Spectrum of Multivariate Polynomial Ring in x, y over Rational
Field
  Defn: Ring morphism:
          From: Multivariate Polynomial Ring in x, y over Rational Field
          To:   Univariate Polynomial Ring in t over Rational Field
          Defn: x |--> t^2
                y |--> t^3
}}}
Two small user-visible changes had to be made to accommodate the new
situation:
- If ''S'' = Spec(''A'') is an affine scheme, then the syntax `S(a_1,
..., a_n)` to construct the topological point of ''S'' defined by the
prime ideal ''P'' = (''a'',,1,,, ..., ''a,,n,,'') of ''A'' is no longer
supported.  The syntax `S(A.ideal(a_1, ..., a_n))` now has to be used
instead.  This is because it conflicts with the much more useful
application of this syntax to construct the point with coordinates
(''a'',,1,,, ..., ''a,,n,,'') if ''S'' is (a subscheme of) an affine
space '''A'''^''n''^.
- Given ''S'' = Spec(''A'') and another scheme ''X'', the result of
`X(A)` is the same as before (a point homset), but `X(S)`, which used to
be identical to this, now returns the standard scheme homset.  To get
the point homset, one now has to type `X(A)` or
`X(S.coordinate_ring())`.  This seems the "principle of least surprise"
convention to me, and it is consistent with the fact that
`X.point_homset()` only accepts rings, not affine schemes.

More improvements to affine schemes are made in #7946.

URL: http://trac.sagemath.org/16158
Reported by: pbruin
Ticket author(s): Peter Bruin
Reviewer(s): Travis Scrimshaw
  • Loading branch information
Release Manager authored and vbraun committed Jul 20, 2014
2 parents 1f73f9f + 185b49c commit 1dfd8ad
Show file tree
Hide file tree
Showing 7 changed files with 536 additions and 379 deletions.
4 changes: 2 additions & 2 deletions src/sage/categories/schemes.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()
1 change: 1 addition & 0 deletions src/sage/schemes/affine/affine_space.py
Original file line number Diff line number Diff line change
Expand Up @@ -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):
"""
Expand Down
61 changes: 37 additions & 24 deletions src/sage/schemes/generic/homset.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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

Expand All @@ -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
Expand All @@ -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)
Expand Down Expand Up @@ -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"""
Expand Down Expand Up @@ -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

Expand All @@ -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:
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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):
Expand Down
11 changes: 6 additions & 5 deletions src/sage/schemes/generic/point.py
Original file line number Diff line number Diff line change
Expand Up @@ -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::
Expand All @@ -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
Expand Down
Loading

0 comments on commit 1dfd8ad

Please sign in to comment.