Path: blob/master/src/sage/schemes/toric/weierstrass.py
8820 views
r"""1Weierstrass form of a toric elliptic curve.23There are 16 reflexive polygons in the plane, see4:func:`~sage.geometry.lattice_polytope.ReflexivePolytopes`. Each of5them defines a toric Fano variety. And each of them has a unique6crepant resolution to a smooth toric surface [CLSsurfaces]_ by7subdividing the face fan. An anticanonical hypersurface defines an8elliptic curve in this ambient space, which we call a toric elliptic9curve. The purpose of this module is to write an anticanonical10hypersurface equation in the short Weierstrass form `y^2 = x^3 + f x +11g`. This works over any base ring as long as its characteristic `\not=122,3`.1314For an analogous treatment of elliptic curves defined as complete15intersection in higher dimensional toric varieties, see16the module :mod:`~sage.schemes.toric.weierstrass_higher`.1718Technically, this module computes the Weierstrass form of the Jacobian19of the elliptic curve. This is why you will never have to specify the20origin (or zero section) in the following.2122It turns out [VolkerBraun]_ that the anticanonical hypersurface23equation of any one of the above 16 toric surfaces is a specialization24(that is, set one or more of the coefficients to zero) of the25following three cases. In inhomogeneous coordinates, they are2627* Cubic in `\mathbb{P}^2`:2829.. math::3031\begin{split}32p(x,y) =&\;33a_{30} x^{3} + a_{21} x^{2} y + a_{12} x y^{2} +34a_{03} y^{3} + a_{20} x^{2} +35\\ &\;36a_{11} x y +37a_{02} y^{2} + a_{10} x + a_{01} y + a_{00}38\end{split}3940* Biquadric in `\mathbb{P}^1\times \mathbb{P}^1`:4142.. math::4344\begin{split}45p(x,y) =&\;46a_{22} x^2 y^2 + a_{21} x^2 y + a_{20} x^2 +47a_{12} x y^2 +48\\ &\;49a_{11} x y + x a_{10} +50y^2 a_{02} + y a_{01} + a_{00}51\end{split}5253* Anticanonical hypersurface in weighted projective space54`\mathbb{P}^2[1,1,2]`:5556.. math::5758\begin{split}59p(x,y) =&\;60a_{40} x^4 +61a_{30} x^3 +62a_{21} x^2 y +63a_{20} x^2 +64\\ &\;65a_{11} x y +66a_{02} y^2 +67a_{10} x +68a_{01} y +69a_{00}70\end{split}7172EXAMPLES:7374The main functionality is provided by :func:`WeierstrassForm`, which75brings each of the above hypersurface equations into Weierstrass76form::7778sage: R.<x,y> = QQ[]79sage: cubic = x^3 + y^3 + 180sage: WeierstrassForm(cubic)81(0, -27/4)82sage: WeierstrassForm(x^4 + y^2 + 1)83(-4, 0)84sage: WeierstrassForm(x^2*y^2 + x^2 + y^2 + 1)85(-16/3, 128/27)8687Only the affine span of the Newton polytope of the polynomial88matters. For example::8990sage: R.<x,y,z> = QQ[]91sage: WeierstrassForm(x^3 + y^3 + z^3)92(0, -27/4)93sage: WeierstrassForm(x * cubic)94(0, -27/4)9596This allows you to work with either homogeneous or inhomogeneous97variables. For exmple, here is the del Pezzo surface of degree 8::9899sage: dP8 = toric_varieties.dP8()100sage: dP8.inject_variables()101Defining t, x, y, z102sage: WeierstrassForm(x*y^2 + y^2*z + t^2*x^3 + t^2*z^3)103(-3, -2)104sage: WeierstrassForm(x*y^2 + y^2 + x^3 + 1)105(-3, -2)106107By specifying only certain variables we can compute the Weierstrass108form over the polynomial ring generated by the remaining109variables. For example, here is a cubic over `\QQ[a]` ::110111sage: R.<a, x, y, z> = QQ[]112sage: cubic = x^3 + a*y^3 + a^2*z^3113sage: WeierstrassForm(cubic, variables=[x,y,z])114(0, -27/4*a^6)115116TESTS::117118sage: R.<f, g, x, y> = QQ[]119sage: cubic = -y^2 + x^3 + f*x + g120sage: WeierstrassForm(cubic, variables=[x,y])121(f, g)122123REFERENCES:124125.. [VolkerBraun]126Volker Braun:127Toric Elliptic Fibrations and F-Theory Compactifications128:arxiv:`1110.4883`129130.. [Duistermaat]131J. J. Duistermaat,132Discrete integrable systems. QRT maps and elliptic surfaces.133Springer Monographs in Mathematics. Berlin: Springer. xxii, 627 p., 2010134135.. [ArtinVillegasTate]136Michael Artin, Fernando Rodriguez-Villegas, John Tate,137On the Jacobians of plane cubics,138Advances in Mathematics 198 (2005) 1, pp. 366--382139:doi:`10.1016/j.aim.2005.06.004`140http://www.math.utexas.edu/users/villegas/publications/jacobian-cubics.pdf141142.. [CLSsurfaces]143Section 10.4 in144David A. Cox, John B. Little, Hal Schenck,145"Toric Varieties", Graduate Studies in Mathematics,146Amer. Math. Soc., Providence, RI, 2011147"""148149########################################################################150# Copyright (C) 2012 Volker Braun <[email protected]>151#152# Distributed under the terms of the GNU General Public License (GPL)153#154# http://www.gnu.org/licenses/155########################################################################156157from sage.misc.all import prod158from sage.rings.infinity import Infinity159from sage.modules.all import vector160from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL161from sage.rings.all import invariant_theory162163######################################################################164#165# Discriminant and j-invariant166#167######################################################################168169170def Discriminant(polynomial, variables=None):171r"""172The discriminant of the elliptic curve.173174INPUT:175176See :func:`WeierstrassForm` for how to specify the input177polynomial(s) and variables.178179OUTPUT:180181The discriminant of the elliptic curve.182183EXAMPLES::184185sage: from sage.schemes.toric.weierstrass import Discriminant186sage: R.<x, y, z> = QQ[]187sage: Discriminant(x^3+y^3+z^3)18819683/16189sage: Discriminant(x*y*z)1900191sage: R.<w,x,y,z> = QQ[]192sage: quadratic1 = w^2+x^2+y^2193sage: quadratic2 = z^2 + w*x194sage: Discriminant([quadratic1, quadratic2])195-1/16196"""197(f, g) = WeierstrassForm(polynomial, variables)198return 4*f**3+27*g**2199200201######################################################################202def j_invariant(polynomial, variables=None):203r"""204Return the `j`-invariant of the elliptic curve.205206INPUT:207208See :func:`WeierstrassForm` for how to specify the input209polynomial(s) and variables.210211OUTPUT:212213The j-invariant of the (irreducible) cubic. Notable special values:214215* The Fermat cubic: `j(x^3+y^3+z^3) = 0`216217* A nodal cubic: `j(-y^2 + x^2 + x^3) = \infty`218219* A cuspidal cubic `y^2=x^3` has undefined `j`-invariant. In this220case, a ``ValueError`` is returned.221222EXAMPLES::223224sage: from sage.schemes.toric.weierstrass import j_invariant225sage: R.<x,y,z> = QQ[]226sage: j_invariant(x^3+y^3+z^3)2270228sage: j_invariant(-y^2 + x^2 + x^3)229+Infinity230sage: R.<x,y,z, a,b> = QQ[]231sage: j_invariant( -y^2*z + x^3 + a*x*z^2, [x,y,z])2321728233234TESTS::235236sage: j_invariant(x*y*z)237Traceback (most recent call last):238...239ValueError: curve is singular and has no well-defined j-invariant240"""241(f, g) = WeierstrassForm(polynomial, variables)242disc = 4*f**3+27*g**2243if disc != 0:244return 1728 * 4*f**3/disc245if f != 0:246return Infinity247raise ValueError('curve is singular and has no well-defined j-invariant')248249250######################################################################251#252# Weierstrass form of any elliptic curve253#254######################################################################255def Newton_polytope_vars_coeffs(polynomial, variables):256"""257Return the Newton polytope in the given variables.258259INPUT:260261See :func:`WeierstrassForm` for how to specify the input262polynomial and variables.263264OUTPUT:265266A tuple containing of the affine span of the Netwton polytope and267a dictionary with keys the integral values of the Newton polytope268and values the corresponding coefficient of ``polynomial``.269270EXAMPLES::271272sage: from sage.schemes.toric.weierstrass import Newton_polytope_vars_coeffs273sage: R.<x,y,z,a30,a21,a12,a03,a20,a11,a02,a10,a01,a00> = QQ[]274sage: p = (a30*x^3 + a21*x^2*y + a12*x*y^2 + a03*y^3 + a20*x^2*z +275....: a11*x*y*z + a02*y^2*z + a10*x*z^2 + a01*y*z^2 + a00*z^3)276sage: p_data = Newton_polytope_vars_coeffs(p, [x,y,z]); p_data277{(2, 1, 0): a21, (0, 3, 0): a03, (1, 0, 2): a10, (0, 2, 1): a02,278(0, 1, 2): a01, (3, 0, 0): a30, (2, 0, 1): a20, (1, 2, 0): a12,279(1, 1, 1): a11, (0, 0, 3): a00}280281sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL282sage: polytope = LatticePolytope_PPL(p_data.keys()); polytope283A 2-dimensional lattice polytope in ZZ^3 with 3 vertices284sage: polytope.vertices()285((0, 0, 3), (3, 0, 0), (0, 3, 0))286sage: polytope.embed_in_reflexive_polytope()287The map A*x+b with A=288[-1 -1]289[ 0 1]290[ 1 0]291b =292(3, 0, 0)293"""294R = polynomial.parent()295var_indices = [R.gens().index(x) for x in variables]296result = dict()297for c, m in polynomial:298e = m.exponents()[0]299v = tuple([e[i] for i in var_indices])300m_red = m // prod(x**i for x, i in zip(variables, v))301result[v] = result.get(v, R.zero()) + c*m_red302return result303304305######################################################################306def Newton_polygon_embedded(polynomial, variables):307r"""308Embed the Newton polytope of the polynomial in one of the three309maximal reflexive polygons.310311This function is a helper for :func:`WeierstrassForm`312313INPUT:314315Same as :func:`WeierstrassForm` with only a single polynomial passed.316317OUTPUT:318319A tuple `(\Delta, P, (x,y))` where320321* `\Delta` is the Newton polytope of ``polynomial``.322323* `P(x,y)` equals the input ``polynomial`` but with redefined variables324such that its Newton polytope is `\Delta`.325326EXAMPLES::327328sage: from sage.schemes.toric.weierstrass import Newton_polygon_embedded329sage: R.<x,y,z> = QQ[]330sage: cubic = x^3 + y^3 + z^3331sage: Newton_polygon_embedded(cubic, [x,y,z])332(A 2-dimensional lattice polytope in ZZ^3 with 3 vertices,333x^3 + y^3 + 1,334(x, y))335336sage: R.<a, x,y,z> = QQ[]337sage: cubic = x^3 + a*y^3 + a^2*z^3338sage: Newton_polygon_embedded(cubic, variables=[x,y,z])339(A 2-dimensional lattice polytope in ZZ^3 with 3 vertices,340a^2*x^3 + y^3 + a,341(x, y))342343sage: R.<s,t,x,y> = QQ[]344sage: biquadric = (s+t)^2 * (x+y)^2345sage: Newton_polygon_embedded(biquadric, [s,t,x,y])346(A 2-dimensional lattice polytope in ZZ^4 with 4 vertices,347s^2*t^2 + 2*s^2*t + 2*s*t^2 + s^2 + 4*s*t + t^2 + 2*s + 2*t + 1,348(s, t))349"""350p_dict = Newton_polytope_vars_coeffs(polynomial, variables)351newton_polytope = LatticePolytope_PPL(p_dict.keys())352assert newton_polytope.affine_dimension() <= 2353embedding = newton_polytope.embed_in_reflexive_polytope('points')354x, y = variables[0:2]355embedded_polynomial = polynomial.parent().zero()356for e, c in p_dict.iteritems():357e_embed = embedding[e]358embedded_polynomial += c * x**(e_embed[0]) * y**(e_embed[1])359return newton_polytope, embedded_polynomial, (x, y)360361362######################################################################363def WeierstrassForm(polynomial, variables=None, transformation=False):364r"""365Return the Weierstrass form of an elliptic curve inside either366inside a toric surface or $\mathbb{P}^3$.367368INPUT:369370- ``polynomial`` -- either a polynomial or a list of polynomials371defining the elliptic curve.372A single polynomial can be either a cubic, a biquadric, or the373hypersurface in `\mathbb{P}^2[1,1,2]`. In this case the374equation need not be in any standard form, only its Newton375polyhedron is used.376If two polynomials are passed, they must both be quadratics in377`\mathbb{P}^3`.378379- ``variables`` -- a list of variables of the parent polynomial380ring or ``None`` (default). In the latter case, all variables381are taken to be polynomial ring variables. If a subset of382polynomial ring variables are given, the Weierstrass form is383determined over the function field generated by the remaining384variables.385386- ``transformation`` -- boolean (default: ``False``). Whether to387return the new variables that bring ``polynomial`` into388Weierstrass form.389390OUTPUT:391392The pair of coefficients `(f,g)` of the Weierstrass form `y^2 =393x^3 + f x + g` of the hypersurface equation.394395If ``transformation=True``, a triple `(X,Y,Z)` of polynomials396defining a rational map of the toric hypersurface or complete397intersection in `\mathbb{P}^3` to its Weierstrass form in398`\mathbb{P}^2[2,3,1]` is returned.399That is, the triple satisfies400401.. math::402403Y^2 = X^3 + f X Z^4 + g Z^6404405when restricted to the toric hypersurface or complete intersection.406407EXAMPLES::408409sage: R.<x,y,z> = QQ[]410sage: cubic = x^3 + y^3 + z^3411sage: f, g = WeierstrassForm(cubic); (f, g)412(0, -27/4)413414Same in inhomogeneous coordinates::415416sage: R.<x,y> = QQ[]417sage: cubic = x^3 + y^3 + 1418sage: f, g = WeierstrassForm(cubic); (f, g)419(0, -27/4)420421sage: X,Y,Z = WeierstrassForm(cubic, transformation=True); (X,Y,Z)422(-x^3*y^3 - x^3 - y^3,4231/2*x^6*y^3 - 1/2*x^3*y^6 - 1/2*x^6 + 1/2*y^6 + 1/2*x^3 - 1/2*y^3,424x*y)425426Note that plugging in `[X:Y:Z]` to the Weierstrass equation is a427complicated polynomial, but contains the hypersurface equation as428a factor::429430sage: -Y^2 + X^3 + f*X*Z^4 + g*Z^6431-1/4*x^12*y^6 - 1/2*x^9*y^9 - 1/4*x^6*y^12 + 1/2*x^12*y^3432- 7/2*x^9*y^6 - 7/2*x^6*y^9 + 1/2*x^3*y^12 - 1/4*x^12 - 7/2*x^9*y^3433- 45/4*x^6*y^6 - 7/2*x^3*y^9 - 1/4*y^12 - 1/2*x^9 - 7/2*x^6*y^3434- 7/2*x^3*y^6 - 1/2*y^9 - 1/4*x^6 + 1/2*x^3*y^3 - 1/4*y^6435sage: cubic.divides(-Y^2 + X^3 + f*X*Z^4 + g*Z^6)436True437438Only the affine span of the Newton polytope of the polynomial439matters. For example::440441sage: R.<x,y,z> = QQ[]442sage: cubic = x^3 + y^3 + z^3443sage: WeierstrassForm(cubic.subs(z=1))444(0, -27/4)445sage: WeierstrassForm(x * cubic)446(0, -27/4)447448This allows you to work with either homogeneous or inhomogeneous449variables. For example, here is the del Pezzo surface of degree 8::450451sage: dP8 = toric_varieties.dP8()452sage: dP8.inject_variables()453Defining t, x, y, z454sage: WeierstrassForm(x*y^2 + y^2*z + t^2*x^3 + t^2*z^3)455(-3, -2)456sage: WeierstrassForm(x*y^2 + y^2 + x^3 + 1)457(-3, -2)458459By specifying only certain variables we can compute the460Weierstrass form over the function field generated by the461remaining variables. For example, here is a cubic over `\QQ[a]` ::462463sage: R.<a, x,y,z> = QQ[]464sage: cubic = x^3 + a*y^3 + a^2*z^3465sage: WeierstrassForm(cubic, variables=[x,y,z])466(0, -27/4*a^6)467468TESTS::469470sage: for P in ReflexivePolytopes(2):471....: S = ToricVariety(FaceFan(P))472....: p = sum((-S.K()).sections_monomials())473....: print WeierstrassForm(p)474(-25/48, -1475/864)475(-97/48, 17/864)476(-25/48, -611/864)477(-27/16, 27/32)478(47/48, -199/864)479(47/48, -71/864)480(5/16, -21/32)481(23/48, -235/864)482(-1/48, 161/864)483(-25/48, 253/864)484(5/16, 11/32)485(-25/48, 125/864)486(-67/16, 63/32)487(-11/16, 3/32)488(-241/48, 3689/864)489(215/48, -5291/864)490"""491if isinstance(polynomial, (list, tuple)):492from sage.schemes.toric.weierstrass_higher import WeierstrassForm2493return WeierstrassForm2(polynomial, variables=variables, transformation=transformation)494if transformation:495from sage.schemes.toric.weierstrass_covering import WeierstrassMap496return WeierstrassMap(polynomial, variables=variables)497if variables is None:498variables = polynomial.variables()499from sage.geometry.polyhedron.ppl_lattice_polygon import (500polar_P2_polytope, polar_P1xP1_polytope, polar_P2_112_polytope)501newton_polytope, polynomial, variables = \502Newton_polygon_embedded(polynomial, variables)503polygon = newton_polytope.embed_in_reflexive_polytope('polytope')504if polygon is polar_P2_polytope():505return WeierstrassForm_P2(polynomial, variables)506if polygon is polar_P1xP1_polytope():507return WeierstrassForm_P1xP1(polynomial, variables)508if polygon is polar_P2_112_polytope():509return WeierstrassForm_P2_112(polynomial, variables)510raise ValueError('Newton polytope is not contained in a reflexive polygon')511512513######################################################################514#515# Weierstrass form of cubic in P^2516#517######################################################################518def _check_homogeneity(polynomial, variables, weights, total_weight=None):519"""520Raise ``ValueError`` if the polynomial is not weighted521homogeneous.522523INPUT:524525- ``polynomial`` -- the input polynomial. See526:func:`WeierstrassForm` for details.527528- ``variables`` -- the variables. See :func:`WeierstrassForm` for529details.530531- ``weights`` -- list of integers, one per variable. the weights532of the variables.533534- ``total_weight`` -- an integer or ``None`` (default). If an535integer is passed, it is also checked that the weighted total536degree of polynomial is this value.537538OUTPUT:539540This function returns nothing. If the polynomial is not weighted541homogeneous, a ``ValueError`` is raised.542543EXAMPLES::544545sage: from sage.schemes.toric.weierstrass import _check_homogeneity546sage: R.<x,y,z,a30,a21,a12,a03,a20,a11,a02,a10,a01,a00> = QQ[]547sage: p = (a30*x^3 + a21*x^2*y + a12*x*y^2 + a03*y^3 + a20*x^2*z +548....: a11*x*y*z + a02*y^2*z + a10*x*z^2 + a01*y*z^2 + a00*z^3)549sage: _check_homogeneity(p, [x,y,z], (1,1,1), 3)550551sage: _check_homogeneity(p+x^4, [x,y,z], (1,1,1), 3)552Traceback (most recent call last):553...554ValueError: The polynomial is not homogeneous with weights (1, 1, 1)555"""556w = vector(weights)557n = w.degree()558all_variables = polynomial.parent().gens()559variable_indices = [all_variables.index(x) for x in variables]560total_weight = None561for e in polynomial.exponents():562weight_e = sum(e[variable_indices[i]] * weights[i] for i in range(n))563if total_weight is None:564total_weight = weight_e565else:566if weight_e != total_weight:567raise ValueError('The polynomial is not homogeneous with '568'weights '+str(weights))569570571######################################################################572def _extract_coefficients(polynomial, monomials, variables):573"""574Return the coefficients of ``monomials``.575576INPUT:577578- ``polynomial`` -- the input polynomial579580- ``monomials`` -- a list of monomials in the polynomial ring581582- ``variables`` -- a list of variables in the polynomial ring583584OUTPUT:585586A tuple containing the coefficients of the monomials in the given587polynomial.588589EXAMPLES::590591sage: from sage.schemes.toric.weierstrass import _extract_coefficients592sage: R.<x,y,z,a30,a21,a12,a03,a20,a11,a02,a10,a01,a00> = QQ[]593sage: p = (a30*x^3 + a21*x^2*y + a12*x*y^2 + a03*y^3 + a20*x^2*z +594....: a11*x*y*z + a02*y^2*z + a10*x*z^2 + a01*y*z^2 + a00*z^3)595sage: m = [x^3, y^3, z^3, x^2*y, x^2*z, x*y^2, y^2*z, x*z^2, y*z^2, x*y*z]596sage: _extract_coefficients(p, m, [x,y,z])597(a30, a03, a00, a21, a20, a12, a02, a10, a01, a11)598599sage: m = [x^3, y^3, 1, x^2*y, x^2, x*y^2, y^2, x, y, x*y]600sage: _extract_coefficients(p.subs(z=1), m, [x,y])601(a30, a03, a00, a21, a20, a12, a02, a10, a01, a11)602"""603R = polynomial.parent()604indices = [R.gens().index(x) for x in variables]605606def index(monomial):607if monomial in R.base_ring():608return tuple(0 for i in indices)609e = monomial.exponents()[0]610return tuple(e[i] for i in indices)611coeffs = dict()612for c, m in polynomial:613i = index(m)614coeffs[i] = c*m + coeffs.pop(i, R.zero())615result = tuple(coeffs.pop(index(m), R.zero()) // m for m in monomials)616if len(coeffs) != 0:617raise ValueError('The polynomial contains more monomials than '618'given: '+str(coeffs))619return result620621622######################################################################623def _check_polynomial_P2(cubic, variables):624"""625Check the polynomial is weighted homogeneous in standard variables.626627INPUT:628629- ``cubic`` -- the input polynomial. See630:func:`WeierstrassForm` for details.631632- ``variables`` -- the variables or ``None``. See633:func:`WeierstrassForm` for details.634635OUTPUT:636637This functions returns ``variables``, potentially guessed from the638polynomial ring. A ``ValueError`` is raised if the polynomial is639not homogeneous.640641EXAMPLES:642643sage: from sage.schemes.toric.weierstrass import _check_polynomial_P2644sage: R.<x,y,z> = QQ[]645sage: cubic = x^3+y^3+z^3646sage: _check_polynomial_P2(cubic, [x,y,z])647(x, y, z)648sage: _check_polynomial_P2(cubic, None)649(x, y, z)650sage: _check_polynomial_P2(cubic.subs(z=1), None)651(x, y, None)652sage: R.<x,y,z,t> = QQ[]653sage: cubic = x^3+y^3+z^3 + t*x*y*z654sage: _check_polynomial_P2(cubic, [x,y,z])655(x, y, z)656sage: _check_polynomial_P2(cubic, [x,y,t])657Traceback (most recent call last):658...659ValueError: The polynomial is not homogeneous with weights (1, 1, 1)660"""661if variables is None:662variables = cubic.variables()663if len(variables) == 3:664x, y, z = variables665_check_homogeneity(cubic, [x, y, z], (1, 1, 1), 3)666elif len(variables) == 2:667x, y = variables668z = None669else:670raise ValueError('Need two or three variables, got '+str(variables))671return (x, y, z)672673674######################################################################675def WeierstrassForm_P2(polynomial, variables=None):676r"""677Bring a cubic into Weierstrass form.678679Input/output is the same as :func:`WeierstrassForm`, except that680the input polynomial must be a standard cubic in `\mathbb{P}^2`,681682.. math::683684\begin{split}685p(x,y) =&\;686a_{30} x^{3} + a_{21} x^{2} y + a_{12} x y^{2} +687a_{03} y^{3} + a_{20} x^{2} +688\\ &\;689a_{11} x y +690a_{02} y^{2} + a_{10} x + a_{01} y + a_{00}691\end{split}692693EXAMPLES::694695sage: from sage.schemes.toric.weierstrass import WeierstrassForm_P2696sage: R.<x,y,z> = QQ[]697sage: WeierstrassForm_P2( x^3+y^3+z^3 )698(0, -27/4)699700sage: R.<x,y,z, a,b> = QQ[]701sage: WeierstrassForm_P2( -y^2*z+x^3+a*x*z^2+b*z^3, [x,y,z] )702(a, b)703704TESTS::705706sage: R.<x,y,z,a30,a21,a12,a03,a20,a11,a02,a10,a01,a00> = QQ[]707sage: p = ( a30*x^3 + a21*x^2*y + a12*x*y^2 + a03*y^3 + a20*x^2*z +708....: a11*x*y*z + a02*y^2*z + a10*x*z^2 + a01*y*z^2 + a00*z^3 )709sage: WeierstrassForm_P2(p, [x,y,z])710(-1/48*a11^4 + 1/6*a20*a11^2*a02 - 1/3*a20^2*a02^2 - 1/2*a03*a20*a11*a10711+ 1/6*a12*a11^2*a10 + 1/3*a12*a20*a02*a10 - 1/2*a21*a11*a02*a10712+ a30*a02^2*a10 - 1/3*a12^2*a10^2 + a21*a03*a10^2 + a03*a20^2*a01713- 1/2*a12*a20*a11*a01 + 1/6*a21*a11^2*a01 + 1/3*a21*a20*a02*a01714- 1/2*a30*a11*a02*a01 + 1/3*a21*a12*a10*a01 - 3*a30*a03*a10*a01715- 1/3*a21^2*a01^2 + a30*a12*a01^2 + a12^2*a20*a00 - 3*a21*a03*a20*a00716- 1/2*a21*a12*a11*a00 + 9/2*a30*a03*a11*a00 + a21^2*a02*a00717- 3*a30*a12*a02*a00,7181/864*a11^6 - 1/72*a20*a11^4*a02 + 1/18*a20^2*a11^2*a02^2719- 2/27*a20^3*a02^3 + 1/24*a03*a20*a11^3*a10 - 1/72*a12*a11^4*a10720- 1/6*a03*a20^2*a11*a02*a10 + 1/36*a12*a20*a11^2*a02*a10721+ 1/24*a21*a11^3*a02*a10 + 1/9*a12*a20^2*a02^2*a10722- 1/6*a21*a20*a11*a02^2*a10 - 1/12*a30*a11^2*a02^2*a10723+ 1/3*a30*a20*a02^3*a10 + 1/4*a03^2*a20^2*a10^2724- 1/6*a12*a03*a20*a11*a10^2 + 1/18*a12^2*a11^2*a10^2725- 1/12*a21*a03*a11^2*a10^2 + 1/9*a12^2*a20*a02*a10^2726- 1/6*a21*a03*a20*a02*a10^2 - 1/6*a21*a12*a11*a02*a10^2727+ a30*a03*a11*a02*a10^2 + 1/4*a21^2*a02^2*a10^2728- 2/3*a30*a12*a02^2*a10^2 - 2/27*a12^3*a10^3 + 1/3*a21*a12*a03*a10^3729- a30*a03^2*a10^3 - 1/12*a03*a20^2*a11^2*a01 + 1/24*a12*a20*a11^3*a01730- 1/72*a21*a11^4*a01 + 1/3*a03*a20^3*a02*a01 - 1/6*a12*a20^2*a11*a02*a01731+ 1/36*a21*a20*a11^2*a02*a01 + 1/24*a30*a11^3*a02*a01732+ 1/9*a21*a20^2*a02^2*a01 - 1/6*a30*a20*a11*a02^2*a01733- 1/6*a12*a03*a20^2*a10*a01 - 1/6*a12^2*a20*a11*a10*a01734+ 5/6*a21*a03*a20*a11*a10*a01 + 1/36*a21*a12*a11^2*a10*a01735- 3/4*a30*a03*a11^2*a10*a01 + 1/18*a21*a12*a20*a02*a10*a01736- 3/2*a30*a03*a20*a02*a10*a01 - 1/6*a21^2*a11*a02*a10*a01737+ 5/6*a30*a12*a11*a02*a10*a01 - 1/6*a30*a21*a02^2*a10*a01738+ 1/9*a21*a12^2*a10^2*a01 - 2/3*a21^2*a03*a10^2*a01739+ a30*a12*a03*a10^2*a01 + 1/4*a12^2*a20^2*a01^2740- 2/3*a21*a03*a20^2*a01^2 - 1/6*a21*a12*a20*a11*a01^2741+ a30*a03*a20*a11*a01^2 + 1/18*a21^2*a11^2*a01^2742- 1/12*a30*a12*a11^2*a01^2 + 1/9*a21^2*a20*a02*a01^2743- 1/6*a30*a12*a20*a02*a01^2 - 1/6*a30*a21*a11*a02*a01^2744+ 1/4*a30^2*a02^2*a01^2 + 1/9*a21^2*a12*a10*a01^2745- 2/3*a30*a12^2*a10*a01^2 + a30*a21*a03*a10*a01^2746- 2/27*a21^3*a01^3 + 1/3*a30*a21*a12*a01^3 - a30^2*a03*a01^3747- a03^2*a20^3*a00 + a12*a03*a20^2*a11*a00 - 1/12*a12^2*a20*a11^2*a00748- 3/4*a21*a03*a20*a11^2*a00 + 1/24*a21*a12*a11^3*a00749+ 5/8*a30*a03*a11^3*a00 - 2/3*a12^2*a20^2*a02*a00750+ a21*a03*a20^2*a02*a00 + 5/6*a21*a12*a20*a11*a02*a00751- 3/2*a30*a03*a20*a11*a02*a00 - 1/12*a21^2*a11^2*a02*a00752- 3/4*a30*a12*a11^2*a02*a00 - 2/3*a21^2*a20*a02^2*a00753+ a30*a12*a20*a02^2*a00 + a30*a21*a11*a02^2*a00754- a30^2*a02^3*a00 + 1/3*a12^3*a20*a10*a00755- 3/2*a21*a12*a03*a20*a10*a00 + 9/2*a30*a03^2*a20*a10*a00756- 1/6*a21*a12^2*a11*a10*a00 + a21^2*a03*a11*a10*a00757- 3/2*a30*a12*a03*a11*a10*a00 - 1/6*a21^2*a12*a02*a10*a00758+ a30*a12^2*a02*a10*a00 - 3/2*a30*a21*a03*a02*a10*a00759- 1/6*a21*a12^2*a20*a01*a00 + a21^2*a03*a20*a01*a00760- 3/2*a30*a12*a03*a20*a01*a00 - 1/6*a21^2*a12*a11*a01*a00761+ a30*a12^2*a11*a01*a00 - 3/2*a30*a21*a03*a11*a01*a00762+ 1/3*a21^3*a02*a01*a00 - 3/2*a30*a21*a12*a02*a01*a00763+ 9/2*a30^2*a03*a02*a01*a00 + 1/4*a21^2*a12^2*a00^2764- a30*a12^3*a00^2 - a21^3*a03*a00^2765+ 9/2*a30*a21*a12*a03*a00^2 - 27/4*a30^2*a03^2*a00^2)766"""767x, y, z = _check_polynomial_P2(polynomial, variables)768cubic = invariant_theory.ternary_cubic(polynomial, x, y, z)769F = polynomial.base_ring()770S = cubic.S_invariant()771T = cubic.T_invariant()772return (27*S, -27/F(4)*T)773774775######################################################################776#777# Weierstrass form of biquadric in P1 x P1778#779######################################################################780def _check_polynomial_P1xP1(biquadric, variables):781"""782Check the polynomial is weighted homogeneous in standard variables.783784INPUT:785786- ``biquadric`` -- the input polynomial. See787:func:`WeierstrassForm` for details.788789- ``variables`` -- the variables or ``None``. See790:func:`WeierstrassForm` for details.791792OUTPUT:793794This functions returns ``variables``, potentially guessed from the795polynomial ring. A ``ValueError`` is raised if the polynomial is796not homogeneous.797798EXAMPLES::799800sage: from sage.schemes.toric.weierstrass import _check_polynomial_P1xP1801sage: R.<x0,x1,y0,y1> = QQ[]802sage: biquadric = ( x0^2*y0^2 + x0*x1*y0^2*2 + x1^2*y0^2*3803....: + x0^2*y0*y1*4 + x0*x1*y0*y1*5 + x1^2*y0*y1*6804....: + x0^2*y1^2*7 + x0*x1*y1^2*8 )805sage: _check_polynomial_P1xP1(biquadric, [x0,x1,y0,y1])806[x0, x1, y0, y1]807sage: _check_polynomial_P1xP1(biquadric, None)808(x0, x1, y0, y1)809sage: _check_polynomial_P1xP1(biquadric.subs(y0=1, y1=1), None)810[x0, None, x1, None]811sage: _check_polynomial_P1xP1(biquadric, [x0,y0,x1,y1])812Traceback (most recent call last):813...814ValueError: The polynomial is not homogeneous with weights (1, 1, 0, 0)815"""816if variables is None:817variables = biquadric.variables()818if len(variables) == 4:819_check_homogeneity(biquadric, variables, (1, 1, 0, 0), 2)820_check_homogeneity(biquadric, variables, (0, 0, 1, 1), 2)821elif len(variables) == 2:822variables = [variables[0], None, variables[1], None]823else:824raise ValueError('Need two or four variables, got '+str(variables))825return variables826827828######################################################################829def _partial_discriminant(quadric, y0, y1=None):830"""831Return the partial discriminant wrt. `(y_0, y_1)`.832833INPUT:834835- ``quadric`` -- a biquadric.836837- ``y_0``, ``y_1`` -- the variables of the quadric. The ``y_1``838variable can be omitted if the quadric is inhomogeneous.839840OUTPUT:841842A plane quartic in ``x0``, ``x1``.843844EXAMPLES::845846sage: R.<x0,x1,y0,y1,a00,a10,a20,a01,a11,a21,a02,a12,a22> = QQ[]847sage: biquadric = ( x0^2*y0^2*a00 + x0*x1*y0^2*a10 + x1^2*y0^2*a20848....: + x0^2*y0*y1*a01 + x0*x1*y0*y1*a11 + x1^2*y0*y1*a21849....: + x0^2*y1^2*a02 + x0*x1*y1^2*a12 + x1^2*y1^2*a22 )850sage: from sage.schemes.toric.weierstrass import _partial_discriminant851sage: _partial_discriminant(biquadric, y0, y1)852x0^4*a01^2 + 2*x0^3*x1*a01*a11 + x0^2*x1^2*a11^2853+ 2*x0^2*x1^2*a01*a21 + 2*x0*x1^3*a11*a21 + x1^4*a21^2854- 4*x0^4*a00*a02 - 4*x0^3*x1*a10*a02 - 4*x0^2*x1^2*a20*a02855- 4*x0^3*x1*a00*a12 - 4*x0^2*x1^2*a10*a12 - 4*x0*x1^3*a20*a12856- 4*x0^2*x1^2*a00*a22 - 4*x0*x1^3*a10*a22 - 4*x1^4*a20*a22857sage: _partial_discriminant(biquadric, x0, x1)858y0^4*a10^2 - 4*y0^4*a00*a20 - 4*y0^3*y1*a20*a01859+ 2*y0^3*y1*a10*a11 + y0^2*y1^2*a11^2 - 4*y0^3*y1*a00*a21860- 4*y0^2*y1^2*a01*a21 - 4*y0^2*y1^2*a20*a02 - 4*y0*y1^3*a21*a02861+ 2*y0^2*y1^2*a10*a12 + 2*y0*y1^3*a11*a12 + y1^4*a12^2862- 4*y0^2*y1^2*a00*a22 - 4*y0*y1^3*a01*a22 - 4*y1^4*a02*a22863"""864if y1 is None:865monomials = (quadric.parent().one(), y0, y0**2)866variables = [y0]867else:868monomials = (y1**2, y0*y1, y0**2)869variables = [y0, y1]870c = _extract_coefficients(quadric, monomials, variables)871return c[1]**2 - 4*c[0]*c[2]872873874######################################################################875def WeierstrassForm_P1xP1(biquadric, variables=None):876r"""877Bring a biquadric into Weierstrass form878879Input/output is the same as :func:`WeierstrassForm`, except that880the input polynomial must be a standard biquadric in `\mathbb{P}^2`,881882.. math::883884\begin{split}885p(x,y) =&\;886a_{40} x^4 +887a_{30} x^3 +888a_{21} x^2 y +889a_{20} x^2 +890\\ &\;891a_{11} x y +892a_{02} y^2 +893a_{10} x +894a_{01} y +895a_{00}896\end{split}897898EXAMPLES::899900sage: from sage.schemes.toric.weierstrass import WeierstrassForm_P1xP1901sage: R.<x0,x1,y0,y1>= QQ[]902sage: biquadric = ( x0^2*y0^2 + x0*x1*y0^2*2 + x1^2*y0^2*3903....: + x0^2*y0*y1*4 + x0*x1*y0*y1*5 + x1^2*y0*y1*6904....: + x0^2*y1^2*7 + x0*x1*y1^2*8 )905sage: WeierstrassForm_P1xP1(biquadric, [x0, x1, y0, y1])906(1581/16, -3529/32)907908Since there is no `x_1^2 y_1^2` term in ``biquadric``, we can909dehomogenize it and get a cubic::910911sage: from sage.schemes.toric.weierstrass import WeierstrassForm_P2912sage: WeierstrassForm_P2(biquadric(x0=1,y0=1))913(1581/16, -3529/32)914915TESTS::916917sage: R.<x0,x1,y0,y1,a00,a10,a20,a01,a11,a21,a02,a12,a22> = QQ[]918sage: biquadric = ( x0^2*y0^2*a00 + x0*x1*y0^2*a10 + x1^2*y0^2*a20919....: + x0^2*y0*y1*a01 + x0*x1*y0*y1*a11 + x1^2*y0*y1*a21920....: + x0^2*y1^2*a02 + x0*x1*y1^2*a12 )921sage: WeierstrassForm_P1xP1(biquadric, [x0, x1, y0, y1])922(-1/48*a11^4 + 1/6*a01*a11^2*a21 - 1/3*a01^2*a21^2923+ 1/6*a20*a11^2*a02 + 1/3*a20*a01*a21*a02 - 1/2*a10*a11*a21*a02924+ a00*a21^2*a02 - 1/3*a20^2*a02^2 - 1/2*a20*a01*a11*a12925+ 1/6*a10*a11^2*a12 + 1/3*a10*a01*a21*a12 - 1/2*a00*a11*a21*a12926+ 1/3*a10*a20*a02*a12 - 1/3*a10^2*a12^2 + a00*a20*a12^2, 1/864*a11^6927- 1/72*a01*a11^4*a21 + 1/18*a01^2*a11^2*a21^2 - 2/27*a01^3*a21^3928- 1/72*a20*a11^4*a02 + 1/36*a20*a01*a11^2*a21*a02929+ 1/24*a10*a11^3*a21*a02 + 1/9*a20*a01^2*a21^2*a02930- 1/6*a10*a01*a11*a21^2*a02 - 1/12*a00*a11^2*a21^2*a02931+ 1/3*a00*a01*a21^3*a02 + 1/18*a20^2*a11^2*a02^2932+ 1/9*a20^2*a01*a21*a02^2 - 1/6*a10*a20*a11*a21*a02^2933+ 1/4*a10^2*a21^2*a02^2 - 2/3*a00*a20*a21^2*a02^2 - 2/27*a20^3*a02^3934+ 1/24*a20*a01*a11^3*a12 - 1/72*a10*a11^4*a12935- 1/6*a20*a01^2*a11*a21*a12 + 1/36*a10*a01*a11^2*a21*a12936+ 1/24*a00*a11^3*a21*a12 + 1/9*a10*a01^2*a21^2*a12937- 1/6*a00*a01*a11*a21^2*a12 - 1/6*a20^2*a01*a11*a02*a12938+ 1/36*a10*a20*a11^2*a02*a12 + 1/18*a10*a20*a01*a21*a02*a12939- 1/6*a10^2*a11*a21*a02*a12 + 5/6*a00*a20*a11*a21*a02*a12940- 1/6*a00*a10*a21^2*a02*a12 + 1/9*a10*a20^2*a02^2*a12941+ 1/4*a20^2*a01^2*a12^2 - 1/6*a10*a20*a01*a11*a12^2942+ 1/18*a10^2*a11^2*a12^2 - 1/12*a00*a20*a11^2*a12^2943+ 1/9*a10^2*a01*a21*a12^2 - 1/6*a00*a20*a01*a21*a12^2944- 1/6*a00*a10*a11*a21*a12^2 + 1/4*a00^2*a21^2*a12^2945+ 1/9*a10^2*a20*a02*a12^2 - 2/3*a00*a20^2*a02*a12^2946- 2/27*a10^3*a12^3 + 1/3*a00*a10*a20*a12^3)947948sage: _ == WeierstrassForm_P1xP1(biquadric.subs(x1=1,y1=1), [x0, y0])949True950"""951x, y, s, t = _check_polynomial_P1xP1(biquadric, variables)952delta = _partial_discriminant(biquadric, s, t)953Q = invariant_theory.binary_quartic(delta, x, y)954g2 = Q.EisensteinD()955g3 = -Q.EisensteinE()956return (-g2/4, -g3/4)957958959######################################################################960#961# Weierstrass form of anticanonical hypersurface in WP2[1,1,2]962#963######################################################################964def _check_polynomial_P2_112(polynomial, variables):965"""966Check the polynomial is weighted homogeneous in standard variables.967968INPUT:969970- ``polynomial`` -- the input polynomial. See971:func:`WeierstrassForm` for details.972973- ``variables`` -- the variables or ``None``. See974:func:`WeierstrassForm` for details.975976OUTPUT:977978This functions returns ``variables``, potentially guessed from the979polynomial ring. A ``ValueError`` is raised if the polynomial is980not homogeneous.981982EXAMPLES:983984sage: from sage.schemes.toric.weierstrass import _check_polynomial_P2_112985sage: R.<x,y,z,t> = QQ[]986sage: polynomial = z^4*t^2 + x*z^3*t^2 + x^2*z^2*t^2 + x^3*z*t^2 + \987....: x^4*t^2 + y*z^2*t + x*y*z*t + x^2*y*t + y^2988sage: _check_polynomial_P2_112(polynomial, [x,y,z,t])989(x, y, z, t)990sage: _check_polynomial_P2_112(polynomial, None)991(x, y, z, t)992sage: _check_polynomial_P2_112(polynomial(z=1, t=1), None)993(x, y, None, None)994sage: _check_polynomial_P2_112(polynomial, [x,y,t,z])995Traceback (most recent call last):996...997ValueError: The polynomial is not homogeneous with weights (1, 0, 1, -2)998"""999if variables is None:1000variables = polynomial.variables()1001else:1002variables = tuple(variables)1003if len(variables) == 4:1004_check_homogeneity(polynomial, variables, (1, 0, 1, -2), 0)1005_check_homogeneity(polynomial, variables, (0, 1, 0, 1), 2)1006elif len(variables) == 2:1007variables = tuple([variables[0], variables[1], None, None])1008else:1009raise ValueError('Need two or four variables, got '+str(variables))1010return variables101110121013def WeierstrassForm_P2_112(polynomial, variables=None):1014r"""1015Bring an anticanonical hypersurface in `\mathbb{P}^2[1,1,2]` into Weierstrass form.10161017Input/output is the same as :func:`WeierstrassForm`, except that1018the input polynomial must be a standard anticanonical hypersurface1019in weighted projective space `\mathbb{P}^2[1,1,2]`:10201021.. math::10221023\begin{split}1024p(x,y) =&\;1025a_{40} x^4 +1026a_{30} x^3 +1027a_{21} x^2 y +1028a_{20} x^2 +1029\\ &\;1030a_{11} x y +1031a_{02} y^2 +1032a_{10} x +1033a_{01} y +1034a_{00}1035\end{split}10361037EXAMPLES::10381039sage: from sage.schemes.toric.weierstrass import WeierstrassForm_P2_1121040sage: fan = Fan(rays=[(1,0),(0,1),(-1,-2),(0,-1)],cones=[[0,1],[1,2],[2,3],[3,0]])1041sage: P112.<x,y,z,t> = ToricVariety(fan)1042sage: (-P112.K()).sections_monomials()1043(z^4*t^2, x*z^3*t^2, x^2*z^2*t^2, x^3*z*t^2,1044x^4*t^2, y*z^2*t, x*y*z*t, x^2*y*t, y^2)1045sage: WeierstrassForm_P2_112(sum(_), [x,y,z,t])1046(-97/48, 17/864)10471048TESTS::10491050sage: R.<x,y,z,t,a40,a30,a20,a10,a00,a21,a11,a01,a02> = QQ[]1051sage: p = ( a40*x^4*t^2 + a30*x^3*z*t^2 + a20*x^2*z^2*t^2 + a10*x*z^3*t^2 +1052....: a00*z^4*t^2 + a21*x^2*y*t + a11*x*y*z*t + a01*y*z^2*t + a02*y^2 )1053sage: WeierstrassForm_P2_112(p, [x,y,z,t])1054(-1/48*a11^4 + 1/6*a21*a11^2*a01 - 1/3*a21^2*a01^2 + a00*a21^2*a021055- 1/2*a10*a21*a11*a02 + 1/6*a20*a11^2*a02 + 1/3*a20*a21*a01*a021056- 1/2*a30*a11*a01*a02 + a40*a01^2*a02 - 1/3*a20^2*a02^2 + a30*a10*a02^21057- 4*a40*a00*a02^2, 1/864*a11^6 - 1/72*a21*a11^4*a011058+ 1/18*a21^2*a11^2*a01^2 - 2/27*a21^3*a01^3 - 1/12*a00*a21^2*a11^2*a021059+ 1/24*a10*a21*a11^3*a02 - 1/72*a20*a11^4*a02 + 1/3*a00*a21^3*a01*a021060- 1/6*a10*a21^2*a11*a01*a02 + 1/36*a20*a21*a11^2*a01*a021061+ 1/24*a30*a11^3*a01*a02 + 1/9*a20*a21^2*a01^2*a021062- 1/6*a30*a21*a11*a01^2*a02 - 1/12*a40*a11^2*a01^2*a021063+ 1/3*a40*a21*a01^3*a02 + 1/4*a10^2*a21^2*a02^21064- 2/3*a20*a00*a21^2*a02^2 - 1/6*a20*a10*a21*a11*a02^21065+ a30*a00*a21*a11*a02^2 + 1/18*a20^2*a11^2*a02^21066- 1/12*a30*a10*a11^2*a02^2 - 2/3*a40*a00*a11^2*a02^21067+ 1/9*a20^2*a21*a01*a02^2 - 1/6*a30*a10*a21*a01*a02^21068- 4/3*a40*a00*a21*a01*a02^2 - 1/6*a30*a20*a11*a01*a02^21069+ a40*a10*a11*a01*a02^2 + 1/4*a30^2*a01^2*a02^21070- 2/3*a40*a20*a01^2*a02^2 - 2/27*a20^3*a02^31071+ 1/3*a30*a20*a10*a02^3 - a40*a10^2*a02^3 - a30^2*a00*a02^31072+ 8/3*a40*a20*a00*a02^3)10731074sage: _ == WeierstrassForm_P2_112(p.subs(z=1,t=1), [x,y])1075True10761077sage: cubic = p.subs(a40=0)1078sage: a,b = WeierstrassForm_P2_112(cubic, [x,y,z,t])1079sage: a = a.subs(t=1,z=1)1080sage: b = b.subs(t=1,z=1)1081sage: from sage.schemes.toric.weierstrass import WeierstrassForm_P21082sage: (a,b) == WeierstrassForm_P2(cubic.subs(t=1,z=1), [x,y])1083True1084"""1085x, y, z, t = _check_polynomial_P2_112(polynomial, variables)1086delta = _partial_discriminant(polynomial, y, t)1087Q = invariant_theory.binary_quartic(delta, x, z)1088g2 = Q.EisensteinD()1089g3 = -Q.EisensteinE()1090return (-g2/4, -g3/4)109110921093