Path: blob/master/sage/schemes/hyperelliptic_curves/hyperelliptic_generic.py
4108 views
"""1Hyperelliptic curves over a general ring23EXAMPLE::45sage: P.<x> = GF(5)[]6sage: f = x^5 - 3*x^4 - 2*x^3 + 6*x^2 + 3*x - 17sage: C = HyperellipticCurve(f); C8Hyperelliptic Curve over Finite Field of size 5 defined by y^2 = x^5 + 2*x^4 + 3*x^3 + x^2 + 3*x + 4910EXAMPLE::1112sage: P.<x> = QQ[]13sage: f = 4*x^5 - 30*x^3 + 45*x - 2214sage: C = HyperellipticCurve(f); C15Hyperelliptic Curve over Rational Field defined by y^2 = 4*x^5 - 30*x^3 + 45*x - 2216sage: C.genus()1721819sage: D = C.affine_patch(0)20sage: D.defining_polynomials()[0].parent()21Multivariate Polynomial Ring in x0, x1 over Rational Field22"""2324#*****************************************************************************25# Copyright (C) 2006 David Kohel <[email protected]>26# Distributed under the terms of the GNU General Public License (GPL)27# http://www.gnu.org/licenses/28#*****************************************************************************2930from sage.rings.all import PolynomialRing, RR, PowerSeriesRing, LaurentSeriesRing, O31from sage.functions.all import log3233import sage.schemes.plane_curves.projective_curve as plane_curve3435def is_HyperellipticCurve(C):36"""37EXAMPLES::3839sage: R.<x> = QQ[]; C = HyperellipticCurve(x^3 + x - 1); C40Hyperelliptic Curve over Rational Field defined by y^2 = x^3 + x - 141sage: sage.schemes.hyperelliptic_curves.hyperelliptic_generic.is_HyperellipticCurve(C)42True43"""44return isinstance(C,HyperellipticCurve_generic)4546class HyperellipticCurve_generic(plane_curve.ProjectiveCurve_generic):47def __init__(self, PP, f, h=None, names=None, genus=None):48x, y, z = PP.gens()49df = f.degree()50F1 = sum([ f[i]*x**i*z**(df-i) for i in range(df+1) ])51if h is None:52F = y**2*z**(df-2) - F153else:54dh = h.degree()55deg = max(df,dh+1)56F0 = sum([ h[i]*x**i*z**(dh-i) for i in range(dh+1) ])57F = y**2*z**(deg-2) + F0*y*z**(deg-dh-1) - F1*z**(deg-df)58plane_curve.ProjectiveCurve_generic.__init__(self,PP,F)59R = PP.base_ring()60if names == None:61names = ["x","y"]62elif isinstance(names,str):63names = names.split(",")64self._names = names65P1 = PolynomialRing(R,name=names[0])66P2 = PolynomialRing(P1,name=names[1])67self._PP = PP68self._printing_ring = P269self._hyperelliptic_polynomials = (f,h)70self._genus = genus7172def change_ring(self, R):73"""74Returns this HyperEllipticCurve over a new base ring R.7576EXAMPLES::7778sage: R.<x> = QQ['x']79sage: H = HyperellipticCurve(x^3-10*x+9)80sage: K = Qp(3,5)81sage: J.<a> = K.extension(x^30-3)82sage: HK = H.change_ring(K)83sage: HJ = HK.change_ring(J); HJ84Hyperelliptic Curve over Eisenstein Extension of 3-adic Field with capped relative precision 5 in a defined by (1 + O(3^5))*x^30 + (O(3^6))*x^29 + (O(3^6))*x^28 + (O(3^6))*x^27 + (O(3^6))*x^26 + (O(3^6))*x^25 + (O(3^6))*x^24 + (O(3^6))*x^23 + (O(3^6))*x^22 + (O(3^6))*x^21 + (O(3^6))*x^20 + (O(3^6))*x^19 + (O(3^6))*x^18 + (O(3^6))*x^17 + (O(3^6))*x^16 + (O(3^6))*x^15 + (O(3^6))*x^14 + (O(3^6))*x^13 + (O(3^6))*x^12 + (O(3^6))*x^11 + (O(3^6))*x^10 + (O(3^6))*x^9 + (O(3^6))*x^8 + (O(3^6))*x^7 + (O(3^6))*x^6 + (O(3^6))*x^5 + (O(3^6))*x^4 + (O(3^6))*x^3 + (O(3^6))*x^2 + (O(3^6))*x + (2*3 + 2*3^2 + 2*3^3 + 2*3^4 + 2*3^5 + O(3^6)) defined by (1 + O(a^150))*y^2 = (1 + O(a^150))*x^3 + (2 + 2*a^30 + a^60 + 2*a^90 + 2*a^120 + O(a^150))*x + a^60 + O(a^210)85"""86from constructor import HyperellipticCurve87f, h = self._hyperelliptic_polynomials88y = self._printing_ring.variable_name()89x = self._printing_ring.base_ring().variable_name()90return HyperellipticCurve(f.change_ring(R), h, "%s,%s"%(x,y))9192def _repr_(self):93"""94String representation of hyperelliptic curves.9596EXAMPLE::9798sage: P.<x> = QQ[]99sage: f = 4*x^5 - 30*x^3 + 45*x - 22100sage: C = HyperellipticCurve(f); C101Hyperelliptic Curve over Rational Field defined by y^2 = 4*x^5 - 30*x^3 + 45*x - 22102sage: C = HyperellipticCurve(f,names='u,v'); C103Hyperelliptic Curve over Rational Field defined by v^2 = 4*u^5 - 30*u^3 + 45*u - 22104"""105106f, h = self._hyperelliptic_polynomials107R = self.base_ring()108y = self._printing_ring.gen()109x = self._printing_ring.base_ring().gen()110if h == 0:111return "Hyperelliptic Curve over %s defined by %s = %s"%(R, y**2, f(x))112else:113return "Hyperelliptic Curve over %s defined by %s + %s = %s"%(R, y**2, h(x)*y, f(x))114115def __cmp__(self, other):116if not isinstance(other, HyperellipticCurve_generic):117return -1118return cmp(self._hyperelliptic_polynomials, other._hyperelliptic_polynomials)119120def hyperelliptic_polynomials(self, K=None, var='x'):121"""122EXAMPLES::123124sage: R.<x> = QQ[]; C = HyperellipticCurve(x^3 + x - 1, x^3/5); C125Hyperelliptic Curve over Rational Field defined by y^2 + 1/5*x^3*y = x^3 + x - 1126sage: C.hyperelliptic_polynomials()127(x^3 + x - 1, 1/5*x^3)128"""129if K is None:130return self._hyperelliptic_polynomials131else:132f, h = self._hyperelliptic_polynomials133P = PolynomialRing(K, var)134return (P(f),P(h))135136def is_singular(self):137r"""138Returns False, because hyperelliptic curves are smooth projective139curves, as checked on construction.140141EXAMPLES::142143sage: R.<x> = QQ[]144sage: H = HyperellipticCurve(x^5+1)145sage: H.is_singular()146False147148A hyperelliptic curve with genus at least 2 always has a singularity at149infinity when viewed as a *plane* projective curve. This can be seen in150the following example.::151152sage: R.<x> = QQ[]153sage: H = HyperellipticCurve(x^5+2)154sage: set_verbose(None)155sage: H.is_singular()156False157sage: from sage.schemes.plane_curves.projective_curve import ProjectiveCurve_generic158sage: ProjectiveCurve_generic.is_singular(H)159True160"""161return False162163def is_smooth(self):164r"""165Returns True, because hyperelliptic curves are smooth projective166curves, as checked on construction.167168EXAMPLES::169170sage: R.<x> = GF(13)[]171sage: H = HyperellipticCurve(x^8+1)172sage: H.is_smooth()173True174175A hyperelliptic curve with genus at least 2 always has a singularity at176infinity when viewed as a *plane* projective curve. This can be seen in177the following example.::178179sage: R.<x> = GF(27, 'a')[]180sage: H = HyperellipticCurve(x^10+2)181sage: set_verbose(None)182sage: H.is_smooth()183True184sage: from sage.schemes.plane_curves.projective_curve import ProjectiveCurve_generic185sage: ProjectiveCurve_generic.is_smooth(H)186False187"""188return True189190def lift_x(self, x, all=False):191f, h = self._hyperelliptic_polynomials192x += self.base_ring()(0)193one = x.parent()(1)194if h.is_zero():195y2 = f(x)196if y2.is_square():197if all:198return [self.point([x, y, one], check=False) for y in y2.sqrt(all=True)]199else:200return self.point([x, y2.sqrt(), one], check=False)201else:202b = h(x)203D = b*b + 4*f(x)204if D.is_square():205if all:206return [self.point([x, (-b+d)/2, one], check=False) for d in D.sqrt(all=True)]207else:208return self.point([x, (-b+D.sqrt())/2, one], check=False)209if all:210return []211else:212raise ValueError, "No point with x-coordinate %s on %s"%(x, self)213214215def genus(self):216return self._genus217218def jacobian(self):219import jacobian_generic220return jacobian_generic.HyperellipticJacobian_generic(self)221222def odd_degree_model(self):223r"""224Return an odd degree model of self, or raise ValueError if one does not exist over the field of definition.225226EXAMPLES::227228sage: x = QQ['x'].gen()229sage: H = HyperellipticCurve((x^2 + 2)*(x^2 + 3)*(x^2 + 5)); H230Hyperelliptic Curve over Rational Field defined by y^2 = x^6 + 10*x^4 + 31*x^2 + 30231sage: H.odd_degree_model()232Traceback (most recent call last):233...234ValueError: No odd degree model exists over field of definition235236sage: K2 = QuadraticField(-2, 'a')237sage: Hp2 = H.change_ring(K2).odd_degree_model(); Hp2238Hyperelliptic Curve over Number Field in a with defining polynomial x^2 + 2 defined by y^2 = 6*a*x^5 - 29*x^4 - 20*x^2 + 6*a*x + 1239240sage: K3 = QuadraticField(-3, 'b')241sage: Hp3 = H.change_ring(QuadraticField(-3, 'b')).odd_degree_model(); Hp3242Hyperelliptic Curve over Number Field in b with defining polynomial x^2 + 3 defined by y^2 = -4*b*x^5 - 14*x^4 - 20*b*x^3 - 35*x^2 + 6*b*x + 1243244Of course, Hp2 and Hp3 are isomorphic over the composite245extension. One consequence of this is that odd degree models246reduced over "different" fields should have the same number of247points on their reductions. 43 and 67 split completely in the248compositum, so when we reduce we find:249250sage: P2 = K2.factor(43)[0][0]251sage: P3 = K3.factor(43)[0][0]252sage: Hp2.change_ring(K2.residue_field(P2)).frobenius_polynomial()253x^4 - 16*x^3 + 134*x^2 - 688*x + 1849254sage: Hp3.change_ring(K3.residue_field(P3)).frobenius_polynomial()255x^4 - 16*x^3 + 134*x^2 - 688*x + 1849256sage: H.change_ring(GF(43)).odd_degree_model().frobenius_polynomial()257x^4 - 16*x^3 + 134*x^2 - 688*x + 1849258259sage: P2 = K2.factor(67)[0][0]260sage: P3 = K3.factor(67)[0][0]261sage: Hp2.change_ring(K2.residue_field(P2)).frobenius_polynomial()262x^4 - 8*x^3 + 150*x^2 - 536*x + 4489263sage: Hp3.change_ring(K3.residue_field(P3)).frobenius_polynomial()264x^4 - 8*x^3 + 150*x^2 - 536*x + 4489265sage: H.change_ring(GF(67)).odd_degree_model().frobenius_polynomial()266x^4 - 8*x^3 + 150*x^2 - 536*x + 4489267268TESTS::269sage: HyperellipticCurve(x^5 + 1, 1).odd_degree_model()270Traceback (most recent call last):271...272NotImplementedError: odd_degree_model only implemented for curves in Weierstrass form273274sage: HyperellipticCurve(x^5 + 1, names="U, V").odd_degree_model()275Hyperelliptic Curve over Rational Field defined by V^2 = U^5 + 1276"""277f, h = self._hyperelliptic_polynomials278if h:279raise NotImplementedError, "odd_degree_model only implemented for curves in Weierstrass form"280if f.degree() % 2:281# already odd, so just yield self282return self283284rts = f.roots(multiplicities=False)285if not rts:286raise ValueError, "No odd degree model exists over field of definition"287rt = rts[0]288x = f.parent().gen()289fnew = f((x*rt + 1)/x).numerator() # move rt to "infinity"290291from constructor import HyperellipticCurve292return HyperellipticCurve(fnew, 0, names=self._names, PP=self._PP)293294def has_odd_degree_model(self):295r"""296Return True if an odd degree model of self exists over the field of definition; False otherwise.297298Use ``odd_degree_model`` to calculate an odd degree model.299300EXAMPLES::301sage: x = QQ['x'].0302sage: HyperellipticCurve(x^5 + x).has_odd_degree_model()303True304sage: HyperellipticCurve(x^6 + x).has_odd_degree_model()305True306sage: HyperellipticCurve(x^6 + x + 1).has_odd_degree_model()307False308"""309try:310return bool(self.odd_degree_model())311except ValueError:312return False313314def _magma_init_(self, magma):315"""316Internal function. Returns a string to initialize this elliptic317curve in the Magma subsystem.318319EXAMPLES::320321sage: R.<x> = QQ[]; C = HyperellipticCurve(x^3 + x - 1, x); C322Hyperelliptic Curve over Rational Field defined by y^2 + x*y = x^3 + x - 1323sage: magma(C) # optional - magma324Hyperelliptic Curve defined by y^2 + x*y = x^3 + x - 1 over Rational Field325sage: R.<x> = GF(9,'a')[]; C = HyperellipticCurve(x^3 + x - 1, x^10); C326Hyperelliptic Curve over Finite Field in a of size 3^2 defined by y^2 + x^10*y = x^3 + x + 2327sage: D = magma(C); D # optional - magma328Hyperelliptic Curve defined by y^2 + (x^10)*y = x^3 + x + 2 over GF(3^2)329sage: D.sage() # optional - magma330Hyperelliptic Curve over Finite Field in a of size 3^2 defined by y^2 + x^10*y = x^3 + x + 2331"""332f, h = self._hyperelliptic_polynomials333return 'HyperellipticCurve(%s, %s)'%(f._magma_init_(magma), h._magma_init_(magma))334335336def monsky_washnitzer_gens(self):337import sage.schemes.elliptic_curves.monsky_washnitzer as monsky_washnitzer338S = monsky_washnitzer.SpecialHyperellipticQuotientRing(self)339return S.gens()340341def invariant_differential(self):342"""343Returns $dx/2y$, as an element of the Monsky-Washnitzer cohomology344of self345346EXAMPLES::347348sage: R.<x> = QQ['x']349sage: C = HyperellipticCurve(x^5 - 4*x + 4)350sage: C.invariant_differential()3511 dx/2y352353"""354import sage.schemes.elliptic_curves.monsky_washnitzer as m_w355S = m_w.SpecialHyperellipticQuotientRing(self)356MW = m_w.MonskyWashnitzerDifferentialRing(S)357return MW.invariant_differential()358359def local_coordinates_at_nonweierstrass(self, P, prec = 20, name = 't'):360"""361For a non-Weierstrass point P = (a,b) on the hyperelliptic362curve y^2 = f(x), returns (x(t), y(t)) such that (y(t))^2 = f(x(t)),363where t = x - a is the local parameter.364365INPUT:366367- P = (a,b) a non-Weierstrass point on self368- prec: desired precision of the local coordinates369- name: gen of the power series ring (default: 't')370371OUTPUT:372(x(t),y(t)) such that y(t)^2 = f(x(t)) and t = x - a373is the local parameter at P374375EXAMPLES::376377sage: R.<x> = QQ['x']378sage: H = HyperellipticCurve(x^5-23*x^3+18*x^2+40*x)379sage: P = H(1,6)380sage: x,y = H.local_coordinates_at_nonweierstrass(P,prec=5)381sage: x3821 + t + O(t^5)383sage: y3846 + t - 7/2*t^2 - 1/2*t^3 - 25/48*t^4 + O(t^5)385sage: Q = H(-2,12)386sage: x,y = H.local_coordinates_at_nonweierstrass(Q,prec=5)387sage: x388-2 + t + O(t^5)389sage: y39012 - 19/2*t - 19/32*t^2 + 61/256*t^3 - 5965/24576*t^4 + O(t^5)391392AUTHOR:393394- Jennifer Balakrishnan (2007-12)395"""396d = P[1]397if d == 0:398raise TypeError, "P = %s is a Weierstrass point. Use local_coordinates_at_weierstrass instead!"%P399pol = self.hyperelliptic_polynomials()[0]400L = PowerSeriesRing(self.base_ring(), name)401t = L.gen()402L.set_default_prec(prec)403K = PowerSeriesRing(L, 'x')404pol = K(pol)405x = K.gen()406b = P[0]407f = pol(t+b)408for i in range((RR(log(prec)/log(2))).ceil()):409d = (d + f/d)/2410return t+b+O(t**(prec)), d + O(t**(prec))411412def local_coordinates_at_weierstrass(self, P, prec = 20, name = 't'):413"""414For a finite Weierstrass point on the hyperelliptic415curve y^2 = f(x), returns (x(t), y(t)) such that416(y(t))^2 = f(x(t)), where t = y is the local parameter.417418INPUT:419- P a finite Weierstrass point on self420- prec: desired precision of the local coordinates421- name: gen of the power series ring (default: 't')422423OUTPUT:424425(x(t),y(t)) such that y(t)^2 = f(x(t)) and t = y426is the local parameter at P427428EXAMPLES:429sage: R.<x> = QQ['x']430sage: H = HyperellipticCurve(x^5-23*x^3+18*x^2+40*x)431sage: A = H(4,0)432sage: x,y = H.local_coordinates_at_weierstrass(A,prec =5)433sage: x4344 + 1/360*t^2 - 191/23328000*t^4 + 7579/188956800000*t^6 + O(t^7)435sage: y436t + O(t^7)437sage: B = H(-5,0)438sage: x,y = H.local_coordinates_at_weierstrass(B,prec = 5)439sage: x440-5 + 1/1260*t^2 + 887/2000376000*t^4 + 643759/1587898468800000*t^6 + O(t^7)441sage: y442t + O(t^7)443444AUTHOR:445- Jennifer Balakrishnan (2007-12)446"""447if P[1] != 0:448raise TypeError, "P = %s is not a finite Weierstrass point. Use local_coordinates_at_nonweierstrass instead!"%P449pol = self.hyperelliptic_polynomials()[0]450L = PowerSeriesRing(self.base_ring(), name)451t = L.gen()452L.set_default_prec(prec+2)453K = PowerSeriesRing(L, 'x')454pol = K(pol)455x = K.gen()456b = P[0]457g = pol/(x-b)458c = b+1/g(b)*t**2459f = pol - t**2460fprime = f.derivative()461for i in range((RR(log(prec+2)/log(2))).ceil()):462c = c-f(c)/fprime(c)463return c + O(t**(prec+2)),t+O(t**(prec+2))464465def local_coordinates_at_infinity(self, prec = 20, name = 't'):466"""467For the genus g hyperelliptic curve y^2 = f(x), returns (x(t), y(t)) such that468(y(t))^2 = f(x(t)), where t = x^g/y is the local parameter at infinity469470INPUT:471- prec: desired precision of the local coordinates472- name: gen of the power series ring (default: 't')473474OUTPUT:475(x(t),y(t)) such that y(t)^2 = f(x(t)) and t = x^g/y476is the local parameter at infinity477478479EXAMPLES:480sage: R.<x> = QQ['x']481sage: H = HyperellipticCurve(x^5-5*x^2+1)482sage: x,y = H.local_coordinates_at_infinity(10)483sage: x484t^-2 + 5*t^4 - t^8 - 50*t^10 + O(t^12)485sage: y486t^-5 + 10*t - 2*t^5 - 75*t^7 + 50*t^11 + O(t^12)487488sage: R.<x> = QQ['x']489sage: H = HyperellipticCurve(x^3-x+1)490sage: x,y = H.local_coordinates_at_infinity(10)491sage: x492t^-2 + t^2 - t^4 - t^6 + 3*t^8 + O(t^12)493sage: y494t^-3 + t - t^3 - t^5 + 3*t^7 - 10*t^11 + O(t^12)495496497AUTHOR:498- Jennifer Balakrishnan (2007-12)499"""500g = self.genus()501pol = self.hyperelliptic_polynomials()[0]502K = LaurentSeriesRing(self.base_ring(), name)503t = K.gen()504K.set_default_prec(prec+2)505L = PolynomialRing(self.base_ring(),'x')506x = L.gen()507i = 0508w = (x**g/t)**2-pol509wprime = w.derivative(x)510x = t**-2511for i in range((RR(log(prec+2)/log(2))).ceil()):512x = x-w(x)/wprime(x)513y = x**g/t514return x+O(t**(prec+2)) , y+O(t**(prec+2))515516517def local_coord(self, P, prec = 20, name = 't'):518"""519Calls the appropriate local_coordinates function520521INPUT:522- P a point on self523- prec: desired precision of the local coordinates524- name: gen of the power series ring (default: 't')525526OUTPUT:527(x(t),y(t)) such that y(t)^2 = f(x(t)), where t528is the local parameter at P529530EXAMPLES:531sage: R.<x> = QQ['x']532sage: H = HyperellipticCurve(x^5-23*x^3+18*x^2+40*x)533sage: H.local_coord(H(1,6),prec=5)534(1 + t + O(t^5), 6 + t - 7/2*t^2 - 1/2*t^3 - 25/48*t^4 + O(t^5))535sage: H.local_coord(H(4,0),prec=5)536(4 + 1/360*t^2 - 191/23328000*t^4 + 7579/188956800000*t^6 + O(t^7), t + O(t^7))537sage: H.local_coord(H(0,1,0),prec=5)538(t^-2 + 23*t^2 - 18*t^4 - 569*t^6 + O(t^7), t^-5 + 46*t^-1 - 36*t - 609*t^3 + 1656*t^5 + O(t^6))539540AUTHOR:541- Jennifer Balakrishnan (2007-12)542543544"""545if P[1] == 0:546return self.local_coordinates_at_weierstrass(P, prec, name)547elif P[2] == 0:548return self.local_coordinates_at_infinity(prec, name)549else:550return self.local_coordinates_at_nonweierstrass(P, prec, name)551552553