Path: blob/master/src/sage/schemes/hyperelliptic_curves/hyperelliptic_generic.py
8821 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[]79sage: H = HyperellipticCurve(x^5 - 10*x + 9)80sage: K = Qp(3,5)81sage: L.<a> = K.extension(x^30-3)82sage: HK = H.change_ring(K)83sage: HL = HK.change_ring(L); HL84Hyperelliptic 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^5 + (2 + 2*a^30 + a^60 + 2*a^90 + 2*a^120 + O(a^150))*x + a^60 + O(a^210)8586sage: R.<x> = FiniteField(7)[]87sage: H = HyperellipticCurve(x^8 + x + 5)88sage: H.base_extend(FiniteField(7^2, 'a'))89Hyperelliptic Curve over Finite Field in a of size 7^2 defined by y^2 = x^8 + x + 590"""91from constructor import HyperellipticCurve92f, h = self._hyperelliptic_polynomials93y = self._printing_ring.variable_name()94x = self._printing_ring.base_ring().variable_name()95return HyperellipticCurve(f.change_ring(R), h.change_ring(R), "%s,%s"%(x,y))9697base_extend = change_ring9899def _repr_(self):100"""101String representation of hyperelliptic curves.102103EXAMPLE::104105sage: P.<x> = QQ[]106sage: f = 4*x^5 - 30*x^3 + 45*x - 22107sage: C = HyperellipticCurve(f); C108Hyperelliptic Curve over Rational Field defined by y^2 = 4*x^5 - 30*x^3 + 45*x - 22109sage: C = HyperellipticCurve(f,names='u,v'); C110Hyperelliptic Curve over Rational Field defined by v^2 = 4*u^5 - 30*u^3 + 45*u - 22111"""112113f, h = self._hyperelliptic_polynomials114R = self.base_ring()115y = self._printing_ring.gen()116x = self._printing_ring.base_ring().gen()117if h == 0:118return "Hyperelliptic Curve over %s defined by %s = %s"%(R, y**2, f(x))119else:120return "Hyperelliptic Curve over %s defined by %s + %s = %s"%(R, y**2, h(x)*y, f(x))121122def __cmp__(self, other):123if not isinstance(other, HyperellipticCurve_generic):124return -1125return cmp(self._hyperelliptic_polynomials, other._hyperelliptic_polynomials)126127def hyperelliptic_polynomials(self, K=None, var='x'):128"""129EXAMPLES::130131sage: R.<x> = QQ[]; C = HyperellipticCurve(x^3 + x - 1, x^3/5); C132Hyperelliptic Curve over Rational Field defined by y^2 + 1/5*x^3*y = x^3 + x - 1133sage: C.hyperelliptic_polynomials()134(x^3 + x - 1, 1/5*x^3)135"""136if K is None:137return self._hyperelliptic_polynomials138else:139f, h = self._hyperelliptic_polynomials140P = PolynomialRing(K, var)141return (P(f),P(h))142143def is_singular(self):144r"""145Returns False, because hyperelliptic curves are smooth projective146curves, as checked on construction.147148EXAMPLES::149150sage: R.<x> = QQ[]151sage: H = HyperellipticCurve(x^5+1)152sage: H.is_singular()153False154155A hyperelliptic curve with genus at least 2 always has a singularity at156infinity when viewed as a *plane* projective curve. This can be seen in157the following example.::158159sage: R.<x> = QQ[]160sage: H = HyperellipticCurve(x^5+2)161sage: set_verbose(None)162sage: H.is_singular()163False164sage: from sage.schemes.plane_curves.projective_curve import ProjectiveCurve_generic165sage: ProjectiveCurve_generic.is_singular(H)166True167"""168return False169170def is_smooth(self):171r"""172Returns True, because hyperelliptic curves are smooth projective173curves, as checked on construction.174175EXAMPLES::176177sage: R.<x> = GF(13)[]178sage: H = HyperellipticCurve(x^8+1)179sage: H.is_smooth()180True181182A hyperelliptic curve with genus at least 2 always has a singularity at183infinity when viewed as a *plane* projective curve. This can be seen in184the following example.::185186sage: R.<x> = GF(27, 'a')[]187sage: H = HyperellipticCurve(x^10+2)188sage: set_verbose(None)189sage: H.is_smooth()190True191sage: from sage.schemes.plane_curves.projective_curve import ProjectiveCurve_generic192sage: ProjectiveCurve_generic.is_smooth(H)193False194"""195return True196197def lift_x(self, x, all=False):198f, h = self._hyperelliptic_polynomials199x += self.base_ring()(0)200one = x.parent()(1)201if h.is_zero():202y2 = f(x)203if y2.is_square():204if all:205return [self.point([x, y, one], check=False) for y in y2.sqrt(all=True)]206else:207return self.point([x, y2.sqrt(), one], check=False)208else:209b = h(x)210D = b*b + 4*f(x)211if D.is_square():212if all:213return [self.point([x, (-b+d)/2, one], check=False) for d in D.sqrt(all=True)]214else:215return self.point([x, (-b+D.sqrt())/2, one], check=False)216if all:217return []218else:219raise ValueError, "No point with x-coordinate %s on %s"%(x, self)220221222def genus(self):223return self._genus224225def jacobian(self):226import jacobian_generic227return jacobian_generic.HyperellipticJacobian_generic(self)228229def odd_degree_model(self):230r"""231Return an odd degree model of self, or raise ValueError if one does not exist over the field of definition.232233EXAMPLES::234235sage: x = QQ['x'].gen()236sage: H = HyperellipticCurve((x^2 + 2)*(x^2 + 3)*(x^2 + 5)); H237Hyperelliptic Curve over Rational Field defined by y^2 = x^6 + 10*x^4 + 31*x^2 + 30238sage: H.odd_degree_model()239Traceback (most recent call last):240...241ValueError: No odd degree model exists over field of definition242243sage: K2 = QuadraticField(-2, 'a')244sage: Hp2 = H.change_ring(K2).odd_degree_model(); Hp2245Hyperelliptic 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 + 1246247sage: K3 = QuadraticField(-3, 'b')248sage: Hp3 = H.change_ring(QuadraticField(-3, 'b')).odd_degree_model(); Hp3249Hyperelliptic 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 + 1250251Of course, Hp2 and Hp3 are isomorphic over the composite252extension. One consequence of this is that odd degree models253reduced over "different" fields should have the same number of254points on their reductions. 43 and 67 split completely in the255compositum, so when we reduce we find:256257sage: P2 = K2.factor(43)[0][0]258sage: P3 = K3.factor(43)[0][0]259sage: Hp2.change_ring(K2.residue_field(P2)).frobenius_polynomial()260x^4 - 16*x^3 + 134*x^2 - 688*x + 1849261sage: Hp3.change_ring(K3.residue_field(P3)).frobenius_polynomial()262x^4 - 16*x^3 + 134*x^2 - 688*x + 1849263sage: H.change_ring(GF(43)).odd_degree_model().frobenius_polynomial()264x^4 - 16*x^3 + 134*x^2 - 688*x + 1849265266sage: P2 = K2.factor(67)[0][0]267sage: P3 = K3.factor(67)[0][0]268sage: Hp2.change_ring(K2.residue_field(P2)).frobenius_polynomial()269x^4 - 8*x^3 + 150*x^2 - 536*x + 4489270sage: Hp3.change_ring(K3.residue_field(P3)).frobenius_polynomial()271x^4 - 8*x^3 + 150*x^2 - 536*x + 4489272sage: H.change_ring(GF(67)).odd_degree_model().frobenius_polynomial()273x^4 - 8*x^3 + 150*x^2 - 536*x + 4489274275TESTS::276sage: HyperellipticCurve(x^5 + 1, 1).odd_degree_model()277Traceback (most recent call last):278...279NotImplementedError: odd_degree_model only implemented for curves in Weierstrass form280281sage: HyperellipticCurve(x^5 + 1, names="U, V").odd_degree_model()282Hyperelliptic Curve over Rational Field defined by V^2 = U^5 + 1283"""284f, h = self._hyperelliptic_polynomials285if h:286raise NotImplementedError, "odd_degree_model only implemented for curves in Weierstrass form"287if f.degree() % 2:288# already odd, so just yield self289return self290291rts = f.roots(multiplicities=False)292if not rts:293raise ValueError, "No odd degree model exists over field of definition"294rt = rts[0]295x = f.parent().gen()296fnew = f((x*rt + 1)/x).numerator() # move rt to "infinity"297298from constructor import HyperellipticCurve299return HyperellipticCurve(fnew, 0, names=self._names, PP=self._PP)300301def has_odd_degree_model(self):302r"""303Return True if an odd degree model of self exists over the field of definition; False otherwise.304305Use ``odd_degree_model`` to calculate an odd degree model.306307EXAMPLES::308sage: x = QQ['x'].0309sage: HyperellipticCurve(x^5 + x).has_odd_degree_model()310True311sage: HyperellipticCurve(x^6 + x).has_odd_degree_model()312True313sage: HyperellipticCurve(x^6 + x + 1).has_odd_degree_model()314False315"""316try:317return bool(self.odd_degree_model())318except ValueError:319return False320321def _magma_init_(self, magma):322"""323Internal function. Returns a string to initialize this elliptic324curve in the Magma subsystem.325326EXAMPLES::327328sage: R.<x> = QQ[]; C = HyperellipticCurve(x^3 + x - 1, x); C329Hyperelliptic Curve over Rational Field defined by y^2 + x*y = x^3 + x - 1330sage: magma(C) # optional - magma331Hyperelliptic Curve defined by y^2 + x*y = x^3 + x - 1 over Rational Field332sage: R.<x> = GF(9,'a')[]; C = HyperellipticCurve(x^3 + x - 1, x^10); C333Hyperelliptic Curve over Finite Field in a of size 3^2 defined by y^2 + x^10*y = x^3 + x + 2334sage: D = magma(C); D # optional - magma335Hyperelliptic Curve defined by y^2 + (x^10)*y = x^3 + x + 2 over GF(3^2)336sage: D.sage() # optional - magma337Hyperelliptic Curve over Finite Field in a of size 3^2 defined by y^2 + x^10*y = x^3 + x + 2338"""339f, h = self._hyperelliptic_polynomials340return 'HyperellipticCurve(%s, %s)'%(f._magma_init_(magma), h._magma_init_(magma))341342343def monsky_washnitzer_gens(self):344import sage.schemes.elliptic_curves.monsky_washnitzer as monsky_washnitzer345S = monsky_washnitzer.SpecialHyperellipticQuotientRing(self)346return S.gens()347348def invariant_differential(self):349"""350Returns $dx/2y$, as an element of the Monsky-Washnitzer cohomology351of self352353EXAMPLES::354355sage: R.<x> = QQ['x']356sage: C = HyperellipticCurve(x^5 - 4*x + 4)357sage: C.invariant_differential()3581 dx/2y359360"""361import sage.schemes.elliptic_curves.monsky_washnitzer as m_w362S = m_w.SpecialHyperellipticQuotientRing(self)363MW = m_w.MonskyWashnitzerDifferentialRing(S)364return MW.invariant_differential()365366def local_coordinates_at_nonweierstrass(self, P, prec=20, name='t'):367"""368For a non-Weierstrass point P = (a,b) on the hyperelliptic369curve y^2 = f(x), returns (x(t), y(t)) such that (y(t))^2 = f(x(t)),370where t = x - a is the local parameter.371372INPUT:373374- P = (a,b) a non-Weierstrass point on self375- prec: desired precision of the local coordinates376- name: gen of the power series ring (default: 't')377378OUTPUT:379(x(t),y(t)) such that y(t)^2 = f(x(t)) and t = x - a380is the local parameter at P381382EXAMPLES::383384sage: R.<x> = QQ['x']385sage: H = HyperellipticCurve(x^5-23*x^3+18*x^2+40*x)386sage: P = H(1,6)387sage: x,y = H.local_coordinates_at_nonweierstrass(P,prec=5)388sage: x3891 + t + O(t^5)390sage: y3916 + t - 7/2*t^2 - 1/2*t^3 - 25/48*t^4 + O(t^5)392sage: Q = H(-2,12)393sage: x,y = H.local_coordinates_at_nonweierstrass(Q,prec=5)394sage: x395-2 + t + O(t^5)396sage: y39712 - 19/2*t - 19/32*t^2 + 61/256*t^3 - 5965/24576*t^4 + O(t^5)398399AUTHOR:400401- Jennifer Balakrishnan (2007-12)402"""403d = P[1]404if d == 0:405raise TypeError, "P = %s is a Weierstrass point. Use local_coordinates_at_weierstrass instead!"%P406pol = self.hyperelliptic_polynomials()[0]407L = PowerSeriesRing(self.base_ring(), name)408t = L.gen()409L.set_default_prec(prec)410K = PowerSeriesRing(L, 'x')411pol = K(pol)412x = K.gen()413b = P[0]414f = pol(t+b)415for i in range((RR(log(prec)/log(2))).ceil()):416d = (d + f/d)/2417return t+b+O(t**(prec)), d + O(t**(prec))418419def local_coordinates_at_weierstrass(self, P, prec=20, name='t'):420"""421For a finite Weierstrass point on the hyperelliptic422curve y^2 = f(x), returns (x(t), y(t)) such that423(y(t))^2 = f(x(t)), where t = y is the local parameter.424425INPUT:426- P a finite Weierstrass point on self427- prec: desired precision of the local coordinates428- name: gen of the power series ring (default: 't')429430OUTPUT:431432(x(t),y(t)) such that y(t)^2 = f(x(t)) and t = y433is the local parameter at P434435EXAMPLES:436sage: R.<x> = QQ['x']437sage: H = HyperellipticCurve(x^5-23*x^3+18*x^2+40*x)438sage: A = H(4, 0)439440sage: x, y = H.local_coordinates_at_weierstrass(A, prec=7)441442sage: x4434 + 1/360*t^2 - 191/23328000*t^4 + 7579/188956800000*t^6 + O(t^7)444sage: y445t + O(t^7)446sage: B = H(-5, 0)447sage: x, y = H.local_coordinates_at_weierstrass(B, prec=5)448sage: x449-5 + 1/1260*t^2 + 887/2000376000*t^4 + O(t^5)450sage: y451t + O(t^5)452453AUTHOR:454- Jennifer Balakrishnan (2007-12)455456- Francis Clarke (2012-08-26)457"""458if P[1] != 0:459raise TypeError, "P = %s is not a finite Weierstrass point. Use local_coordinates_at_nonweierstrass instead!"%P460L = PowerSeriesRing(self.base_ring(), name)461t = L.gen()462pol = self.hyperelliptic_polynomials()[0]463pol_prime = pol.derivative()464b = P[0]465t2 = t**2466c = b + t2/pol_prime(b)467c = c.add_bigoh(prec)468for _ in range(1 + log(prec, 2)):469c -= (pol(c) - t2)/pol_prime(c)470return (c, t.add_bigoh(prec))471472def local_coordinates_at_infinity(self, prec = 20, name = 't'):473"""474For the genus g hyperelliptic curve y^2 = f(x), returns (x(t), y(t)) such that475(y(t))^2 = f(x(t)), where t = x^g/y is the local parameter at infinity476477INPUT:478- prec: desired precision of the local coordinates479- name: gen of the power series ring (default: 't')480481OUTPUT:482(x(t),y(t)) such that y(t)^2 = f(x(t)) and t = x^g/y483is the local parameter at infinity484485486EXAMPLES:487sage: R.<x> = QQ['x']488sage: H = HyperellipticCurve(x^5-5*x^2+1)489sage: x,y = H.local_coordinates_at_infinity(10)490sage: x491t^-2 + 5*t^4 - t^8 - 50*t^10 + O(t^12)492sage: y493t^-5 + 10*t - 2*t^5 - 75*t^7 + 50*t^11 + O(t^12)494495sage: R.<x> = QQ['x']496sage: H = HyperellipticCurve(x^3-x+1)497sage: x,y = H.local_coordinates_at_infinity(10)498sage: x499t^-2 + t^2 - t^4 - t^6 + 3*t^8 + O(t^12)500sage: y501t^-3 + t - t^3 - t^5 + 3*t^7 - 10*t^11 + O(t^12)502503504AUTHOR:505- Jennifer Balakrishnan (2007-12)506"""507g = self.genus()508pol = self.hyperelliptic_polynomials()[0]509K = LaurentSeriesRing(self.base_ring(), name)510t = K.gen()511K.set_default_prec(prec+2)512L = PolynomialRing(self.base_ring(),'x')513x = L.gen()514i = 0515w = (x**g/t)**2-pol516wprime = w.derivative(x)517x = t**-2518for i in range((RR(log(prec+2)/log(2))).ceil()):519x = x-w(x)/wprime(x)520y = x**g/t521return x+O(t**(prec+2)) , y+O(t**(prec+2))522523524def local_coord(self, P, prec = 20, name = 't'):525"""526Calls the appropriate local_coordinates function527528INPUT:529- P a point on self530- prec: desired precision of the local coordinates531- name: gen of the power series ring (default: 't')532533OUTPUT:534(x(t),y(t)) such that y(t)^2 = f(x(t)), where t535is the local parameter at P536537EXAMPLES:538sage: R.<x> = QQ['x']539sage: H = HyperellipticCurve(x^5-23*x^3+18*x^2+40*x)540sage: H.local_coord(H(1 ,6), prec=5)541(1 + t + O(t^5), 6 + t - 7/2*t^2 - 1/2*t^3 - 25/48*t^4 + O(t^5))542sage: H.local_coord(H(4, 0), prec=7)543(4 + 1/360*t^2 - 191/23328000*t^4 + 7579/188956800000*t^6 + O(t^7), t + O(t^7))544sage: H.local_coord(H(0, 1, 0), prec=5)545(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))546547AUTHOR:548- Jennifer Balakrishnan (2007-12)549550551"""552if P[1] == 0:553return self.local_coordinates_at_weierstrass(P, prec, name)554elif P[2] == 0:555return self.local_coordinates_at_infinity(prec, name)556else:557return self.local_coordinates_at_nonweierstrass(P, prec, name)558559560