From 34dd9acdad986d56542c302fcbc829b9a71b4a62 Mon Sep 17 00:00:00 2001 From: Sabrina Kunzweiler Date: Thu, 9 Jan 2025 15:40:48 +0100 Subject: [PATCH] fix and add some docstrings --- .../hyperelliptic_constructor.py | 89 +------ .../hyperelliptic_g2.py | 88 +++++++ .../hyperelliptic_generic.py | 137 +++++++++- .../jacobian_generic.py | 246 +++++++----------- .../jacobian_homset_generic.py | 80 +++++- .../jacobian_homset_split.py | 70 ++++- .../jacobian_morphism.py | 19 ++ 7 files changed, 487 insertions(+), 242 deletions(-) diff --git a/src/sage/schemes/hyperelliptic_curves_smooth_model/hyperelliptic_constructor.py b/src/sage/schemes/hyperelliptic_curves_smooth_model/hyperelliptic_constructor.py index 7b2cdc9de7f..c38e343c140 100644 --- a/src/sage/schemes/hyperelliptic_curves_smooth_model/hyperelliptic_constructor.py +++ b/src/sage/schemes/hyperelliptic_curves_smooth_model/hyperelliptic_constructor.py @@ -1,82 +1,6 @@ r""" - Constructor for hyperelliptic curves using the smooth model - - In Sage, a hyperelliptic curve of genus `g` is always - specified by an (affine) equation in Weierstrass form - - .. MATH:: - - y^2 + h(x) y = f(x), - - for some polynomials `h` and `f`. This defines a smooth - model in weighted projective space `\PP(1 : g + 1 : 1)` - - .. MATH:: - Y^2 + H(X,Z) Y = F(X,Z), - - where `H` is the degree `g + 1` homogenization of `h`, - and `F` is the degree `2 g + 2` homogenization of `f`. - - There are either 0, 1 or 2 points at infinity (`Z=0`), - in which case we say that the hyperelliptic curve is - inert, ramified or split, respectively. - - - EXAMPLES: - - We create a hyperelliptic curve over the rationals:: - - sage: R. = PolynomialRing(QQ) - sage: H = HyperellipticCurveSmoothModel(x^8+1, x^4+1); H - Hyperelliptic Curve over Rational Field defined by y^2 + (x^4 + 1)*y = x^8 + 1 - - This hyperelliptic curve has no points at infinity, i.e. `H` is inert:: - sage: H.points_at_infinity() - [] - sage: H.is_inert() - True - - We can extend the base field to obtain a hyperelliptic curve with two points at infinity:: - sage: K. = QQ.extension(x^2+x-1) - sage: HK = H.change_ring(K) - sage: HK.points_at_infinity() - [(1 : alpha : 0), (1 : -alpha - 1 : 0)] - sage: HK.is_split() - True - - The construction of hyperelliptic curves is supported over different fields. The correct class is chosen automatically:: - sage: F = FiniteField(13) - sage: S. = PolynomialRing(F) - sage: HF = HyperellipticCurve(x^5 + x^4 + x^3 + x^2 + x + 1, x^3 + x); HF - Hyperelliptic Curve over Finite Field of size 13 defined by y^2 + (x^3 + x)*y = x^5 + x^4 + x^3 + x^2 + x + 1 - sage: type(HF) - - sage: Q5 = Qp(5,10) - sage: T. = Q5[] - sage: H5 = HyperellipticCurveSmoothModel(x^7 + 1); H5 - Hyperelliptic Curve over 5-adic Field with capped relative precision 10 defined by y^2 = x^7 + 1 + O(5^10) - sage: type(H5) - - - The input polynomials need not be monic:: - sage: R. = QQ[] - sage: HyperellipticCurveSmoothModel(3*x^5+1) - Hyperelliptic Curve over Rational Field defined by y^2 = 3*x^5 + 1 - - The polynomials f and h need to define a smooth curve of genus at least one. In particular polynomials defining elliptic curves are allowed as input. - sage: E = HyperellipticCurveSmoothModel(x^3+1) - sage: E.genus() - 1 - sage: HyperellipticCurveSmoothModel(x) - Traceback (most recent call last): - ... - ValueError: arguments f = x and h = 0 must define a curve of genus at least one. - - The following polynomials define a singular curve and are not allowed as input:: - sage: C = HyperellipticCurve(x^6 + 2*x - 1, 2*x - 2) - Traceback (most recent call last): - ... - ValueError: not a hyperelliptic curve: singularity in the provided affine patch +Constructor for hyperelliptic curves using the smooth model +in weighted projective space `\PP(1 : g + 1 : 1)`. Adapted from /hyperelliptic/constructor.py @@ -182,10 +106,10 @@ def HyperellipticCurveSmoothModel(f, h=0, check_squarefree=True): The construction of hyperelliptic curves is supported over different fields. The correct class is chosen automatically:: sage: F = FiniteField(13) sage: S. = PolynomialRing(F) - sage: HF = HyperellipticCurve(x^5 + x^4 + x^3 + x^2 + x + 1, x^3 + x); HF + sage: HF = HyperellipticCurveSmoothModel(x^5 + x^4 + x^3 + x^2 + x + 1, x^3 + x); HF Hyperelliptic Curve over Finite Field of size 13 defined by y^2 + (x^3 + x)*y = x^5 + x^4 + x^3 + x^2 + x + 1 sage: type(HF) - + sage: Q5 = Qp(5,10) sage: T. = Q5[] sage: H5 = HyperellipticCurveSmoothModel(x^7 + 1); H5 @@ -213,10 +137,11 @@ def HyperellipticCurveSmoothModel(f, h=0, check_squarefree=True): The following polynomials define a singular curve and are not allowed as input:: - sage: C = HyperellipticCurve(x^6 + 2*x - 1, 2*x - 2) + sage: C = HyperellipticCurveSmoothModel(x^6 + 2*x - 1, 2*x - 2) Traceback (most recent call last): ... - ValueError: not a hyperelliptic curve: singularity in the provided affine patch + ValueError: singularity in the provided affine patch + """ # --------------------------- diff --git a/src/sage/schemes/hyperelliptic_curves_smooth_model/hyperelliptic_g2.py b/src/sage/schemes/hyperelliptic_curves_smooth_model/hyperelliptic_g2.py index eecd79b58f5..0af34ca3268 100644 --- a/src/sage/schemes/hyperelliptic_curves_smooth_model/hyperelliptic_g2.py +++ b/src/sage/schemes/hyperelliptic_curves_smooth_model/hyperelliptic_g2.py @@ -50,6 +50,94 @@ def is_odd_degree(self): @cached_method def jacobian(self): + r""" + Returns the Jacobian of the hyperelliptic curve. + + Elements of the Jacobian are represented by tuples + of the form `(u, v : n)`, where + - (u,v) is the Mumford representative of a divisor `P_1 + ... + P_r`, + - n is a non-negative integer + + This tuple represents the equivalence class + + ..MATH:: + + [P_1 + ... + P_r + n \cdot \infty_+ + m\cdot \infty_- - D_\infty], + + where `m = g - \deg(u) - n`, and `\infty_+`, \infty_-` are the + points at infinity of the hyperelliptic curve, + + ..MATH:: + D_\infty = + \lceil g/2 \rceil \infty_+ + \lfloor g/2 \rfloor \infty_-. + + Here, `\infty_- = \infty_+`, if the hyperelliptic curve is ramified. + + + EXAMPLES:: + + We construct the Jacobian of a hyperelliptic curve with affine equation + `y^2 + (x^3 + x + 1) y = 2*x^5 + 4*x^4 + x^3 - x` over the rationals. + This curve has two points at infinity:: + + sage: R. = QQ[] + sage: H = HyperellipticCurveSmoothModel(2*x^5 + 4*x^4 + x^3 - x, x^3 + x + 1) + sage: J = Jacobian(H); J + Jacobian of Hyperelliptic Curve over Rational Field defined by y^2 + (x^3 + x + 1)*y = 2*x^5 + 4*x^4 + x^3 - x + + The points `P = (0, 0)` and `Q = (-1, -1)` are on `H`. We construct the + element `D_1 = [P - Q] = [P + (-Q) - D_\infty`] on the Jacobian:: + + sage: P = H.point([0, 0]) + sage: Q = H.point([-1, -1]) + sage: D1 = J(P,Q); D1 + (x^2 + x, -2*x : 0) + + Elements of the Jacobian can also be constructed by directly providing + the Mumford representation:: + + sage: D1 == J(x^2 + x, -2*x, 0) + True + + We can also embed single points into the Jacobian. Below we construct + `D_2 = [P - P_0]`, where `P_0` is the distinguished point of `H` + (by default one of the points at infinity):: + + sage: D2 = J(P); D2 + (x, 0 : 0) + sage: P0 = H.distinguished_point(); P0 + (1 : 0 : 0) + sage: D2 == J(P, P0) + True + + We may add elements, or multiply by integers:: + + sage: 2*D1 + (x, -1 : 1) + sage: D1 + D2 + (x^2 + x, -1 : 0) + sage: -D2 + (x, -1 : 1) + + Note that the neutral element is given by `[D_\infty - D_\infty]`, + in particular `n = 1`:: + + sage: J.zero() + (1, 0 : 1) + + There are two more elements of the Jacobian that are only supported + at infinity: `[\infty_+ - \infty_-]` and `[\infty_- - \infty_+]`:: + + sage: [P_plus, P_minus] = H.points_at_infinity() + sage: P_plus == P0 + True + sage: J(P_plus,P_minus) + (1, 0 : 2) + sage: J(P_minus, P_plus) + (1, 0 : 0) + """ + + from sage.schemes.hyperelliptic_curves_smooth_model.jacobian_g2_generic import ( HyperellipticJacobian_g2_generic, ) diff --git a/src/sage/schemes/hyperelliptic_curves_smooth_model/hyperelliptic_generic.py b/src/sage/schemes/hyperelliptic_curves_smooth_model/hyperelliptic_generic.py index 83f92514965..d0ca86d6c99 100644 --- a/src/sage/schemes/hyperelliptic_curves_smooth_model/hyperelliptic_generic.py +++ b/src/sage/schemes/hyperelliptic_curves_smooth_model/hyperelliptic_generic.py @@ -110,7 +110,7 @@ def change_ring(self, R): the base ring to the residue field:: sage: R. = PolynomialRing(QQ); - sage: H = HyperellipticCurve(R([0, -1, 2, 0, -2]), R([0, 1, 0, 1])); #LMFDB label: 763.a.763.1 + sage: H = HyperellipticCurveSmoothModel(R([0, -1, 2, 0, -2]), R([0, 1, 0, 1])); #LMFDB label: 763.a.763.1 sage: H.change_ring(FiniteField(2)) Hyperelliptic Curve over Finite Field of size 2 defined by y^2 + (x^3 + x)*y = x sage: H.change_ring(FiniteField(3)) @@ -121,7 +121,7 @@ def change_ring(self, R): sage: H.change_ring(FiniteField(7)) Traceback (most recent call last): ... - ValueError: not a hyperelliptic curve: singularity in the provided affine patch + ValueError: singularity in the provided affine patch """ from sage.schemes.hyperelliptic_curves_smooth_model.hyperelliptic_constructor import ( HyperellipticCurveSmoothModel, @@ -781,6 +781,137 @@ def set_distinguished_point(self, P0): def jacobian(self): """ Returns the Jacobian of the hyperelliptic curve. + + Elements of the Jacobian are represented by tuples + of the form `(u, v : n)`, where + - (u,v) is the Mumford representative of a divisor `P_1 + ... + P_r`, + - n is a non-negative integer + + This tuple represents the equivalence class + + ..MATH:: + + [P_1 + ... + P_r + n \cdot \infty_+ + m\cdot \infty_- - D_\infty], + + where `m = g - \deg(u) - n`, and `\infty_+`, \infty_-` are the + points at infinity of the hyperelliptic curve, + + ..MATH:: + D_\infty = + \lceil g/2 \rceil \infty_+ + \lfloor g/2 \rfloor \infty_-. + + Here, `\infty_- = \infty_+`, if the hyperelliptic curve is ramified. + + Such a representation exists and is unique, unless the genus `g` is odd + and the curve is inert. + + If the hyperelliptic curve is ramified or inert, + then `n` can be deduced from `\deg(u)` and `g`. In these cases, + `n` is omitted in the description. + + + EXAMPLES: + + We construct the Jacobian of a hyperelliptic curve with affine equation + `y^2 + (x^3 + x + 1) y = 2*x^5 + 4*x^4 + x^3 - x` over the rationals. + This curve has two points at infinity:: + + sage: R. = QQ[] + sage: H = HyperellipticCurveSmoothModel(2*x^5 + 4*x^4 + x^3 - x, x^3 + x + 1) + sage: J = Jacobian(H); J + Jacobian of Hyperelliptic Curve over Rational Field defined by y^2 + (x^3 + x + 1)*y = 2*x^5 + 4*x^4 + x^3 - x + + The points `P = (0, 0)` and `Q = (-1, -1)` are on `H`. We construct the + element `D_1 = [P - Q] = [P + (-Q) - D_\infty`] on the Jacobian:: + + sage: P = H.point([0, 0]) + sage: Q = H.point([-1, -1]) + sage: D1 = J(P,Q); D1 + (x^2 + x, -2*x : 0) + + Elements of the Jacobian can also be constructed by directly providing + the Mumford representation:: + + sage: D1 == J(x^2 + x, -2*x, 0) + True + + We can also embed single points into the Jacobian. Below we construct + `D_2 = [P - P_0]`, where `P_0` is the distinguished point of `H` + (by default one of the points at infinity):: + + sage: D2 = J(P); D2 + (x, 0 : 0) + sage: P0 = H.distinguished_point(); P0 + (1 : 0 : 0) + sage: D2 == J(P, P0) + True + + We may add elements, or multiply by integers:: + + sage: 2*D1 + (x, -1 : 1) + sage: D1 + D2 + (x^2 + x, -1 : 0) + sage: -D2 + (x, -1 : 1) + + Note that the neutral element is given by `[D_\infty - D_\infty]`, + in particular `n = 1`:: + + sage: J.zero() + (1, 0 : 1) + + There are two more elements of the Jacobian that are only supported + at infinity: `[\infty_+ - \infty_-]` and `[\infty_- - \infty_+]`:: + + sage: [P_plus, P_minus] = H.points_at_infinity() + sage: P_plus == P0 + True + sage: J(P_plus,P_minus) + (1, 0 : 2) + sage: J(P_minus, P_plus) + (1, 0 : 0) + + Now, we consider the Jacobian of a hyperelliptic curve with only one + point at infinity, defined over a finite field:: + + sage: K = FiniteField(7) + sage: R. = K[] + sage: H = HyperellipticCurveSmoothModel(x^7 + 3*x + 2) + sage: J = Jacobian(H); J + Jacobian of Hyperelliptic Curve over Finite Field of size 7 defined by y^2 = x^7 + 3*x + 2 + + Elements on the Jacobian can be constructed as before. But the value + `n` is not used here, since there is exactly one point at infinity:: + + sage: P = H.point([3, 0]) + sage: Q = H.point([5, 1]) + sage: D1 = J(P,Q); D1 + (x^2 + 6*x + 1, 3*x + 5) + sage: D2 = J(x^3 + 3*x^2 + 4*x + 3, 2*x^2 + 4*x) + sage: D1 + D2 + (x^3 + 2, 4) + + Over finite fields, we may also construct random elements and + compute the order of the Jacobian:: + + sage: J.random_element() #random + (x^3 + x^2 + 4*x + 5, 3*x^2 + 3*x) + sage: J.order() + 344 + + Note that arithmetic on the Jacobian is not implemented if the + underlying hyperelliptic curve is inert (i.e. has no points at + infinity) and the genus is odd:: + + sage: R. = GF(13)[] + sage: H = HyperellipticCurveSmoothModel(x^8+1,x^4+1) + sage: J = Jacobian(H) + sage: J.zero() + Traceback (most recent call last): + ... + ValueError: unable to perform arithmetic for inert models of odd genus + """ from sage.schemes.hyperelliptic_curves_smooth_model.jacobian_generic import ( HyperellipticJacobian_generic, @@ -1026,7 +1157,7 @@ def has_odd_degree_model(self): def _magma_init_(self, magma): """ - Internal function. Returns a string to initialize this elliptic + Internal function. Returns a string to initialize this hyperelliptic curve in the Magma subsystem. EXAMPLES:: diff --git a/src/sage/schemes/hyperelliptic_curves_smooth_model/jacobian_generic.py b/src/sage/schemes/hyperelliptic_curves_smooth_model/jacobian_generic.py index e9b79cd17a6..183cece0b5b 100644 --- a/src/sage/schemes/hyperelliptic_curves_smooth_model/jacobian_generic.py +++ b/src/sage/schemes/hyperelliptic_curves_smooth_model/jacobian_generic.py @@ -1,150 +1,6 @@ r""" - Jacobians of hyperelliptic curves - - In Sage, a hyperelliptic curve `H` of genus `g` is always - specified by an (affine) equation in Weierstrass form - - .. MATH:: - - H : y^2 + h(x) y = f(x), - - for some polynomials `h` and `f`. - - Elements of the Jacobian of such curves can be identified - with equivalence classes of divisors. In the following, we - denote by `\infty_+`, \infty_-` the points at infinity of `H`, - and we set - - ..MATH:: - D_\infty = - \lceil g/2 \rceil \infty_+ + \lfloor g/2 \rfloor \infty_-. - - Here, `\infty_- = \infty_+`, if `H` is ramified. - Unless the genus `g` is odd and `H` is inert, the divisor - `D_\infty` is rational. In these cases, any element on - the Jacobian admits a unique representative of the form - - ..MATH:: - - [P_1 + ... + P_r + n \cdot \infty_+ + m\cdot \infty_- - D_\infty], - - with `n` and `m` non-negative integers and `P_1 + ... + P_r` - an affine and reduced divisor on `H`. - This module implements the arithemtic for Jacobians of - hyperelliptic curves. Elements of the Jacobian are represented - by tuples of the form `(u, v : n)`, where - - (u,v) is the Mumford representative of the divisor `P_1 + ... + P_r`, - - n is the coefficient of `\infty_+` - - We note that `m = g - \deg(u) - n` and is therefore omitted in - the description. Similarly, if `H` ramified or inert, - then `n` can be deduced from `\deg(u)` and `g`. In these cases, - `n` is omitted in the description as well. - - - EXAMPLES: - - We construct the Jacobian of a hyperelliptic curve with affine equation - `y^2 + (x^3 + x + 1) y = 2*x^5 + 4*x^4 + x^3 - x` over the rationals. - This curve has two points at infinity:: - - sage: R. = QQ[] - sage: H = HyperellipticCurveSmoothModel(2*x^5 + 4*x^4 + x^3 - x, x^3 + x + 1) - sage: J = Jacobian(H); J - Jacobian of Hyperelliptic Curve over Rational Field defined by y^2 + (x^3 + x + 1)*y = 2*x^5 + 4*x^4 + x^3 - x - - The points `P = (0, 0)` and `Q = (-1, -1)` are on `H`. We construct the - element `D_1 = [P - Q] = [P + (-Q) - D_\infty`] on the Jacobian:: - - sage: P = H.point([0, 0]) - sage: Q = H.point([-1, -1]) - sage: D1 = J(P,Q); D1 - (x^2 + x, -2*x : 0) - - Elements of the Jacobian can also be constructed by directly providing - the Mumford representation:: - - sage: D1 == J(x^2 + x, -2*x, 0) - True - - We can also embed single points into the Jacobian. Below we construct - `D_2 = [P - P_0]`, where `P_0` is the distinguished point of `H` - (by default one of the points at infinity):: - - sage: D2 = J(P); D2 - (x, 0 : 0) - sage: P0 = H.distinguished_point(); P0 - (1 : 0 : 0) - sage: D2 == J(P, P0) - True - - We may add elements, or multiply by integers:: - - sage: 2*D1 - (x, -1 : 1) - sage: D1 + D2 - (x^2 + x, -1 : 0) - sage: -D2 - (x, -1 : 1) - - Note that the neutral element is given by `[D_\infty - D_\infty]`, - in particular `n = 1`:: - - sage: J.zero() - (1, 0 : 1) - - There are two more elements of the Jacobian that are only supported - at infinity: `[\infty_+ - \infty_-]` and `[\infty_- - \infty_+]`:: - - sage: [P_plus, P_minus] = H.points_at_infinity() - sage: P_plus == P0 - True - sage: J(P_plus,P_minus) - (1, 0 : 2) - sage: J(P_minus, P_plus) - (1, 0 : 0) - - Now, we consider the Jacobian of a hyperelliptic curve with only one - point at infinity, defined over a finite field:: - - sage: K = FiniteField(7) - sage: R. = K[] - sage: H = HyperellipticCurveSmoothModel(x^7 + 3*x + 2) - sage: J = Jacobian(H); J - Jacobian of Hyperelliptic Curve over Finite Field of size 7 defined by y^2 = x^7 + 3*x + 2 - - Elements on the Jacobian can be constructed as before. But the value - `n` is not used here, since there is only one point at infinity:: - - sage: P = H.point([3, 0]) - sage: Q = H.point([5, 1]) - sage: D1 = J(P,Q); D1 - (x^2 + 6*x + 1, 3*x + 5) - sage: D2 = J(x^3 + 3*x^2 + 4*x + 3, 2*x^2 + 4*x) - sage: D1 + D2 - (x^3 + 2, 4) - - Over finite fields, we may also construct random elements and - compute the order of the Jacobian:: - - sage: J.random_element() #random - (x^3 + x^2 + 4*x + 5, 3*x^2 + 3*x) - sage: J.order() - 344 - - Note that arithmetic on the Jacobian is not implemented if the - underlying hyperelliptic curve is inert (i.e. has no points at - infinity) and the genus is odd:: - - sage: R. = GF(13)[] - sage: H = HyperellipticCurveSmoothModel(x^8+1,x^4+1) - sage: J = Jacobian(H); J - Jacobian of Hyperelliptic Curve over Finite Field of size 13 defined by y^2 + (x^4 + 1)*y = x^8 + 1 - - - TODO: - - finish example for the inert case. + hyperelliptic curves. AUTHORS: @@ -170,17 +26,73 @@ class HyperellipticJacobian_generic(Jacobian_generic): - """ + r""" This is the base class for Jacobians of hyperelliptic curves. + + We represent elements of the Jacobian by tuples of the form + `(u, v : n)`, where + - (u,v) is the Mumford representative of a divisor `P_1 + ... + P_r`, + - n is a non-negative integer + + This tuple represents the equivalence class + + ..MATH:: + + [P_1 + ... + P_r + n \cdot \infty_+ + m\cdot \infty_- - D_\infty], + + where `m = g - \deg(u) - n`, and `\infty_+`, \infty_-` are the + points at infinity of the hyperelliptic curve, + + ..MATH:: + D_\infty = + \lceil g/2 \rceil \infty_+ + \lfloor g/2 \rfloor \infty_-. + + Here, `\infty_- = \infty_+`, if the hyperelliptic curve is ramified. + + Such a representation exists and is unique, unless the genus `g` is odd + and the curve is inert. + + If the hyperelliptic curve is ramified or inert, then `n` can be deduced + from `\deg(u)` and `g`. In these cases, `n` is omitted in the description. """ def dimension(self): """ Return the dimension of this Jacobian. + + EXAMPLES: + + sage: R. = QQ[] + sage: H = HyperellipticCurveSmoothModel(x^2, x^4+1); H + Hyperelliptic Curve over Rational Field defined by y^2 + (x^4 + 1)*y = x^2 + sage: J = Jacobian(H) + sage: J.dimension() + 3 """ return Integer(self.curve().genus()) def point(self, *mumford, check=True, **kwargs): + r""" + Return a point on the Jacobian, given: + + 1. No arguments or the integer `0`; return `0 \in J`; + + 2. A point `P` on `J = Jac(C)`, return `P`; + + 3. A point `P` on the curve `H` such that `J = Jac(H)`; + return `[P - P_0]`, where `P_0` is the distinguished point of `H`. + By default, `P_0 = \infty`; + + 4. Two points `P, Q` on the curve `H` such that `J = Jac(H)`; + return `[P - Q]`; + + 5. Polynomials `(u, v)` such that `v^2 + hv - f \equiv 0 \pmod u`; + return `[(u(x), y - v(x))]`. + + .. SEEALSO:: + + :mod:`sage.schemes.hyperelliptic_curves_smooth_model.jacobian_homset_generic`. + """ try: return self.point_homset()(*mumford, check=check) except AttributeError: @@ -207,21 +119,63 @@ def _point(self, *args, **kwds): @cached_method def order(self): + """ + Compute the order of the Jacobian. + + .. SEEALSO:: + + :meth:`sage.schemes.hyperelliptic_curves_smooth_model.jacobian_homset_generic.order`. + """ return self.point_homset().order() def count_points(self, *args, **kwds): + """ + .. SEEALSO:: + + :meth:`sage.schemes.hyperelliptic_curves_smooth_model.jacobian_homset_generic.count_points`. + """ return self.point_homset().count_points(*args, **kwds) def lift_u(self, *args, **kwds): + """ + Return one or all points with given `u`-coordinate. + + .. SEEALSO:: + + :meth:`sage.schemes.hyperelliptic_curves_smooth_model.jacobian_homset_generic.lift_u`. + """ return self.point_homset().lift_u(*args, **kwds) def random_element(self, *args, **kwds): + """ + Return a random element of the Jacobian. + + .. SEEALSO:: + + :meth:`sage.schemes.hyperelliptic_curves_smooth_model.jacobian_homset_generic.random_element`. + """ return self.point_homset().random_element(*args, **kwds) def points(self, *args, **kwds): + """ + Return all points on the Jacobian. + + .. SEEALSO:: + + :meth:`sage.schemes.hyperelliptic_curves_smooth_model.jacobian_homset_generic.points`. + """ + return self.point_homset().points(*args, **kwds) def list(self): + """ + Return all points on the Jacobian. + + .. SEEALSO:: + + :meth:`sage.schemes.hyperelliptic_curves_smooth_model.jacobian_homset_generic.points`. + """ + return self.point_homset().points() def __iter__(self): diff --git a/src/sage/schemes/hyperelliptic_curves_smooth_model/jacobian_homset_generic.py b/src/sage/schemes/hyperelliptic_curves_smooth_model/jacobian_homset_generic.py index b4a42058e44..ea66c949618 100644 --- a/src/sage/schemes/hyperelliptic_curves_smooth_model/jacobian_homset_generic.py +++ b/src/sage/schemes/hyperelliptic_curves_smooth_model/jacobian_homset_generic.py @@ -24,16 +24,38 @@ def _morphism(self, *args, **kwds): return self._morphism_element(*args, **kwds) def curve(self): - # It is unlike you will want to use this, as this returns the original curve H even when + """ + On input the set of L-rational points of a Jacobian Jac(H) defined over K, + return the curve H. + + NOTE: + The base field of H is not extended to L. + + EXAMPLES:: + sage: R. = QQ[] + sage: K. = QQ.extension(x^2+x+1) + sage: H = HyperellipticCurveSmoothModel(x^6-1) + sage: JK = Jacobian(H)(K); JK + Abelian group of points on Jacobian of Hyperelliptic Curve over Rational Field defined by y^2 = x^6 - 1 + sage: JK.curve() + Hyperelliptic Curve over Rational Field defined by y^2 = x^6 - 1 + """ return self.codomain().curve() def extended_curve(self): """ - TODO: + On input the set of L-rational points of a Jacobian Jac(H) defined over K, + return the curve H with base extended to L. EXAMPLES:: - sage: # TODO + sage: R. = QQ[] + sage: K. = QQ.extension(x^2+x+1) + sage: H = HyperellipticCurveSmoothModel(x^6-1) + sage: JK = Jacobian(H)(K); JK + Abelian group of points on Jacobian of Hyperelliptic Curve over Rational Field defined by y^2 = x^6 - 1 + sage: JK.extended_curve() + Hyperelliptic Curve over Number Field in omega with defining polynomial x^2 + x + 1 defined by y^2 = x^6 - 1 """ # Code from schemes/generic/homset.py if "_extended_curve" in self.__dict__: @@ -125,8 +147,14 @@ def point_to_mumford_coordinates(self, P): of (the affine part of) the divisor [P]. EXAMPLES:: - - sage: # TODO + + sage: R. = QQ[] + sage: H = HyperellipticCurveSmoothModel(x^5 - 2*x^4 + 2*x^3 - x^2, 1) + sage: P = H([2,3]); P + (2 : 3 : 1) + sage: JQ = H.jacobian()(QQ) + sage: JQ.point_to_mumford_coordinates(P) + (x - 2, 3) """ R, x = self.extended_curve().polynomial_ring().objgen() X, Y, Z = P._coords @@ -152,7 +180,7 @@ def __call__(self, *args, check=True): return `[P - Q]`; 5. Polynomials `(u, v)` such that `v^2 + hv - f \equiv 0 \pmod u`; - reutrn `[(u(x), y - v(x))]`. + return `[(u(x), y - v(x))]`. EXAMPLES: @@ -285,6 +313,14 @@ def __call__(self, *args, check=True): def zero(self, check=True): """ Return the zero element of this jacobian homset. + + EXAMPLES: + + sage: R. = QQ[] + sage: H = HyperellipticCurveSmoothModel(x^5 + 1) + sage: JQ = H.jacobian()(QQ) + sage: JQ.zero() + (1, 0) """ H = self.extended_curve() R = H.polynomial_ring() @@ -398,19 +434,43 @@ def cantor_composition(self, u1, v1, u2, v2): Return the Cantor composition of ``(u1, v1)`` and ``(u2, v2)``. EXAMPLES:: - - sage: # TODO + sage: R. = GF(13)[] + sage: H = HyperellipticCurveSmoothModel(x^7 + x^5 + x + 1) + sage: JF = Jacobian(H).point_homset() + sage: (u1, v1) = (x^3 + 4*x^2, 10*x^2 + 7*x + 1) + sage: (u2, v2) = (x^3 + 8*x^2 + 11*x + 2, x^2 + 9*x + 10) + sage: JF.cantor_composition(u1, v1, u2, v2) + (x^6 + 12*x^5 + 4*x^4 + 7*x^3 + 8*x^2, 5*x^5 + 2*x^4 + 12*x^2 + 7*x + 1) """ u3, v3, _ = self._cantor_composition_generic(u1, v1, u2, v2) return u3, v3 def cantor_reduction(self, u0, v0): """ - Return the Cantor reduced ``(u0, v0)``. + Apply one reduction step of Cantor's algorithm to ``(u0, v0)``. + + Note that, in general, several steps are necessary the + representation of a reduced divisor. EXAMPLES:: + sage: R. = GF(13)[] + sage: H = HyperellipticCurveSmoothModel(x^7 + x^5 + x + 1) + sage: g = H.genus() + sage: JF = Jacobian(H).point_homset() + sage: (u0, v0) = (x^6 + 12*x^5 + 4*x^4 + 7*x^3 + 8*x^2, 5*x^5 + 2*x^4 + 12*x^2 + 7*x + 1) + sage: (u1, v1) = JF.cantor_reduction(u0, v0) + sage: u1.degree() <= g + False + sage: (u2, v2) = JF.cantor_reduction(u1, v1) + sage: u2.degree() <= g + True - sage: # TODO + Applying the reduction step to a reduced divisor might have unintended output, + as is illustrated below. + + sage: (u3, v3) = JF.cantor_reduction(u2, v2) + sage: u3.degree() >= g + True """ return self._cantor_reduction_generic(u0, v0) diff --git a/src/sage/schemes/hyperelliptic_curves_smooth_model/jacobian_homset_split.py b/src/sage/schemes/hyperelliptic_curves_smooth_model/jacobian_homset_split.py index dc25510b970..9f5b27d854f 100644 --- a/src/sage/schemes/hyperelliptic_curves_smooth_model/jacobian_homset_split.py +++ b/src/sage/schemes/hyperelliptic_curves_smooth_model/jacobian_homset_split.py @@ -33,6 +33,19 @@ def point_to_mumford_coordinates(self, P): where * n = 1 if P is the point oo+ * n = 0 otherwise . + + EXAMPLES:: + + sage: R. = QQ[] + sage: H = HyperellipticCurveSmoothModel(x^6 - 8*x^4 + 6*x^3 + 8*x^2 - 4*x + 1) + sage: P = H([-1, 46, 3]); P + (-1/3 : 46/27 : 1) + sage: O = H([1,1,0]) + sage: JQ = H.jacobian()(QQ) + sage: JQ.point_to_mumford_coordinates(P) + (x + 1/3, 46/27, 0) + sage: JQ.point_to_mumford_coordinates(O) + (1, 0, 1) """ R, x = self.curve().polynomial_ring().objgen() @@ -50,6 +63,11 @@ def point_to_mumford_coordinates(self, P): def __call__(self, *args, check=True): r""" + Return a rational point in the abstract Homset `J(K)`, given: + + 1. No arguments or the integer `0`; return `0 \in J`; + + 2. A point `P` on `J = Jac(C)`, return `P`; 3. Polynomials u,v such that `v^2 + h*v - f = 0 mod u`, returning J(u,v,n) with n = ((g - deg(u))/2).ceil(). @@ -102,7 +120,7 @@ def __call__(self, *args, check=True): The points at infinity may also be embedded into the Jacobian:: - sage: [P0,P1] = H.points_at_infinity() + sage: [P0, P1] = H.points_at_infinity() sage: JH(P0) (1, 0 : 2) sage: JH(P1) @@ -183,6 +201,11 @@ def __call__(self, *args, check=True): def cantor_composition(self, u1, v1, n1, u2, v2, n2): """ + Return the Cantor composition of the divisors represented by + ``(u1, v1, n1)`` and ``(u2, v2, n2)``. + Here ``n1`` and ``n2`` denote the multiplicity of the point + infty_+. + Follows algorithm 3.4 of Efficient Arithmetic on Hyperelliptic Curves With Real Representation @@ -190,6 +213,18 @@ def cantor_composition(self, u1, v1, n1, u2, v2, n2): https://www.math.auckland.ac.nz/~sgal018/Dave-Mireles-Full.pdf TODO: when h = 0 we can speed this up. + + EXAMPLES:: + + sage: R. = GF(7)[] + sage: H = HyperellipticCurveSmoothModel(x^8 + 3*x + 2) + sage: JF = Jacobian(H).point_homset() + sage: D1 = [x^2 + 4*x + 3, 2*x + 2, 1] + sage: assert JF(D1) + sage: D2 = [x^3 + 6*x^2 + 6*x, 6*x^2 + 6*x + 3, 0] + sage: assert JF(D2) + sage: D3 = JF.cantor_composition(*D1, *D2); D3 + (x^5 + 3*x^4 + 5*x^3 + 4*x, 3*x^3 + 3*x^2 + 3*x + 3, -1) """ # Collect data from HyperellipticCurve H = self.curve() @@ -205,11 +240,26 @@ def cantor_composition(self, u1, v1, n1, u2, v2, n2): def cantor_reduction(self, u0, v0, n0): """ + Compute the Cantor reduction of ``(u0,v0,n0)``, + where ``(u0,v0)`` represent an affine semi-reduced divisor and + n0 is the multiplicity of the point infty+. + Follows algorithm 3.5 of Efficient Arithmetic on Hyperelliptic Curves With Real Representation David J. Mireles Morales (2008) https://www.math.auckland.ac.nz/~sgal018/Dave-Mireles-Full.pdf + + EXAMPLES:: + sage: R. = GF(7)[] + sage: H = HyperellipticCurveSmoothModel(x^8 + 3*x + 2) + sage: JF = Jacobian(H).point_homset() + sage: D1 = [x^2 + 4*x + 3, 2*x + 2, 1] + sage: D2 = [x^3 + 6*x^2 + 6*x, 6*x^2 + 6*x + 3, 0] + sage: D3 = JF.cantor_composition(*D1, *D2); D3 + (x^5 + 3*x^4 + 5*x^3 + 4*x, 3*x^3 + 3*x^2 + 3*x + 3, -1) + sage: JF.cantor_reduction(*D3) + (6*x^3 + 3*x^2 + 5*x + 2, 2*x^2 + 3*x + 5, 0) """ # Collect data from HyperellipticCurve H = self.curve() @@ -237,11 +287,29 @@ def cantor_reduction(self, u0, v0, n0): def cantor_compose_at_infinity(self, u0, v0, n0, plus=True): """ + Compute the composition of ``(u0,v0,n0)`` with a divisor supported + at infinity+ (default) or infinity-, and apply a reduction step. + Follows algorithm 3.6 of Efficient Arithmetic on Hyperelliptic Curves With Real Representation David J. Mireles Morales (2008) https://www.math.auckland.ac.nz/~sgal018/Dave-Mireles-Full.pdf + + EXAMPLES: + + sage: R. = GF(7)[] + sage: H = HyperellipticCurveSmoothModel(x^8 + 3*x + 2) + sage: JF = Jacobian(H).point_homset() + sage: D1 = [x^2 + 4*x + 3, 2*x + 2, 1] + + Composing at infty+ decreases the value of n0, + while composing at infty- decreases that value. + + sage: JF.cantor_compose_at_infinity(*D1) + (x^2 + 3*x + 6, 5*x + 5, -1) + sage: JF.cantor_compose_at_infinity(*D1, plus=False) + (x^3 + 6*x^2 + x + 4, 5*x + 5, 2) """ # Collect data from HyperellipticCurve H = self.curve() diff --git a/src/sage/schemes/hyperelliptic_curves_smooth_model/jacobian_morphism.py b/src/sage/schemes/hyperelliptic_curves_smooth_model/jacobian_morphism.py index b5d5abe1229..b86faddf23c 100644 --- a/src/sage/schemes/hyperelliptic_curves_smooth_model/jacobian_morphism.py +++ b/src/sage/schemes/hyperelliptic_curves_smooth_model/jacobian_morphism.py @@ -1,5 +1,6 @@ from sage.groups.generic import order_from_multiple from sage.misc.cachefunc import cached_method +from sage.rings.finite_rings.finite_field_base import FiniteField as FiniteField_generic from sage.rings.polynomial.polynomial_element import Polynomial from sage.schemes.generic.morphism import SchemeMorphism from sage.structure.element import AdditiveGroupElement @@ -164,6 +165,24 @@ def __bool__(self): @cached_method def order(self): + """ + Returns the order of self. + This is only implemented over finite fields. + + EXAMPLES: + + sage: K = FiniteField(7) + sage: R. = K[] + sage: H = HyperellipticCurveSmoothModel(x^6 + 3*x + 2) + sage: JK = Jacobian(H)(K) + sage: D = JK(x^2 + 5*x + 6, 6*x + 3) + sage: D.order() + 38 + """ + if not isinstance(self.base_ring(), FiniteField_generic): + raise NotImplementedError( + "this is only implemented for Jacobians over a finite field" + ) n = self.parent().order() return order_from_multiple(self, n)