From 8088a117d2a29d83fe9c28685cce1ae468433be0 Mon Sep 17 00:00:00 2001 From: Gareth Ma Date: Sat, 30 Mar 2024 20:29:40 +0000 Subject: [PATCH 01/19] add `.End` method --- src/sage/categories/homset.py | 2 ++ src/sage/structure/parent.pyx | 41 +++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/src/sage/categories/homset.py b/src/sage/categories/homset.py index deb489a9042..a7f62861d3b 100644 --- a/src/sage/categories/homset.py +++ b/src/sage/categories/homset.py @@ -116,6 +116,8 @@ def Hom(X, Y, category=None, check=True): 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) + True sage: Hom(ZZ, QQ, Sets()) Set of Morphisms from Integer Ring to Rational Field in Category of sets diff --git a/src/sage/structure/parent.pyx b/src/sage/structure/parent.pyx index b63e8aa9341..3a34c9b39e6 100644 --- a/src/sage/structure/parent.pyx +++ b/src/sage/structure/parent.pyx @@ -1438,6 +1438,47 @@ cdef class Parent(sage.structure.category_object.CategoryObject): Hom_kwds = {} if category is None else {'category': category} return self.Hom(codomain, **Hom_kwds)(im_gens, **kwds) + def End(self, category=None): + r""" + Return the endomorphism set ``End(self, category)``, which is equivalent to + ``Hom(self, self, category)``. + + INPUT: + + - ``category`` -- a category or ``None`` (default: ``None``) + If ``None``, the category of ``self`` is used. + + OUTPUT: + + The endomorphism set of ``self`` in the category ``category``. + + .. SEEALSO:: :func:`~sage.categories.homset.End`, :func:`~sage.categories.homset.Hom` + + TODO:: + + The method does not return a endomorphism *ring*, since currently + there are no classes for sum (and composition, without computing + the rational maps) of endomorphisms. Ideally it should be unified + with :class:`sage.schemes.elliptic_curves.hom_sum.EllipticCurveHom_sum`. + + EXAMPLES:: + + sage: R. = PolynomialRing(QQ, 2) + sage: R.End() + Set of Homomorphisms from Multivariate Polynomial Ring in x, y over Rational Field to Rational Field + sage: R.End() is End(R) + True + sage: R.End() is R.Hom(R) + True + + This example illustrates the optional third argument:: + + sage: QQ.End(Sets()) + Set of Morphisms from Rational Field to Integer Ring in Category of sets + """ + from sage.categories.homset import End + return End(self, category) + ################################################################################# # New Coercion support functionality ################################################################################# From d58dcb7ba82f7532d8742fbea97b1b4ef76f4607 Mon Sep 17 00:00:00 2001 From: Gareth Ma Date: Sun, 31 Mar 2024 00:57:45 +0000 Subject: [PATCH 02/19] initial SchemeMorphism_add --- src/sage/schemes/elliptic_curves/hom_sum.py | 37 +--- src/sage/schemes/generic/homset.py | 61 +++++- src/sage/schemes/generic/morphism.py | 193 +++++++++++++++++- .../hyperelliptic_curves/jacobian_homset.py | 2 + 4 files changed, 249 insertions(+), 44 deletions(-) diff --git a/src/sage/schemes/elliptic_curves/hom_sum.py b/src/sage/schemes/elliptic_curves/hom_sum.py index ab10ec0d530..3831513a782 100644 --- a/src/sage/schemes/elliptic_curves/hom_sum.py +++ b/src/sage/schemes/elliptic_curves/hom_sum.py @@ -43,6 +43,7 @@ """ from sage.misc.cachefunc import cached_method +from sage.schemes.generic.morphism import SchemeMorphism_sum from sage.structure.sequence import Sequence from sage.arith.misc import gcd @@ -58,10 +59,9 @@ from sage.schemes.elliptic_curves.hom import EllipticCurveHom, compare_via_evaluation -class EllipticCurveHom_sum(EllipticCurveHom): +class EllipticCurveHom_sum(EllipticCurveHom, SchemeMorphism_sum): _degree = None - _phis = None def __init__(self, phis, domain=None, codomain=None): r""" @@ -120,22 +120,6 @@ def __init__(self, phis, domain=None, codomain=None): EllipticCurveHom.__init__(self, self._domain, self._codomain) self._degree = None - def _call_(self, P): - r""" - Evaluate this sum morphism at a point. - - EXAMPLES:: - - sage: E = EllipticCurve(GF(101), [5,5]) - sage: phi = E.isogenies_prime_degree(7)[0] - sage: P = E.lift_x(0) - sage: (phi + phi)(P) - (72 : 56 : 1) - sage: (phi - phi)(P) - (0 : 1 : 0) - """ - return sum((phi(P) for phi in self._phis), self._codomain(0)) - def _eval(self, P): r""" Less strict evaluation method for internal use. @@ -181,23 +165,6 @@ def _repr_(self): f'\n To: {self._codomain}' \ f'\n Via: {self._phis}' - def summands(self): - r""" - Return the individual summands making up this sum morphism. - - EXAMPLES:: - - sage: E = EllipticCurve(j=5) - sage: m2 = E.scalar_multiplication(2) - sage: m3 = E.scalar_multiplication(3) - sage: m2 + m3 - Sum morphism: - From: Elliptic Curve defined by y^2 + x*y = x^3 + x^2 + 180*x + 17255 over Rational Field - To: Elliptic Curve defined by y^2 + x*y = x^3 + x^2 + 180*x + 17255 over Rational Field - Via: (Scalar-multiplication endomorphism [2] of Elliptic Curve defined by y^2 + x*y = x^3 + x^2 + 180*x + 17255 over Rational Field, Scalar-multiplication endomorphism [3] of Elliptic Curve defined by y^2 + x*y = x^3 + x^2 + 180*x + 17255 over Rational Field) - """ - return self._phis - @cached_method def to_isogeny_chain(self): r""" diff --git a/src/sage/schemes/generic/homset.py b/src/sage/schemes/generic/homset.py index 6fca9c1e257..0be5f869787 100644 --- a/src/sage/schemes/generic/homset.py +++ b/src/sage/schemes/generic/homset.py @@ -295,15 +295,20 @@ def _repr_(self): EXAMPLES:: sage: A = AffineSpace(4, QQ) - sage: print(A.structure_morphism()._repr_()) + sage: repr(A.structure_morphism().parent()) Scheme morphism: From: Affine Space of dimension 4 over Rational Field To: Spectrum of Rational Field - Defn: Structure map + + sage: 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): @@ -324,13 +329,58 @@ def natural_map(self): 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 Set of morphisms + From: Spectrum of Rational Field + To: 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 as an + :class:`SchemeMorphism` object. + + .. SEEALSO:: :method:`natural_map` + + EXAMPLES:: + + sage: Spec(QQ).End().identity() + Scheme endomorphism of Set of morphisms + From: Spectrum of Rational Field + To: Spectrum of Rational Field + Defn: Identity map + + sage: Hom(Spec(ZZ), Spec(QQ)).identity() + Traceback (most recent call first): + ... + ValueError: domain and codomain must be equal + """ + if not self.is_endomorphism_set(): + raise ValueError('domain and codomain must be equal') + from sage.schemes.generic.morphism import SchemeMorphism_id + return SchemeMorphism_id(self.domain()) + + def _an_element_(self): + r""" + Return a morphism from this homset via the :meth:`natural_map`. In + particular, it returns the identity map when this is an endomorphism + set. + + EXAMPLES:: + + sage: Spec(QQ).End().an_element() + """ + return self.natural_map() + def _element_constructor_(self, x, check=True): """ Construct a scheme morphism. @@ -401,7 +451,6 @@ def _element_constructor_(self, x, check=True): raise TypeError("x must be a ring homomorphism, list or tuple") - # ******************************************************************* # Base class for points # ******************************************************************* diff --git a/src/sage/schemes/generic/morphism.py b/src/sage/schemes/generic/morphism.py index 7d91214e32a..9032fa8b2f6 100644 --- a/src/sage/schemes/generic/morphism.py +++ b/src/sage/schemes/generic/morphism.py @@ -60,6 +60,8 @@ - Simon King (2013-10): copy the changes of :class:`~sage.categories.morphism.Morphism` that have been introduced in :issue:`14711`. + +- Lorenz Panny, Gareth Ma (Mar 2024): introduce :class:`SchemeMorphism_sum`. """ # **************************************************************************** @@ -337,13 +339,49 @@ def _repr_(self): s += "\n To: %s" % self._codomain d = self._repr_defn() if d != '': - s += "\n Defn: %s" % ('\n '.join(self._repr_defn().split('\n'))) + s += "\n Defn: %s" % '\n '.join(d.split('\n')) return s - def __mul__(self, right): + def _add_(self, other): + r""" + Add two :class:`SchemeMorphism` objects by constructing a + formal :class:`SchemeMorphism_sum`. + + EXAMPLES:: + + sage: phi = Spec(QQ).End().identity() + sage: phi + phi + Sum morphism: + From: Set of morphisms + From: Spectrum of Rational Field + To: Spectrum of Rational Field + To: Set of morphisms + From: Spectrum of Rational Field + To: Spectrum of Rational Field + Via: (Scheme endomorphism of Set of morphisms + From: Spectrum of Rational Field + To: Spectrum of Rational Field + Defn: Identity map, Scheme endomorphism of Set of morphisms + From: Spectrum of Rational Field + To: Spectrum of Rational Field + Defn: Identity map) """ - We can currently only multiply scheme morphisms. + phis = [] + if isinstance(self, SchemeMorphism_sum): + phis.extend(self.summands()) + else: + phis.append(self) + if isinstance(other, SchemeMorphism_sum): + phis.extend(other.summands()) + else: + phis.append(other) + + #TODO should probably try to simplify some more? + assert other.domain() == self.domain() and other.codomain() == self.codomain() + return SchemeMorphism_sum(phis, domain=self.domain(), codomain=self.codomain()) + def __mul__(self, right): + """ If one factor is an identity morphism, the other is returned. Otherwise, a formal composition of maps obtained from the scheme morphisms is returned. @@ -669,6 +707,109 @@ def glue_along_domains(self, other): return glue.GluedScheme(self, other) +class SchemeMorphism_sum(SchemeMorphism): + """ + Formal sum of scheme morphisms. + + EXAMPLES:: + + PR_TODO + """ + + _phis = None + + def __init__(self, phis, domain=None, codomain=None, check=True): + r""" + Construct a sum morphism from its summands. + + The codomain scheme should implement addition. For empty sums, the + domain and codomain schemes must be given. + + EXAMPLES:: + + sage: from src.sage.schemes.generic.morphism import SchemeMorphism_sum + sage: phi = Spec(QQ).identity_morphism() + sage: SchemeMorphism_sum([phi, phi]) + PR_TODO + + The zero morphism can be defined when the codomain implements addition:: + + sage: SchemeMorphism_sum([], Spec(QQ), ZZ) + Sum morphism: + From: Spectrum of Rational Field + To: Spectrum of Integer Ring + Via: () + """ + phis = tuple(phis) + + if not phis and (domain is None or codomain is None): + raise ValueError('need either phis or both domain and codomain') + + for phi in phis: + if not isinstance(phi, SchemeMorphism): + raise ValueError(f'not a scheme morphism: {phi}') + + if domain is None: + domain = phis[0].domain() + if codomain is None: + codomain = phis[0].codomain() + if check: + try: + x = codomain.an_element() + _ = x + x + except (TypeError, NotImplementedError): + raise ValueError(f"addition is not implemented for {codomain}") + for phi in phis: + if phi.domain() != domain: + raise ValueError(f'summand {phi} has incorrect domain (need {domain})') + if phi.codomain() != codomain: + raise ValueError(f'summand {phi} has incorrect codomain (need {codomain})') + + self._phis = phis + self._domain = domain + SchemeMorphism.__init__(self, self._domain, codomain) + + def _call_(self, P): + r""" + Evaluate this sum morphism at a point. + + EXAMPLES:: + + ... + """ + return sum((phi(P) for phi in self._phis), self._codomain.zero()) + + def _repr_(self): + r""" + Return basic facts about this sum morphism as a string. + + EXAMPLES:: + + ... + """ + return f'Sum morphism:' \ + f'\n From: {self._domain}' \ + f'\n To: {self._codomain}' \ + f'\n Via: {self._phis}' + + def summands(self): + r""" + Return the individual summands making up this sum morphism. + + EXAMPLES:: + + sage: E = EllipticCurve(j=5) + sage: m2 = E.scalar_multiplication(2) + sage: m3 = E.scalar_multiplication(3) + sage: m2 + m3 + Sum morphism: + From: Elliptic Curve defined by y^2 + x*y = x^3 + x^2 + 180*x + 17255 over Rational Field + To: Elliptic Curve defined by y^2 + x*y = x^3 + x^2 + 180*x + 17255 over Rational Field + Via: (Scalar-multiplication endomorphism [2] of Elliptic Curve defined by y^2 + x*y = x^3 + x^2 + 180*x + 17255 over Rational Field, Scalar-multiplication endomorphism [3] of Elliptic Curve defined by y^2 + x*y = x^3 + x^2 + 180*x + 17255 over Rational Field) + """ + return self._phis + + class SchemeMorphism_id(SchemeMorphism): """ Return the identity morphism from `X` to itself. @@ -698,6 +839,8 @@ def __init__(self, X): """ SchemeMorphism.__init__(self, X.Hom(X)) + # TODO: Replace all _repr_defn with just _repr_ overload + # For example, this should be an "Identity endomorphism of ..." directly def _repr_defn(self): r""" Return a string representation of the definition of ``self``. @@ -713,6 +856,36 @@ def _repr_defn(self): """ return 'Identity map' + def _call_(self, P): + r""" + Compute image of `P` under the identity morphism, which is `P`. + + INPUT: + + - ``P`` -- a scheme. + + OUTPUT: + + The scheme `P`. + + EXAMPLES:: + + sage: S = Spec(QQ).an_element() + sage: Spec(QQ).End().identity()(S) == S + True + + sage: R. = QQ[] + sage: J = HyperellipticCurve(x^5 - 8*x).jacobian() + sage: P = J(2, 4); P + (2, y - 4) + sage: phi = J.End().identity(); phi + Scheme endomorphism of Jacobian of Hyperelliptic Curve over Rational Field defined by y^2 = x^5 - x + Defn: Identity map + sage: phi(P) + (1) + """ + return P + class SchemeMorphism_structure_map(SchemeMorphism): r""" @@ -2146,3 +2319,17 @@ def specialization(self, D=None, phi=None, ambient=None): ambient = ambient.change_ring(phi.codomain().base_ring()) psi = ambient.ambient_space().coordinate_ring().hom([0 for i in range(ambient.ambient_space().ngens())], ambient.base_ring()) return ambient([psi(phi(t)) for t in self]) + + def _add_(self, point): + r""" + Add two point schemes. + + EXAMPLES:: + + sage: A = AffineSpace(QQ, 2) + sage: A(2, 3) + A(3, 5) + Traceback (most recent call first): + ... + NotImplementedError + """ + raise NotImplementedError diff --git a/src/sage/schemes/hyperelliptic_curves/jacobian_homset.py b/src/sage/schemes/hyperelliptic_curves/jacobian_homset.py index a5f4f63876c..11b4575d9bb 100644 --- a/src/sage/schemes/hyperelliptic_curves/jacobian_homset.py +++ b/src/sage/schemes/hyperelliptic_curves/jacobian_homset.py @@ -121,6 +121,8 @@ def __call__(self, P): R = PolynomialRing(self.value_ring(), 'x') return JacobianMorphism_divisor_class_field(self, (R.one(), R.zero())) + elif len(P) == 1: + return self(P[0]) elif len(P) == 2: P1 = P[0] P2 = P[1] From 50af7fb07e84a923c00f85217c369574e823e4a5 Mon Sep 17 00:00:00 2001 From: Gareth Ma Date: Sun, 31 Mar 2024 02:25:19 +0000 Subject: [PATCH 03/19] fix most doctests --- src/sage/schemes/affine/affine_homset.py | 8 ++--- src/sage/schemes/affine/affine_space.py | 4 +-- .../schemes/elliptic_curves/ell_generic.py | 2 +- src/sage/schemes/elliptic_curves/homset.py | 1 + src/sage/schemes/generic/homset.py | 30 +++++++------------ src/sage/schemes/generic/morphism.py | 28 ++++++++--------- src/sage/schemes/generic/scheme.py | 4 +-- .../schemes/projective/projective_homset.py | 8 ++--- .../schemes/projective/projective_space.py | 4 +-- 9 files changed, 32 insertions(+), 57 deletions(-) diff --git a/src/sage/schemes/affine/affine_homset.py b/src/sage/schemes/affine/affine_homset.py index b6570bd6f6d..cb022f03696 100644 --- a/src/sage/schemes/affine/affine_homset.py +++ b/src/sage/schemes/affine/affine_homset.py @@ -113,9 +113,7 @@ class SchemeHomset_polynomial_affine_space(SchemeHomset_generic): sage: A. = 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): """ @@ -126,9 +124,7 @@ def identity(self): sage: A. = 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 """ diff --git a/src/sage/schemes/affine/affine_space.py b/src/sage/schemes/affine/affine_space.py index 05d3c5b59e3..8ebce80e139 100644 --- a/src/sage/schemes/affine/affine_space.py +++ b/src/sage/schemes/affine/affine_space.py @@ -371,9 +371,7 @@ def _homset(self, *args, **kwds): sage: A. = 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) diff --git a/src/sage/schemes/elliptic_curves/ell_generic.py b/src/sage/schemes/elliptic_curves/ell_generic.py index b887b7666b5..2500e7cf5f1 100644 --- a/src/sage/schemes/elliptic_curves/ell_generic.py +++ b/src/sage/schemes/elliptic_curves/ell_generic.py @@ -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) diff --git a/src/sage/schemes/elliptic_curves/homset.py b/src/sage/schemes/elliptic_curves/homset.py index c6516f9b34b..4ccca129628 100644 --- a/src/sage/schemes/elliptic_curves/homset.py +++ b/src/sage/schemes/elliptic_curves/homset.py @@ -101,6 +101,7 @@ def __init__(self, E1, E2, category=None): sage: E2 = EllipticCurve(GF(101), [4,9]) sage: H = Hom(E1, E2) sage: TestSuite(H).run(skip='_test_elements') + # PR_TODO: Fix :: diff --git a/src/sage/schemes/generic/homset.py b/src/sage/schemes/generic/homset.py index 0be5f869787..d3b69314f2a 100644 --- a/src/sage/schemes/generic/homset.py +++ b/src/sage/schemes/generic/homset.py @@ -245,9 +245,7 @@ class SchemeHomset_generic(HomsetWithBase): 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 """ @@ -295,12 +293,12 @@ def _repr_(self): EXAMPLES:: sage: A = AffineSpace(4, QQ) - sage: repr(A.structure_morphism().parent()) - 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 - sage: repr(Spec(QQ).End()) + sage: print(repr(Spec(QQ).End())) Set of scheme endomorphisms of Spectrum of Rational Field """ if self.is_endomorphism_set(): @@ -331,9 +329,7 @@ def natural_map(self): Defn: Structure map sage: Spec(QQ).End().natural_map() - Scheme endomorphism of Set of morphisms - From: Spectrum of Rational Field - To: Spectrum of Rational Field + Scheme endomorphism of Spectrum of Rational Field Defn: Identity map """ X = self.domain() @@ -353,14 +349,11 @@ def identity(self): EXAMPLES:: - sage: Spec(QQ).End().identity() - Scheme endomorphism of Set of morphisms - From: Spectrum of Rational Field - To: Spectrum of Rational Field + Scheme endomorphism of Spectrum of Rational Field Defn: Identity map sage: Hom(Spec(ZZ), Spec(QQ)).identity() - Traceback (most recent call first): + Traceback (most recent call last): ... ValueError: domain and codomain must be equal """ @@ -378,6 +371,8 @@ def _an_element_(self): EXAMPLES:: sage: Spec(QQ).End().an_element() + Scheme endomorphism of Spectrum of Rational Field + Defn: Identity map """ return self.natural_map() @@ -430,11 +425,8 @@ def _element_constructor_(self, x, check=True): sage: A. = 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 sage: H(1) Traceback (most recent call last): ... diff --git a/src/sage/schemes/generic/morphism.py b/src/sage/schemes/generic/morphism.py index 9032fa8b2f6..4c336b7bfe5 100644 --- a/src/sage/schemes/generic/morphism.py +++ b/src/sage/schemes/generic/morphism.py @@ -102,8 +102,7 @@ def is_SchemeMorphism(f): OUTPUT: - Boolean. Return ``True`` if ``f`` is a scheme morphism or a point - on an elliptic curve. + Boolean. Return ``True`` if ``f`` is a scheme morphism. EXAMPLES:: @@ -114,9 +113,13 @@ def is_SchemeMorphism(f): sage: from sage.schemes.generic.morphism import is_SchemeMorphism sage: is_SchemeMorphism(f) True + + sage: E = EllipticCurve(GF(103), [3, 5]) + sage: P = E.random_point() + sage: is_SchemeMorphism(P) + True """ - from sage.schemes.elliptic_curves.ell_point import EllipticCurvePoint_field - return isinstance(f, (SchemeMorphism, EllipticCurvePoint_field)) + return isinstance(f, SchemeMorphism) class SchemeMorphism(Element): @@ -727,7 +730,7 @@ def __init__(self, phis, domain=None, codomain=None, check=True): EXAMPLES:: - sage: from src.sage.schemes.generic.morphism import SchemeMorphism_sum + sage: from sage.schemes.generic.morphism import SchemeMorphism_sum sage: phi = Spec(QQ).identity_morphism() sage: SchemeMorphism_sum([phi, phi]) PR_TODO @@ -798,14 +801,7 @@ def summands(self): EXAMPLES:: - sage: E = EllipticCurve(j=5) - sage: m2 = E.scalar_multiplication(2) - sage: m3 = E.scalar_multiplication(3) - sage: m2 + m3 - Sum morphism: - From: Elliptic Curve defined by y^2 + x*y = x^3 + x^2 + 180*x + 17255 over Rational Field - To: Elliptic Curve defined by y^2 + x*y = x^3 + x^2 + 180*x + 17255 over Rational Field - Via: (Scalar-multiplication endomorphism [2] of Elliptic Curve defined by y^2 + x*y = x^3 + x^2 + 180*x + 17255 over Rational Field, Scalar-multiplication endomorphism [3] of Elliptic Curve defined by y^2 + x*y = x^3 + x^2 + 180*x + 17255 over Rational Field) + wrong """ return self._phis @@ -879,10 +875,10 @@ def _call_(self, P): sage: P = J(2, 4); P (2, y - 4) sage: phi = J.End().identity(); phi - Scheme endomorphism of Jacobian of Hyperelliptic Curve over Rational Field defined by y^2 = x^5 - x + Scheme endomorphism of Jacobian of Hyperelliptic Curve over Rational Field defined by y^2 = x^5 - 8*x Defn: Identity map sage: phi(P) - (1) + (2, y - 4) """ return P @@ -2328,7 +2324,7 @@ def _add_(self, point): sage: A = AffineSpace(QQ, 2) sage: A(2, 3) + A(3, 5) - Traceback (most recent call first): + Traceback (most recent call last): ... NotImplementedError """ diff --git a/src/sage/schemes/generic/scheme.py b/src/sage/schemes/generic/scheme.py index 2c0e3100c86..6740669b577 100644 --- a/src/sage/schemes/generic/scheme.py +++ b/src/sage/schemes/generic/scheme.py @@ -971,9 +971,7 @@ def __call__(self, *args): following one:: sage: S(S) - Set of morphisms - From: Spectrum of Integer Ring - To: Spectrum of Integer Ring + Set of scheme endomorphisms of Spectrum of Integer Ring For affine or projective varieties, passing the correct number of elements of the base ring constructs the rational point diff --git a/src/sage/schemes/projective/projective_homset.py b/src/sage/schemes/projective/projective_homset.py index 91c01a51128..5674d9a05b3 100644 --- a/src/sage/schemes/projective/projective_homset.py +++ b/src/sage/schemes/projective/projective_homset.py @@ -540,9 +540,7 @@ class SchemeHomset_polynomial_projective_space(SchemeHomset_generic): sage: P. = ProjectiveSpace(2, QQ) sage: Hom(P, P) - Set of morphisms - From: Projective Space of dimension 2 over Rational Field - To: Projective Space of dimension 2 over Rational Field + Set of scheme endomorphisms of Projective Space of dimension 2 over Rational Field """ def identity(self): """ @@ -552,9 +550,7 @@ def identity(self): sage: P. = ProjectiveSpace(2, QQ) sage: Hom(P, P) - Set of morphisms - From: Projective Space of dimension 2 over Rational Field - To: Projective Space of dimension 2 over Rational Field + Set of scheme endomorphisms of Projective Space of dimension 2 over Rational Field sage: _.identity() Scheme endomorphism of Projective Space of dimension 2 over Rational Field Defn: Identity map diff --git a/src/sage/schemes/projective/projective_space.py b/src/sage/schemes/projective/projective_space.py index 5c55a62106e..ee80059e92d 100644 --- a/src/sage/schemes/projective/projective_space.py +++ b/src/sage/schemes/projective/projective_space.py @@ -750,9 +750,7 @@ def _homset(self, *args, **kwds): sage: P. = ProjectiveSpace(2, QQ) sage: Hom(P, P) - Set of morphisms - From: Projective Space of dimension 2 over Rational Field - To: Projective Space of dimension 2 over Rational Field + Set of scheme endomorphisms of Projective Space of dimension 2 over Rational Field """ return SchemeHomset_polynomial_projective_space(*args, **kwds) From 5a9b44a7717c436b7eaa2e47cbc48a1d03d4d906 Mon Sep 17 00:00:00 2001 From: Gareth Ma Date: Sun, 31 Mar 2024 13:13:55 +0100 Subject: [PATCH 04/19] Hot fix for multiprocessing issue https://sagemath.zulipchat.com/#narrow/stream/271070-help---build/topic/Too.20many.20open.20files.3F/near/430442342 --- src/sage/features/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/features/__init__.py b/src/sage/features/__init__.py index 6af9413e55a..a8b11ef7db5 100644 --- a/src/sage/features/__init__.py +++ b/src/sage/features/__init__.py @@ -162,7 +162,7 @@ def __init__(self, name, spkg=None, url=None, description=None, type='optional') # shared among subprocesses. Thus we use the Value class from the # multiprocessing module (cf. self._seen of class AvailableSoftware) from multiprocessing import Value - self._num_hidings = Value('i', 0) + self._num_hidings = Value('i', 0, lock=False) try: from sage.misc.package import spkg_type From a0af15e284b9ab0074d3b9f4c3fc101ebd6fe7e3 Mon Sep 17 00:00:00 2001 From: Gareth Ma Date: Sun, 31 Mar 2024 16:01:26 +0100 Subject: [PATCH 05/19] richcmp and refactoring --- src/sage/schemes/elliptic_curves/homset.py | 20 ---- src/sage/schemes/generic/homset.py | 46 +++++--- src/sage/schemes/generic/morphism.py | 101 ++++++++++++++---- .../hyperelliptic_curves/jacobian_generic.py | 15 +++ 4 files changed, 129 insertions(+), 53 deletions(-) diff --git a/src/sage/schemes/elliptic_curves/homset.py b/src/sage/schemes/elliptic_curves/homset.py index 4ccca129628..e925adb9245 100644 --- a/src/sage/schemes/elliptic_curves/homset.py +++ b/src/sage/schemes/elliptic_curves/homset.py @@ -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 @@ -101,7 +100,6 @@ def __init__(self, E1, E2, category=None): sage: E2 = EllipticCurve(GF(101), [4,9]) sage: H = Hom(E1, E2) sage: TestSuite(H).run(skip='_test_elements') - # PR_TODO: Fix :: @@ -232,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 diff --git a/src/sage/schemes/generic/homset.py b/src/sage/schemes/generic/homset.py index d3b69314f2a..81b080cf71e 100644 --- a/src/sage/schemes/generic/homset.py +++ b/src/sage/schemes/generic/homset.py @@ -176,7 +176,7 @@ def create_key_and_extra_args(self, X, Y, category=None, base=None, 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): @@ -263,8 +263,9 @@ def __reduce__(self): 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""" @@ -342,13 +343,17 @@ def natural_map(self): def identity(self): r""" - Return the identity morphism in this homset as an - :class:`SchemeMorphism` object. + 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:: :method:`natural_map` + .. SEEALSO:: :meth:`natural_map` EXAMPLES:: + sage: End(Spec(QQ)).identity() Scheme endomorphism of Spectrum of Rational Field Defn: Identity map @@ -356,17 +361,29 @@ def identity(self): 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') - from sage.schemes.generic.morphism import SchemeMorphism_id - return SchemeMorphism_id(self.domain()) + try: + return self.domain().identity_morphism() + except AttributeError: + from sage.schemes.generic.morphism import SchemeMorphism_id + return SchemeMorphism_id(self.domain()) def _an_element_(self): r""" - Return a morphism from this homset via the :meth:`natural_map`. In - particular, it returns the identity map when this is an endomorphism - set. + Return a morphism from this homset via the + :meth:`natural_map`, or :meth:`zero` if a natural map does + not exist. EXAMPLES:: @@ -374,7 +391,10 @@ def _an_element_(self): Scheme endomorphism of Spectrum of Rational Field Defn: Identity map """ - return self.natural_map() + try: + return self.natural_map() + except NotImplementedError: + return self.zero() def _element_constructor_(self, x, check=True): """ @@ -623,7 +643,7 @@ def _coerce_map_from_(self, other): except AttributeError: # no .ambient_space return False elif isinstance(other, SchemeHomset_points): - #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 diff --git a/src/sage/schemes/generic/morphism.py b/src/sage/schemes/generic/morphism.py index 4c336b7bfe5..e3521720e96 100644 --- a/src/sage/schemes/generic/morphism.py +++ b/src/sage/schemes/generic/morphism.py @@ -352,21 +352,15 @@ def _add_(self, other): EXAMPLES:: - sage: phi = Spec(QQ).End().identity() + sage: R. = QQ[] + sage: J = HyperellipticCurve(x^5 + x + 1).jacobian() + sage: phi = End(J).identity() sage: phi + phi Sum morphism: - From: Set of morphisms - From: Spectrum of Rational Field - To: Spectrum of Rational Field - To: Set of morphisms - From: Spectrum of Rational Field - To: Spectrum of Rational Field - Via: (Scheme endomorphism of Set of morphisms - From: Spectrum of Rational Field - To: Spectrum of Rational Field - Defn: Identity map, Scheme endomorphism of Set of morphisms - From: Spectrum of Rational Field - To: Spectrum of Rational Field + From: Jacobian of Hyperelliptic Curve over Rational Field defined by y^2 = x^5 + x + 1 + To: Jacobian of Hyperelliptic Curve over Rational Field defined by y^2 = x^5 + x + 1 + Via: (Scheme endomorphism of Jacobian of Hyperelliptic Curve over Rational Field defined by y^2 = x^5 + x + 1 + Defn: Identity map, Scheme endomorphism of Jacobian of Hyperelliptic Curve over Rational Field defined by y^2 = x^5 + x + 1 Defn: Identity map) """ phis = [] @@ -716,7 +710,18 @@ class SchemeMorphism_sum(SchemeMorphism): EXAMPLES:: - PR_TODO + sage: R. = QQ[] + sage: J = HyperellipticCurve(x^5 - 8*x).jacobian() + sage: phi = End(J).identity(); phi + Scheme endomorphism of Jacobian of Hyperelliptic Curve over Rational Field defined by y^2 = x^5 - 8*x + Defn: Identity map + sage: psi = phi + phi; psi + Sum morphism: + From: Jacobian of Hyperelliptic Curve over Rational Field defined by y^2 = x^5 - 8*x + To: Jacobian of Hyperelliptic Curve over Rational Field defined by y^2 = x^5 - 8*x + Via: (Scheme endomorphism of Jacobian of Hyperelliptic Curve over Rational Field defined by y^2 = x^5 - 8*x + Defn: Identity map, Scheme endomorphism of Jacobian of Hyperelliptic Curve over Rational Field defined by y^2 = x^5 - 8*x + Defn: Identity map) """ _phis = None @@ -731,9 +736,34 @@ def __init__(self, phis, domain=None, codomain=None, check=True): EXAMPLES:: sage: from sage.schemes.generic.morphism import SchemeMorphism_sum + sage: R. = QQ[] + sage: J = HyperellipticCurve(x^5 - 8*x).jacobian() + sage: phi = End(J).identity(); phi + Scheme endomorphism of Jacobian of Hyperelliptic Curve over Rational Field defined by y^2 = x^5 - 8*x + Defn: Identity map + sage: psi = SchemeMorphism_sum([phi, phi, phi]); psi + Sum morphism: + From: Jacobian of Hyperelliptic Curve over Rational Field defined by y^2 = x^5 - 8*x + To: Jacobian of Hyperelliptic Curve over Rational Field defined by y^2 = x^5 - 8*x + Via: (Scheme endomorphism of Jacobian of Hyperelliptic Curve over Rational Field defined by y^2 = x^5 - 8*x + Defn: Identity map, Scheme endomorphism of Jacobian of Hyperelliptic Curve over Rational Field defined by y^2 = x^5 - 8*x + Defn: Identity map, Scheme endomorphism of Jacobian of Hyperelliptic Curve over Rational Field defined by y^2 = x^5 - 8*x + Defn: Identity map) + sage: phi + phi == phi + phi + True + sage: psi == phi + phi + phi + True + + sage: P = J(2, 4); (P, psi(P), P * 3) + ((2, y - 4), (1), (1)) + + The codomain should implement addition:: + sage: phi = Spec(QQ).identity_morphism() sage: SchemeMorphism_sum([phi, phi]) - PR_TODO + Traceback (most recent call last): + ... + ValueError: addition is not implemented for Spectrum of Rational Field The zero morphism can be defined when the codomain implements addition:: @@ -778,7 +808,7 @@ def _call_(self, P): EXAMPLES:: - ... + PR_TODO """ return sum((phi(P) for phi in self._phis), self._codomain.zero()) @@ -788,7 +818,7 @@ def _repr_(self): EXAMPLES:: - ... + PR_TODO """ return f'Sum morphism:' \ f'\n From: {self._domain}' \ @@ -801,10 +831,41 @@ def summands(self): EXAMPLES:: - wrong + PR_TODO """ return self._phis + # PR_TODO: Implement equality check + # How to do it non-stupidly? + def _richcmp_(self, other, op): + r""" + Help. + + EXAMPLES:: + + sage: R. = QQ[] + sage: J = HyperellipticCurve(x^5 - 8*x).jacobian() + sage: phi = End(J).identity() + sage: phi == phi + True + sage: phi + phi == phi + phi + True + sage: phi + phi == phi + phi + phi + False + sage: sorted([phi + phi, phi + phi]) + Traceback (most recent call last): + ... + TypeError: '<' not supported between instances of 'SchemeMorphism_sum' and 'SchemeMorphism_sum' + """ + if not isinstance(other, SchemeMorphism_sum): + return self._richcmp_(SchemeMorphism_sum([other]), op) + + from sage.structure.richcmp import op_EQ + if op != op_EQ: + return NotImplemented + + return self._phis == other._phis + class SchemeMorphism_id(SchemeMorphism): """ @@ -867,14 +928,14 @@ def _call_(self, P): EXAMPLES:: sage: S = Spec(QQ).an_element() - sage: Spec(QQ).End().identity()(S) == S + sage: End(Spec(QQ)).identity()(S) == S True sage: R. = QQ[] sage: J = HyperellipticCurve(x^5 - 8*x).jacobian() sage: P = J(2, 4); P (2, y - 4) - sage: phi = J.End().identity(); phi + sage: phi = End(J).identity(); phi Scheme endomorphism of Jacobian of Hyperelliptic Curve over Rational Field defined by y^2 = x^5 - 8*x Defn: Identity map sage: phi(P) diff --git a/src/sage/schemes/hyperelliptic_curves/jacobian_generic.py b/src/sage/schemes/hyperelliptic_curves/jacobian_generic.py index 2e91a96e02a..d97ebbc917e 100644 --- a/src/sage/schemes/hyperelliptic_curves/jacobian_generic.py +++ b/src/sage/schemes/hyperelliptic_curves/jacobian_generic.py @@ -142,6 +142,21 @@ class HyperellipticJacobian_generic(Jacobian_generic): sage: J1 == J2 False """ + def zero(self): + """ + Return the additive identity of this Jacobian. + + EXAMPLES:: + + sage: R. = QQ[] + sage: J = HyperellipticCurve(x^5 + x + 1).jacobian() + sage: J.zero() + (1) + sage: J.zero() == J(0) == J.point(0) + True + """ + return self.point(0) + def dimension(self): """ Return the dimension of this Jacobian. From cfccbd7174e3ffd78003a261bc281728420e69ee Mon Sep 17 00:00:00 2001 From: Gareth Ma Date: Sun, 31 Mar 2024 16:03:39 +0100 Subject: [PATCH 06/19] remove a random rant in my code --- src/sage/structure/parent.pyx | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/sage/structure/parent.pyx b/src/sage/structure/parent.pyx index 3a34c9b39e6..85578b26163 100644 --- a/src/sage/structure/parent.pyx +++ b/src/sage/structure/parent.pyx @@ -1454,13 +1454,6 @@ cdef class Parent(sage.structure.category_object.CategoryObject): .. SEEALSO:: :func:`~sage.categories.homset.End`, :func:`~sage.categories.homset.Hom` - TODO:: - - The method does not return a endomorphism *ring*, since currently - there are no classes for sum (and composition, without computing - the rational maps) of endomorphisms. Ideally it should be unified - with :class:`sage.schemes.elliptic_curves.hom_sum.EllipticCurveHom_sum`. - EXAMPLES:: sage: R. = PolynomialRing(QQ, 2) From 5dcc121f3c1b6a20f20ea2ef23cb49f7881a7d7d Mon Sep 17 00:00:00 2001 From: Gareth Ma Date: Sun, 31 Mar 2024 16:52:51 +0100 Subject: [PATCH 07/19] write documentation (examples) --- src/sage/schemes/generic/morphism.py | 40 +++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/src/sage/schemes/generic/morphism.py b/src/sage/schemes/generic/morphism.py index e3521720e96..28a57951340 100644 --- a/src/sage/schemes/generic/morphism.py +++ b/src/sage/schemes/generic/morphism.py @@ -808,7 +808,12 @@ def _call_(self, P): EXAMPLES:: - PR_TODO + sage: R. = QQ[] + sage: J = HyperellipticCurve(x^5 - 8*x).jacobian() + sage: phi = End(J).identity() + sage: P = J(2, 4) + sage: (phi + phi)(P) == P * 2 + True """ return sum((phi(P) for phi in self._phis), self._codomain.zero()) @@ -818,7 +823,16 @@ def _repr_(self): EXAMPLES:: - PR_TODO + sage: R. = QQ[] + sage: J = HyperellipticCurve(x^5 - 8*x).jacobian() + sage: phi = End(J).identity() + sage: phi + phi + Sum morphism: + From: Jacobian of Hyperelliptic Curve over Rational Field defined by y^2 = x^5 - 8*x + To: Jacobian of Hyperelliptic Curve over Rational Field defined by y^2 = x^5 - 8*x + Via: (Scheme endomorphism of Jacobian of Hyperelliptic Curve over Rational Field defined by y^2 = x^5 - 8*x + Defn: Identity map, Scheme endomorphism of Jacobian of Hyperelliptic Curve over Rational Field defined by y^2 = x^5 - 8*x + Defn: Identity map) """ return f'Sum morphism:' \ f'\n From: {self._domain}' \ @@ -831,7 +845,16 @@ def summands(self): EXAMPLES:: - PR_TODO + sage: R. = QQ[] + sage: J = HyperellipticCurve(x^5 - 8*x).jacobian() + sage: phi = End(J).identity() + sage: (phi + phi).summands() + (Scheme endomorphism of Jacobian of Hyperelliptic Curve over Rational Field defined by y^2 = x^5 - 8*x + Defn: Identity map, + Scheme endomorphism of Jacobian of Hyperelliptic Curve over Rational Field defined by y^2 = x^5 - 8*x + Defn: Identity map) + sage: _ == (phi, phi) + True """ return self._phis @@ -839,7 +862,16 @@ def summands(self): # How to do it non-stupidly? def _richcmp_(self, other, op): r""" - Help. + Compare two scheme morphisms. + + INPUT: + + - ``other`` -- anything. To compare against the scheme + morphism ``self``. + + OUTPUT: + + A boolean or ``NotImplemented``. EXAMPLES:: From 306ddf5dae01643d2848aff4c2a1531f49043fbc Mon Sep 17 00:00:00 2001 From: Gareth Ma Date: Sun, 31 Mar 2024 16:59:59 +0100 Subject: [PATCH 08/19] fix doctest --- src/sage/structure/parent.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sage/structure/parent.pyx b/src/sage/structure/parent.pyx index 85578b26163..5a71cc22b31 100644 --- a/src/sage/structure/parent.pyx +++ b/src/sage/structure/parent.pyx @@ -1467,7 +1467,7 @@ cdef class Parent(sage.structure.category_object.CategoryObject): This example illustrates the optional third argument:: sage: QQ.End(Sets()) - Set of Morphisms from Rational Field to Integer Ring in Category of sets + Set of Morphisms from Rational Field to Rational Field in Category of sets """ from sage.categories.homset import End return End(self, category) From 6bfcc86399ac008ae44b2982bcb0d91d3a23a408 Mon Sep 17 00:00:00 2001 From: Gareth Ma Date: Sun, 31 Mar 2024 19:48:29 +0100 Subject: [PATCH 09/19] apply review changes (doctest + use categories) --- src/sage/matrix/action.pyx | 22 +++++++------------ src/sage/rings/ring_extension.pyx | 1 + src/sage/schemes/generic/morphism.py | 10 +++++++-- .../schemes/jacobians/abstract_jacobian.py | 8 ++++++- src/sage/structure/parent.pyx | 2 +- 5 files changed, 25 insertions(+), 18 deletions(-) diff --git a/src/sage/matrix/action.pyx b/src/sage/matrix/action.pyx index 4bb1f4bbe2a..77e355e295a 100644 --- a/src/sage/matrix/action.pyx +++ b/src/sage/matrix/action.pyx @@ -393,10 +393,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) @@ -412,9 +411,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 """ @@ -464,10 +461,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) @@ -485,9 +481,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 """ diff --git a/src/sage/rings/ring_extension.pyx b/src/sage/rings/ring_extension.pyx index d412ab47e27..9243e302ce6 100644 --- a/src/sage/rings/ring_extension.pyx +++ b/src/sage/rings/ring_extension.pyx @@ -669,6 +669,7 @@ cdef class RingExtension_generic(CommutativeRing): sage: dir(K) # needs sage.rings.number_field ['CartesianProduct', 'Element', + 'End', 'Hom', ... 'zeta', diff --git a/src/sage/schemes/generic/morphism.py b/src/sage/schemes/generic/morphism.py index 28a57951340..f431af3f300 100644 --- a/src/sage/schemes/generic/morphism.py +++ b/src/sage/schemes/generic/morphism.py @@ -363,6 +363,12 @@ def _add_(self, other): Defn: Identity map, Scheme endomorphism of Jacobian of Hyperelliptic Curve over Rational Field defined by y^2 = x^5 + x + 1 Defn: Identity map) """ + from sage.categories.additive_magmas import AdditiveMagmas + if self not in AdditiveMagmas(): + raise TypeError(f"{self} is not an additive magma") + if other not in AdditiveMagmas(): + raise TypeError(f"{other} is not an additive magma") + phis = [] if isinstance(self, SchemeMorphism_sum): phis.extend(self.summands()) @@ -871,7 +877,7 @@ def _richcmp_(self, other, op): OUTPUT: - A boolean or ``NotImplemented``. + A boolean or ``NotImplemented`` EXAMPLES:: @@ -2411,7 +2417,7 @@ def specialization(self, D=None, phi=None, ambient=None): def _add_(self, point): r""" - Add two point schemes. + Add two scheme points. EXAMPLES:: diff --git a/src/sage/schemes/jacobians/abstract_jacobian.py b/src/sage/schemes/jacobians/abstract_jacobian.py index 9ab2ef283ae..0a8a4f78a8e 100644 --- a/src/sage/schemes/jacobians/abstract_jacobian.py +++ b/src/sage/schemes/jacobians/abstract_jacobian.py @@ -127,8 +127,14 @@ def __init__(self, C): raise TypeError("C (=%s) must be defined over a field." % C) if C.dimension() != 1: raise ValueError("C (=%s) must have dimension 1." % C) + # Jacobian of curves defined over a field are abelian varities + from sage.categories.schemes import AbelianVarieties self.__curve = C - Scheme.__init__(self, C.base_scheme()) + + category = None + if C.is_smooth(): + category = AbelianVarieties(C.base_ring()) + Scheme.__init__(self, C.base_scheme(), category=category) def __richcmp__(self, J, op): """ diff --git a/src/sage/structure/parent.pyx b/src/sage/structure/parent.pyx index 5a71cc22b31..15afa39820a 100644 --- a/src/sage/structure/parent.pyx +++ b/src/sage/structure/parent.pyx @@ -1458,7 +1458,7 @@ cdef class Parent(sage.structure.category_object.CategoryObject): sage: R. = PolynomialRing(QQ, 2) sage: R.End() - Set of Homomorphisms from Multivariate Polynomial Ring in x, y over Rational Field to Rational Field + Set of Homomorphisms from Multivariate Polynomial Ring in x, y over Rational Field to Multivariate Polynomial Ring in x, y over Rational Field sage: R.End() is End(R) True sage: R.End() is R.Hom(R) From 031aedfc6bdb9fa8de99ed73555734323e76cf9b Mon Sep 17 00:00:00 2001 From: Gareth Ma Date: Sun, 31 Mar 2024 21:31:21 +0100 Subject: [PATCH 10/19] patch TestSuite (since abstract class doesn't implement element methods) --- src/sage/schemes/curves/projective_curve.py | 31 +++++++++++++++++++ .../schemes/jacobians/abstract_jacobian.py | 13 ++++---- 2 files changed, 37 insertions(+), 7 deletions(-) diff --git a/src/sage/schemes/curves/projective_curve.py b/src/sage/schemes/curves/projective_curve.py index c12756ac2fe..720a071352c 100644 --- a/src/sage/schemes/curves/projective_curve.py +++ b/src/sage/schemes/curves/projective_curve.py @@ -220,6 +220,37 @@ def __init__(self, A, X, category=None): Curve_generic.__init__(self, A, X, category=category) + def _an_element_(self): + r""" + Return an element of this projective curve. We try to find variables + that never appear as a pure monomial, and fail otherwise. + + EXAMPLES:: + + sage: P. = ProjectiveSpace(QQ, 2) + sage: C = Curve(x*y^2*z^7 - x^10 - x^2*z^8) + sage: C.an_element() # random + (0 : 0 : 1 : 0) + sage: C.an_element() in C + True + """ + gens = self.ambient_space().gens() + variables = set(gens) + for poly in self.defining_polynomials(): + for m in poly.monomials(): + mvs = m.variables() + if len(mvs) == 1 and mvs[0] in variables: + variables.remove(mvs[0]) + if len(variables) == 0: + return NotImplemented + + # Set this to 1 and others to 0 + ring = self.base_ring() + idx = gens.index(list(variables)[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. diff --git a/src/sage/schemes/jacobians/abstract_jacobian.py b/src/sage/schemes/jacobians/abstract_jacobian.py index 0a8a4f78a8e..864f4b17487 100644 --- a/src/sage/schemes/jacobians/abstract_jacobian.py +++ b/src/sage/schemes/jacobians/abstract_jacobian.py @@ -91,13 +91,12 @@ def __init__(self, C): Note: this is an abstract parent, so we skip element tests:: - sage: TestSuite(J).run(skip =["_test_an_element",\ - "_test_elements",\ - "_test_elements_eq_reflexive",\ - "_test_elements_eq_symmetric",\ - "_test_elements_eq_transitive",\ - "_test_elements_neq",\ - "_test_some_elements"]) + sage: TestSuite(J).run(skip=[ + ....: "_test_additive_associativity", "_test_an_element", + ....: "_test_elements", "_test_elements_eq_reflexive", + ....: "_test_elements_eq_symmetric", "_test_elements_eq_transitive", + ....: "_test_elements_neq", "_test_some_elements", "_test_zero" + ....: ]) :: From f98946e19adfb085274b71d23cdd6ff3eb739d14 Mon Sep 17 00:00:00 2001 From: Gareth Ma Date: Mon, 1 Apr 2024 01:58:46 +0100 Subject: [PATCH 11/19] move elliptic curve tests --- src/sage/schemes/curves/projective_curve.py | 7 +++++-- src/sage/schemes/generic/morphism.py | 22 +++++++++++++++++++++ src/sage/structure/parent.pyx | 3 ++- 3 files changed, 29 insertions(+), 3 deletions(-) diff --git a/src/sage/schemes/curves/projective_curve.py b/src/sage/schemes/curves/projective_curve.py index 720a071352c..c307ebcd39b 100644 --- a/src/sage/schemes/curves/projective_curve.py +++ b/src/sage/schemes/curves/projective_curve.py @@ -222,8 +222,11 @@ def __init__(self, A, X, category=None): def _an_element_(self): r""" - Return an element of this projective curve. We try to find variables - that never appear as a pure monomial, and fail otherwise. + Return an element of this projective curve. + + ALGORITHM: + + We try to find variables that never appear as a pure monomial, and fail otherwise. EXAMPLES:: diff --git a/src/sage/schemes/generic/morphism.py b/src/sage/schemes/generic/morphism.py index f431af3f300..30365f6da2b 100644 --- a/src/sage/schemes/generic/morphism.py +++ b/src/sage/schemes/generic/morphism.py @@ -363,6 +363,7 @@ def _add_(self, other): Defn: Identity map, Scheme endomorphism of Jacobian of Hyperelliptic Curve over Rational Field defined by y^2 = x^5 + x + 1 Defn: Identity map) """ + # PR_TODO: Move this to category level from sage.categories.additive_magmas import AdditiveMagmas if self not in AdditiveMagmas(): raise TypeError(f"{self} is not an additive magma") @@ -820,6 +821,16 @@ def _call_(self, P): sage: P = J(2, 4) sage: (phi + phi)(P) == P * 2 True + + :: + + sage: E = EllipticCurve(GF(101), [5,5]) + sage: phi = E.isogenies_prime_degree(7)[0] + sage: P = E.lift_x(0) + sage: (phi + phi)(P) + (72 : 56 : 1) + sage: (phi - phi)(P) + (0 : 1 : 0) """ return sum((phi(P) for phi in self._phis), self._codomain.zero()) @@ -861,6 +872,17 @@ def summands(self): Defn: Identity map) sage: _ == (phi, phi) True + + :: + + sage: E = EllipticCurve(j=5) + sage: m2 = E.scalar_multiplication(2) + sage: m3 = E.scalar_multiplication(3) + sage: m2 + m3 + Sum morphism: + From: Elliptic Curve defined by y^2 + x*y = x^3 + x^2 + 180*x + 17255 over Rational Field + To: Elliptic Curve defined by y^2 + x*y = x^3 + x^2 + 180*x + 17255 over Rational Field + Via: (Scalar-multiplication endomorphism [2] of Elliptic Curve defined by y^2 + x*y = x^3 + x^2 + 180*x + 17255 over Rational Field, Scalar-multiplication endomorphism [3] of Elliptic Curve defined by y^2 + x*y = x^3 + x^2 + 180*x + 17255 over Rational Field) """ return self._phis diff --git a/src/sage/structure/parent.pyx b/src/sage/structure/parent.pyx index 15afa39820a..114a4415b65 100644 --- a/src/sage/structure/parent.pyx +++ b/src/sage/structure/parent.pyx @@ -1458,7 +1458,8 @@ cdef class Parent(sage.structure.category_object.CategoryObject): sage: R. = PolynomialRing(QQ, 2) sage: R.End() - Set of Homomorphisms from Multivariate Polynomial Ring in x, y over Rational Field to Multivariate Polynomial Ring in x, y over Rational Field + Set of Homomorphisms from Multivariate Polynomial Ring in x, y over + Rational Field to Multivariate Polynomial Ring in x, y over Rational Field sage: R.End() is End(R) True sage: R.End() is R.Hom(R) From d67fbb362f71b297cc71073e03826d3745ae7fb3 Mon Sep 17 00:00:00 2001 From: Gareth Ma Date: Mon, 1 Apr 2024 02:01:33 +0100 Subject: [PATCH 12/19] add hash methods --- src/sage/schemes/affine/affine_morphism.py | 13 +++++++ src/sage/schemes/generic/morphism.py | 42 ++++++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/src/sage/schemes/affine/affine_morphism.py b/src/sage/schemes/affine/affine_morphism.py index e55f75b4e18..d3b85b72b7e 100644 --- a/src/sage/schemes/affine/affine_morphism.py +++ b/src/sage/schemes/affine/affine_morphism.py @@ -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. = 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. diff --git a/src/sage/schemes/generic/morphism.py b/src/sage/schemes/generic/morphism.py index 30365f6da2b..50feb858147 100644 --- a/src/sage/schemes/generic/morphism.py +++ b/src/sage/schemes/generic/morphism.py @@ -851,6 +851,7 @@ def _repr_(self): Defn: Identity map, Scheme endomorphism of Jacobian of Hyperelliptic Curve over Rational Field defined by y^2 = x^5 - 8*x Defn: Identity map) """ + # PR_TODO: Remove the "Via:" part? return f'Sum morphism:' \ f'\n From: {self._domain}' \ f'\n To: {self._codomain}' \ @@ -926,6 +927,22 @@ def _richcmp_(self, other, op): return self._phis == other._phis + def __hash__(self): + """ + Return a hash for this sum of scheme morhpisms. + + EXAMPLES:: + + sage: R. = QQ[] + sage: J = HyperellipticCurve(x^5 - 8*x).jacobian() + sage: phi = End(J).identity() + sage: psi = phi + phi + sage: hash(phi) == hash((phi.__class__, J, J, (phi, phi))) + True + """ + return hash((self.__class__, self.codomain(), self.domain(), + tuple(self._phis))) + class SchemeMorphism_id(SchemeMorphism): """ @@ -1003,6 +1020,18 @@ def _call_(self, P): """ return P + def __hash__(self): + """ + Return a hash for self. + + EXAMPLES:: + + sage: phi = Spec(QQ).End().identity() + sage: hash(phi) == hash((phi.__class__, Spec(QQ))) + True + """ + return hash((self.__class__, self.domain())) + class SchemeMorphism_structure_map(SchemeMorphism): r""" @@ -1310,6 +1339,19 @@ def __init__(self, parent, polys, check=True): SchemeMorphism.__init__(self, parent) + def __hash__(self): + """ + Return a hash for self. + + EXAMPLES:: + + sage: A. = AffineSpace(2, QQ) + sage: phi = A.hom([2*x, 2*y], A) + sage: hash(phi) == hash(phi.__class__, A, A, (2*x, 2*y)) + True + """ + return hash((self.__class__, self.domain(), self.codomain(), self._polys)) + def __eq__(self, other): """ Check equality of ``self`` and ``other``. From 85a914971dc05cada837b2245ec3345a0796b3fb Mon Sep 17 00:00:00 2001 From: Gareth Ma Date: Mon, 1 Apr 2024 03:26:06 +0100 Subject: [PATCH 13/19] fix hash doctests --- src/sage/schemes/generic/morphism.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/sage/schemes/generic/morphism.py b/src/sage/schemes/generic/morphism.py index 50feb858147..38641370148 100644 --- a/src/sage/schemes/generic/morphism.py +++ b/src/sage/schemes/generic/morphism.py @@ -380,7 +380,7 @@ def _add_(self, other): else: phis.append(other) - #TODO should probably try to simplify some more? + # TODO should probably try to simplify some more? assert other.domain() == self.domain() and other.codomain() == self.codomain() return SchemeMorphism_sum(phis, domain=self.domain(), codomain=self.codomain()) @@ -937,7 +937,7 @@ def __hash__(self): sage: J = HyperellipticCurve(x^5 - 8*x).jacobian() sage: phi = End(J).identity() sage: psi = phi + phi - sage: hash(phi) == hash((phi.__class__, J, J, (phi, phi))) + sage: hash(psi) == hash((psi.__class__, J, J, (phi, phi))) True """ return hash((self.__class__, self.codomain(), self.domain(), @@ -1347,7 +1347,7 @@ def __hash__(self): sage: A. = AffineSpace(2, QQ) sage: phi = A.hom([2*x, 2*y], A) - sage: hash(phi) == hash(phi.__class__, A, A, (2*x, 2*y)) + sage: hash(phi) == hash((phi.__class__, A, A, (2*x, 2*y))) True """ return hash((self.__class__, self.domain(), self.codomain(), self._polys)) From 18d7910cb42c99db84a27a5eff00dd27564dea5b Mon Sep 17 00:00:00 2001 From: Gareth Ma Date: Tue, 2 Apr 2024 03:09:02 +0100 Subject: [PATCH 14/19] use categories to check for addition --- src/sage/schemes/generic/morphism.py | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/sage/schemes/generic/morphism.py b/src/sage/schemes/generic/morphism.py index 38641370148..26ba066635a 100644 --- a/src/sage/schemes/generic/morphism.py +++ b/src/sage/schemes/generic/morphism.py @@ -78,17 +78,18 @@ import operator -from sage.structure.element import Element, parent, coercion_model from sage.arith.power import generic_power +from sage.structure.element import Element, parent, coercion_model from sage.structure.richcmp import richcmp from sage.structure.sequence import Sequence +from sage.categories.additive_magmas import AdditiveMagmas from sage.categories.homset import Homset, Hom, End +from sage.categories.map import FormalCompositeMap, Map +from sage.categories.morphism import SetMorphism from sage.rings.fraction_field_element import FractionFieldElement from sage.rings.fraction_field import is_FractionField -from sage.categories.map import FormalCompositeMap, Map from sage.misc.constant_function import ConstantFunction from sage.misc.lazy_attribute import lazy_attribute -from sage.categories.morphism import SetMorphism from sage.schemes.generic.algebraic_scheme import AlgebraicScheme_subscheme @@ -363,13 +364,17 @@ def _add_(self, other): Defn: Identity map, Scheme endomorphism of Jacobian of Hyperelliptic Curve over Rational Field defined by y^2 = x^5 + x + 1 Defn: Identity map) """ - # PR_TODO: Move this to category level + # TODO: Move this to category level from sage.categories.additive_magmas import AdditiveMagmas if self not in AdditiveMagmas(): raise TypeError(f"{self} is not an additive magma") if other not in AdditiveMagmas(): raise TypeError(f"{other} is not an additive magma") + # TODO: should probably try to simplify some more? + if other.domain() != self.domain() and other.codomain() != self.codomain(): + raise TypeError(f"{self} and {other} must have the same domains and codomains") + phis = [] if isinstance(self, SchemeMorphism_sum): phis.extend(self.summands()) @@ -380,8 +385,6 @@ def _add_(self, other): else: phis.append(other) - # TODO should probably try to simplify some more? - assert other.domain() == self.domain() and other.codomain() == self.codomain() return SchemeMorphism_sum(phis, domain=self.domain(), codomain=self.codomain()) def __mul__(self, right): @@ -793,12 +796,10 @@ def __init__(self, phis, domain=None, codomain=None, check=True): domain = phis[0].domain() if codomain is None: codomain = phis[0].codomain() - if check: - try: - x = codomain.an_element() - _ = x + x - except (TypeError, NotImplementedError): - raise ValueError(f"addition is not implemented for {codomain}") + if check and codomain not in AdditiveMagmas(): + # If you see this message but it seems wrong, you should initialize codomain + # within the AdditiveMagma category. + raise ValueError(f"addition is not implemented for {codomain}") for phi in phis: if phi.domain() != domain: raise ValueError(f'summand {phi} has incorrect domain (need {domain})') @@ -940,8 +941,7 @@ def __hash__(self): sage: hash(psi) == hash((psi.__class__, J, J, (phi, phi))) True """ - return hash((self.__class__, self.codomain(), self.domain(), - tuple(self._phis))) + return hash((self.__class__, self.codomain(), self.domain(), self._phis)) class SchemeMorphism_id(SchemeMorphism): From a0b0e23e8d42a5483b8ee3b42bdf236181122535 Mon Sep 17 00:00:00 2001 From: Gareth Ma Date: Tue, 2 Apr 2024 03:21:10 +0100 Subject: [PATCH 15/19] remove incorrect inheritance --- src/sage/schemes/elliptic_curves/hom_sum.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/sage/schemes/elliptic_curves/hom_sum.py b/src/sage/schemes/elliptic_curves/hom_sum.py index 3831513a782..a1bcbe0bf1e 100644 --- a/src/sage/schemes/elliptic_curves/hom_sum.py +++ b/src/sage/schemes/elliptic_curves/hom_sum.py @@ -59,7 +59,7 @@ from sage.schemes.elliptic_curves.hom import EllipticCurveHom, compare_via_evaluation -class EllipticCurveHom_sum(EllipticCurveHom, SchemeMorphism_sum): +class EllipticCurveHom_sum(EllipticCurveHom): _degree = None @@ -68,6 +68,14 @@ def __init__(self, phis, domain=None, codomain=None): 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 From 641613f742a949635271d9fc66742787eb5ad723 Mon Sep 17 00:00:00 2001 From: Gareth Ma Date: Tue, 2 Apr 2024 06:11:23 +0100 Subject: [PATCH 16/19] add back methods I removed --- src/sage/schemes/elliptic_curves/hom_sum.py | 35 ++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/src/sage/schemes/elliptic_curves/hom_sum.py b/src/sage/schemes/elliptic_curves/hom_sum.py index a1bcbe0bf1e..23c62f0a9dc 100644 --- a/src/sage/schemes/elliptic_curves/hom_sum.py +++ b/src/sage/schemes/elliptic_curves/hom_sum.py @@ -43,7 +43,6 @@ """ from sage.misc.cachefunc import cached_method -from sage.schemes.generic.morphism import SchemeMorphism_sum from sage.structure.sequence import Sequence from sage.arith.misc import gcd @@ -61,6 +60,7 @@ class EllipticCurveHom_sum(EllipticCurveHom): + _phis = None _degree = None def __init__(self, phis, domain=None, codomain=None): @@ -128,6 +128,22 @@ def __init__(self, phis, domain=None, codomain=None): EllipticCurveHom.__init__(self, self._domain, self._codomain) self._degree = None + def _call_(self, P): + r""" + Evaluate this sum morphism at a point. + + EXAMPLES:: + + sage: E = EllipticCurve(GF(101), [5,5]) + sage: phi = E.isogenies_prime_degree(7)[0] + sage: P = E.lift_x(0) + sage: (phi + phi)(P) + (72 : 56 : 1) + sage: (phi - phi)(P) + (0 : 1 : 0) + """ + return sum((phi(P) for phi in self._phis), self._codomain(0)) + def _eval(self, P): r""" Less strict evaluation method for internal use. @@ -173,6 +189,23 @@ def _repr_(self): f'\n To: {self._codomain}' \ f'\n Via: {self._phis}' + def summands(self): + r""" + Return the individual summands making up this sum morphism. + + EXAMPLES:: + + sage: E = EllipticCurve(j=5) + sage: m2 = E.scalar_multiplication(2) + sage: m3 = E.scalar_multiplication(3) + sage: m2 + m3 + Sum morphism: + From: Elliptic Curve defined by y^2 + x*y = x^3 + x^2 + 180*x + 17255 over Rational Field + To: Elliptic Curve defined by y^2 + x*y = x^3 + x^2 + 180*x + 17255 over Rational Field + Via: (Scalar-multiplication endomorphism [2] of Elliptic Curve defined by y^2 + x*y = x^3 + x^2 + 180*x + 17255 over Rational Field, Scalar-multiplication endomorphism [3] of Elliptic Curve defined by y^2 + x*y = x^3 + x^2 + 180*x + 17255 over Rational Field) + """ + return self._phis + @cached_method def to_isogeny_chain(self): r""" From 43396bab3f9c12c227fb2a1742125f09aa08a52e Mon Sep 17 00:00:00 2001 From: Gareth Ma Date: Tue, 2 Apr 2024 06:21:28 +0100 Subject: [PATCH 17/19] fix unhashable .an_element() for projective curves --- src/sage/schemes/curves/projective_curve.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/sage/schemes/curves/projective_curve.py b/src/sage/schemes/curves/projective_curve.py index c307ebcd39b..c3f596ff7b7 100644 --- a/src/sage/schemes/curves/projective_curve.py +++ b/src/sage/schemes/curves/projective_curve.py @@ -232,24 +232,25 @@ def _an_element_(self): sage: P. = ProjectiveSpace(QQ, 2) sage: C = Curve(x*y^2*z^7 - x^10 - x^2*z^8) - sage: C.an_element() # random - (0 : 0 : 1 : 0) + sage: C.an_element() + (0 : 1 : 0) sage: C.an_element() in C True """ - gens = self.ambient_space().gens() - variables = set(gens) + # 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 and mvs[0] in variables: - variables.remove(mvs[0]) - if len(variables) == 0: + if len(mvs) == 1: + counts[gens.index(mvs[0])] += 1 + if min(counts) > 0: return NotImplemented # Set this to 1 and others to 0 ring = self.base_ring() - idx = gens.index(list(variables)[0]) + idx = counts.index(0) coordinate = [ring.zero()] * len(gens) coordinate[idx] = ring.one() return self(coordinate) From dd22a16f736bbea36b85bcc19bbfc5abd975d9aa Mon Sep 17 00:00:00 2001 From: Gareth Ma Date: Tue, 9 Apr 2024 17:06:16 +0100 Subject: [PATCH 18/19] wrap doctests --- src/sage/schemes/generic/homset.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/sage/schemes/generic/homset.py b/src/sage/schemes/generic/homset.py index 81b080cf71e..af8d6b709c3 100644 --- a/src/sage/schemes/generic/homset.py +++ b/src/sage/schemes/generic/homset.py @@ -445,7 +445,8 @@ def _element_constructor_(self, x, check=True): sage: A. = AffineSpace(R) sage: C = A.subscheme(x*y - 1) sage: H = C.Hom(C); H - Set of scheme endomorphisms of Closed subscheme of Affine Space of dimension 2 over Rational Field defined by: + Set of scheme endomorphisms of Closed subscheme of Affine Space of + dimension 2 over Rational Field defined by: x*y - 1 sage: H(1) Traceback (most recent call last): From 95e093077c0bc1b74f7b3f01fb06628aafc1dcab Mon Sep 17 00:00:00 2001 From: Gareth Ma Date: Wed, 10 Apr 2024 10:37:06 +0100 Subject: [PATCH 19/19] review changes --- src/sage/schemes/generic/homset.py | 2 +- src/sage/schemes/generic/morphism.py | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/sage/schemes/generic/homset.py b/src/sage/schemes/generic/homset.py index af8d6b709c3..d3030b4d126 100644 --- a/src/sage/schemes/generic/homset.py +++ b/src/sage/schemes/generic/homset.py @@ -644,7 +644,7 @@ def _coerce_map_from_(self, other): except AttributeError: # no .ambient_space return False elif isinstance(other, SchemeHomset_points): - #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 diff --git a/src/sage/schemes/generic/morphism.py b/src/sage/schemes/generic/morphism.py index 26ba066635a..269883d234e 100644 --- a/src/sage/schemes/generic/morphism.py +++ b/src/sage/schemes/generic/morphism.py @@ -730,8 +730,9 @@ class SchemeMorphism_sum(SchemeMorphism): From: Jacobian of Hyperelliptic Curve over Rational Field defined by y^2 = x^5 - 8*x To: Jacobian of Hyperelliptic Curve over Rational Field defined by y^2 = x^5 - 8*x Via: (Scheme endomorphism of Jacobian of Hyperelliptic Curve over Rational Field defined by y^2 = x^5 - 8*x - Defn: Identity map, Scheme endomorphism of Jacobian of Hyperelliptic Curve over Rational Field defined by y^2 = x^5 - 8*x - Defn: Identity map) + Defn: Identity map, + Scheme endomorphism of Jacobian of Hyperelliptic Curve over Rational Field defined by y^2 = x^5 - 8*x + Defn: Identity map) """ _phis = None