Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implementing SchemeMorphism_sum #37705

Draft
wants to merge 21 commits into
base: develop
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 19 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/sage/categories/homset.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,8 @@
from Alternating group of order 3!/2 as a permutation group
to Alternating group of order 3!/2 as a permutation group
in Category of finite enumerated permutation groups
sage: Hom(G, G) is End(G)

Check warning on line 119 in src/sage/categories/homset.py

View workflow job for this annotation

GitHub Actions / build

Warning: Variable 'G' referenced here was set only in doctest marked '# needs sage.groups'

Variable 'G' referenced here was set only in doctest marked '# needs sage.groups'
True
sage: Hom(ZZ, QQ, Sets())
Set of Morphisms from Integer Ring to Rational Field in Category of sets

Expand Down
22 changes: 8 additions & 14 deletions src/sage/matrix/action.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -408,10 +408,9 @@ cdef class MatrixPolymapAction(MatrixMulAction):
sage: H = Hom(P,P)
sage: A = MatrixPolymapAction(M,H)
sage: A
Left action by Full MatrixSpace of 2 by 2 dense matrices over Rational
Field on Set of morphisms
From: Projective Space of dimension 1 over Rational Field
To: Projective Space of dimension 1 over Rational Field
Left action by Full MatrixSpace of 2 by 2 dense matrices over
Rational Field on Set of scheme endomorphisms of Projective Space of
dimension 1 over Rational Field
"""
if not isinstance(S, SchemeHomset_generic):
raise TypeError("not a scheme polynomial morphism: %s"% S)
Expand All @@ -427,9 +426,7 @@ cdef class MatrixPolymapAction(MatrixMulAction):
sage: H = End(P)
sage: A = MatrixPolymapAction(M,H)
sage: A.codomain()
Set of morphisms
From: Projective Space of dimension 1 over Rational Field
To: Projective Space of dimension 1 over Rational Field
Set of scheme endomorphisms of Projective Space of dimension 1 over Rational Field
sage: A.codomain().is_endomorphism_set()
True
"""
Expand Down Expand Up @@ -479,10 +476,9 @@ cdef class PolymapMatrixAction(MatrixMulAction):
sage: H = Hom(P,P)
sage: A = PolymapMatrixAction(M,H)
sage: A
Right action by Full MatrixSpace of 2 by 2 dense matrices over Rational
Field on Set of morphisms
From: Projective Space of dimension 1 over Rational Field
To: Projective Space of dimension 1 over Rational Field
Right action by Full MatrixSpace of 2 by 2 dense matrices over
Rational Field on Set of scheme endomorphisms of Projective Space of
dimension 1 over Rational Field
"""
if not isinstance(S, SchemeHomset_generic):
raise TypeError("not a scheme polynomial morphism: %s"% S)
Expand All @@ -500,9 +496,7 @@ cdef class PolymapMatrixAction(MatrixMulAction):
sage: H = End(P)
sage: A = PolymapMatrixAction(M,H)
sage: A.codomain()
Set of morphisms
From: Projective Space of dimension 1 over Rational Field
To: Projective Space of dimension 1 over Rational Field
Set of scheme endomorphisms of Projective Space of dimension 1 over Rational Field
sage: A.codomain().is_endomorphism_set()
True
"""
Expand Down
1 change: 1 addition & 0 deletions src/sage/rings/ring_extension.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -669,6 +669,7 @@ cdef class RingExtension_generic(CommutativeRing):
sage: dir(K) # needs sage.rings.number_field
['CartesianProduct',
'Element',
'End',
'Hom',
...
'zeta',
Expand Down
8 changes: 2 additions & 6 deletions src/sage/schemes/affine/affine_homset.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,9 +113,7 @@ class SchemeHomset_polynomial_affine_space(SchemeHomset_generic):

sage: A.<x,y> = AffineSpace(2, QQ)
sage: Hom(A, A)
Set of morphisms
From: Affine Space of dimension 2 over Rational Field
To: Affine Space of dimension 2 over Rational Field
Set of scheme endomorphisms of Affine Space of dimension 2 over Rational Field
"""
def identity(self):
"""
Expand All @@ -126,9 +124,7 @@ def identity(self):
sage: A.<x,y> = AffineSpace(2, QQ)
sage: I = A.identity_morphism()
sage: I.parent()
Set of morphisms
From: Affine Space of dimension 2 over Rational Field
To: Affine Space of dimension 2 over Rational Field
Set of scheme endomorphisms of Affine Space of dimension 2 over Rational Field
sage: _.identity() == I
True
"""
Expand Down
13 changes: 13 additions & 0 deletions src/sage/schemes/affine/affine_morphism.py
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,19 @@ def __call__(self, x, check=True):
P = [f(x._coords) for f in self._polys]
return self.codomain().point_homset(R)(P, check=check)

def __hash__(self):
"""
Return a hash for this scheme morphism.

EXAMPLES::

sage: A.<x,y> = AffineSpace(QQ, 2)
sage: F = A.hom([2*x, 2*y], A)
sage: hash(F) == hash((F.__class__, A, A, (2*x, 2*y)))
True
"""
return hash((self.__class__, self.domain(), self.codomain(), self._polys))

def __eq__(self, right):
"""
Tests the equality of two affine maps.
Expand Down
4 changes: 1 addition & 3 deletions src/sage/schemes/affine/affine_space.py
Original file line number Diff line number Diff line change
Expand Up @@ -371,9 +371,7 @@ def _homset(self, *args, **kwds):

sage: A.<x,y> = AffineSpace(2, QQ)
sage: Hom(A, A)
Set of morphisms
From: Affine Space of dimension 2 over Rational Field
To: Affine Space of dimension 2 over Rational Field
Set of scheme endomorphisms of Affine Space of dimension 2 over Rational Field
"""
return SchemeHomset_polynomial_affine_space(*args, **kwds)

Expand Down
35 changes: 35 additions & 0 deletions src/sage/schemes/curves/projective_curve.py
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,41 @@

Curve_generic.__init__(self, A, X, category=category)

def _an_element_(self):
r"""
Return an element of this projective curve.

ALGORITHM:

We try to find variables that never appear as a pure monomial, and fail otherwise.

EXAMPLES::

sage: P.<x,y,z> = ProjectiveSpace(QQ, 2)
sage: C = Curve(x*y^2*z^7 - x^10 - x^2*z^8)
sage: C.an_element()
(0 : 1 : 0)
sage: C.an_element() in C
True
"""
# The dimension won't be too large anyways.
gens = list(self.ambient_space().gens())
counts = [0] * len(gens)
for poly in self.defining_polynomials():
for m in poly.monomials():
mvs = m.variables()
if len(mvs) == 1:
counts[gens.index(mvs[0])] += 1
if min(counts) > 0:
return NotImplemented

Check warning on line 249 in src/sage/schemes/curves/projective_curve.py

View check run for this annotation

Codecov / codecov/patch

src/sage/schemes/curves/projective_curve.py#L249

Added line #L249 was not covered by tests

# Set this to 1 and others to 0
ring = self.base_ring()
idx = counts.index(0)
coordinate = [ring.zero()] * len(gens)
coordinate[idx] = ring.one()
return self(coordinate)

def _repr_type(self):
r"""
Return a string representation of the type of this curve.
Expand Down
2 changes: 1 addition & 1 deletion src/sage/schemes/elliptic_curves/ell_generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -3166,7 +3166,7 @@ def montgomery_model(self, twisted=False, morphism=False):
sage: P + Q # this doesn't work...
Traceback (most recent call last):
...
TypeError: unsupported operand parent(s) for +: ...
NotImplementedError
sage: f(g(P) + g(Q)) # ...but this does
(107 : 168 : 1)

Expand Down
10 changes: 9 additions & 1 deletion src/sage/schemes/elliptic_curves/hom_sum.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,14 +60,22 @@

class EllipticCurveHom_sum(EllipticCurveHom):

_degree = None
_phis = None
_degree = None

def __init__(self, phis, domain=None, codomain=None):
r"""
Construct a sum morphism of elliptic curves from its summands.
(For empty sums, the domain and codomain curves must be given.)

.. TODO::

This class :class:`EllipticCurveHom_sum` really should inherit from
:class:`SchemeMorphism_sum`. However, there's a lot of issues that
I can't figure out how to resolve, mainly regarding
multi-inheritance in Python and which methods the coercion model
should use. See :issue:`37705` for some of my thoughts.

EXAMPLES::

sage: from sage.schemes.elliptic_curves.hom_sum import EllipticCurveHom_sum
Expand Down
19 changes: 0 additions & 19 deletions src/sage/schemes/elliptic_curves/homset.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@
# ****************************************************************************

from sage.rings.integer_ring import ZZ
from sage.categories.morphism import Morphism
from sage.schemes.generic.homset import SchemeHomset_generic
from sage.schemes.elliptic_curves.ell_generic import EllipticCurve_generic

Expand Down Expand Up @@ -231,24 +230,6 @@ def _repr_(self):
s += f'\n To: {self.codomain()}'
return s

def identity(self):
r"""
Return the identity morphism in this elliptic-curve homset
as an :class:`EllipticCurveHom` object.

EXAMPLES::

sage: E = EllipticCurve(j=42)
sage: End(E).identity()
Elliptic-curve endomorphism of Elliptic Curve defined by y^2 = x^3 + 5901*x + 1105454 over Rational Field
Via: (u,r,s,t) = (1, 0, 0, 0)
sage: End(E).identity() == E.scalar_multiplication(1)
True
"""
if not self.is_endomorphism_set():
raise ValueError('domain and codomain must be equal')
return self.domain().identity_morphism()

def is_commutative(self):
r"""
Assuming this homset is an endomorphism ring, check whether
Expand Down
100 changes: 81 additions & 19 deletions src/sage/schemes/generic/homset.py
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@
from sage.categories.schemes import Schemes
category = Schemes(base_spec)
key = (id(X), id(Y), category, as_point_homset)
extra = {'X':X, 'Y':Y, 'base_ring':base_ring, 'check':check}
extra = {'X': X, 'Y': Y, 'base_ring': base_ring, 'check': check}
return key, extra

def create_object(self, version, key, **extra_args):
Expand Down Expand Up @@ -245,9 +245,7 @@
sage: from sage.schemes.generic.homset import SchemeHomset_generic
sage: A2 = AffineSpace(QQ,2)
sage: Hom = SchemeHomset_generic(A2, A2); Hom
Set of morphisms
From: Affine Space of dimension 2 over Rational Field
To: Affine Space of dimension 2 over Rational Field
Set of scheme endomorphisms of Affine Space of dimension 2 over Rational Field
sage: Hom.category()
Category of endsets of schemes over Rational Field
"""
Expand All @@ -265,8 +263,9 @@
sage: loads(Hom.dumps()) == Hom
True
"""
return SchemeHomset, (self.domain(), self.codomain(), self.homset_category(),
self.base_ring(), False, False)
return SchemeHomset, (self.domain(), self.codomain(),
self.homset_category(), self.base_ring(), False,
False)

def __call__(self, *args, **kwds):
r"""
Expand Down Expand Up @@ -295,15 +294,20 @@
EXAMPLES::

sage: A = AffineSpace(4, QQ)
sage: print(A.structure_morphism()._repr_())
Scheme morphism:
sage: print(repr(A.structure_morphism().parent()))
Set of morphisms
From: Affine Space of dimension 4 over Rational Field
To: Spectrum of Rational Field
Defn: Structure map

sage: print(repr(Spec(QQ).End()))
Set of scheme endomorphisms of Spectrum of Rational Field
"""
s = 'Set of morphisms'
s += '\n From: %s' % self.domain()
s += '\n To: %s' % self.codomain()
if self.is_endomorphism_set():
return f"Set of scheme endomorphisms of {self.domain()}"

s = "Set of morphisms"
s += f'\n From: {self.domain()}'
s += f'\n To: {self.codomain()}'
return s

def natural_map(self):
Expand All @@ -324,13 +328,74 @@
From: Affine Space of dimension 4 over Rational Field
To: Spectrum of Rational Field
Defn: Structure map

sage: Spec(QQ).End().natural_map()
Scheme endomorphism of Spectrum of Rational Field
Defn: Identity map
"""
X = self.domain()
Y = self.codomain()
if is_AffineScheme(Y) and Y.coordinate_ring() == X.base_ring():
return SchemeMorphism_structure_map(self)
if self.is_endomorphism_set():
return self.identity()
raise NotImplementedError

def identity(self):
r"""
Return the identity morphism in this homset.

Only implemented when this homset is an endomorphism set. In this case,
either the :meth:`identity_morphism` of the domain is returned, or a
:class:`SchemeMorphism_id` class is constructed.

.. SEEALSO:: :meth:`natural_map`

EXAMPLES::

sage: End(Spec(QQ)).identity()
Scheme endomorphism of Spectrum of Rational Field
Defn: Identity map

sage: Hom(Spec(ZZ), Spec(QQ)).identity()
Traceback (most recent call last):
...
ValueError: domain and codomain must be equal

Elliptic curves have a custom :meth:`identity_morphism`::

sage: E = EllipticCurve(j=42)
sage: End(E).identity()
Elliptic-curve endomorphism of Elliptic Curve defined by y^2 = x^3 + 5901*x + 1105454 over Rational Field
Via: (u,r,s,t) = (1, 0, 0, 0)
sage: End(E).identity() == E.scalar_multiplication(1)
True
"""
if not self.is_endomorphism_set():
raise ValueError('domain and codomain must be equal')
try:
return self.domain().identity_morphism()
except AttributeError:
from sage.schemes.generic.morphism import SchemeMorphism_id
return SchemeMorphism_id(self.domain())

Check warning on line 380 in src/sage/schemes/generic/homset.py

View check run for this annotation

Codecov / codecov/patch

src/sage/schemes/generic/homset.py#L378-L380

Added lines #L378 - L380 were not covered by tests

def _an_element_(self):
r"""
Return a morphism from this homset via the
:meth:`natural_map`, or :meth:`zero` if a natural map does
not exist.

EXAMPLES::

sage: Spec(QQ).End().an_element()
Scheme endomorphism of Spectrum of Rational Field
Defn: Identity map
"""
try:
return self.natural_map()
except NotImplementedError:
return self.zero()

def _element_constructor_(self, x, check=True):
"""
Construct a scheme morphism.
Expand Down Expand Up @@ -380,11 +445,9 @@
sage: A.<x,y> = AffineSpace(R)
sage: C = A.subscheme(x*y - 1)
sage: H = C.Hom(C); H
Set of morphisms
From: Closed subscheme of Affine Space of dimension 2 over Rational Field
defined by: x*y - 1
To: Closed subscheme of Affine Space of dimension 2 over Rational Field
defined by: x*y - 1
Set of scheme endomorphisms of Closed subscheme of Affine Space of
dimension 2 over Rational Field defined by:
x*y - 1
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sage: H(1)
Traceback (most recent call last):
...
Expand All @@ -401,7 +464,6 @@

raise TypeError("x must be a ring homomorphism, list or tuple")


# *******************************************************************
# Base class for points
# *******************************************************************
Expand Down Expand Up @@ -582,7 +644,7 @@
except AttributeError: # no .ambient_space
return False
elif isinstance(other, SchemeHomset_points):
#we are converting between scheme points
#we are converting between scheme points
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
#we are converting between scheme points
# we are converting between scheme points

source = other.codomain()
if isinstance(target, AlgebraicScheme_subscheme):
#subscheme coerce when there is containment
Expand Down
Loading
Loading