Ticket #13458: trac_13458_toric_Weierstrass_covering.patch

File trac_13458_toric_Weierstrass_covering.patch, 25.2 KB (added by vbraun, 8 years ago)

Updated patch

  • doc/en/reference/schemes/index.rst

    # HG changeset patch
    # User Volker Braun <vbraun@stp.dias.ie>
    # Date 1371504902 25200
    #      Mon Jun 17 14:35:02 2013 -0700
    # Node ID 61571925b75faffda8d9e8deeff65d9f8649321e
    # Parent  98d5711ec9819c8a9e716c27041529fe7a5c83e6
    Compute the map from a elliptic curve in a toric surface
    to its Weierstrass form
    
    diff --git a/doc/en/reference/schemes/index.rst b/doc/en/reference/schemes/index.rst
    a b  
    3939   sage/schemes/toric/ideal
    4040   sage/schemes/toric/morphism
    4141   sage/schemes/toric/weierstrass
     42   sage/schemes/toric/weierstrass_covering
    4243
    4344
    4445.. include:: ../footer.txt
  • sage/geometry/polyhedron/lattice_euclidean_group_element.py

    diff --git a/sage/geometry/polyhedron/lattice_euclidean_group_element.py b/sage/geometry/polyhedron/lattice_euclidean_group_element.py
    a b  
    134134        s = 'The map A*x+b with A=\n'+str(self._A)
    135135        s += '\nb = \n'+str(self._b)
    136136        return s
     137
     138    def domain_dim(self):
     139        """
     140        Return the rank of the domain lattice
     141
     142        EXAMPLES::
     143
     144            sage: from sage.geometry.polyhedron.lattice_euclidean_group_element \
     145            ....:     import LatticeEuclideanGroupElement
     146            sage: M = LatticeEuclideanGroupElement([[1,2],[2,3],[-1,2]], [1,2,3])
     147            sage: M
     148            The map A*x+b with A=
     149            [ 1  2]
     150            [ 2  3]
     151            [-1  2]
     152            b =
     153            (1, 2, 3)
     154            sage: M.domain_dim()
     155            2
     156        """
     157        return self._A.ncols()
     158
     159    def codomain_dim(self):
     160        """
     161        Return the rank of the codomain lattice
     162
     163        EXAMPLES::
     164
     165            sage: from sage.geometry.polyhedron.lattice_euclidean_group_element \
     166            ....:     import LatticeEuclideanGroupElement
     167            sage: M = LatticeEuclideanGroupElement([[1,2],[2,3],[-1,2]], [1,2,3])
     168            sage: M
     169            The map A*x+b with A=
     170            [ 1  2]
     171            [ 2  3]
     172            [-1  2]
     173            b =
     174            (1, 2, 3)
     175            sage: M.codomain_dim()
     176            3
     177
     178        Note that this is not the same as the rank. In fact, the
     179        codomain dimension depends only on the matrix shape, and not
     180        on the rank of the linear mapping::
     181
     182            sage: zero_map = LatticeEuclideanGroupElement([[0,0],[0,0],[0,0]], [0,0,0])
     183            sage: zero_map.codomain_dim()
     184            3
     185        """
     186        return self._A.nrows()
  • sage/schemes/toric/all.py

    diff --git a/sage/schemes/toric/all.py b/sage/schemes/toric/all.py
    a b  
    55from library import toric_varieties
    66from variety import AffineToricVariety, ToricVariety
    77
     8
    89from sage.misc.lazy_import import lazy_import
    910lazy_import('sage.schemes.toric.weierstrass', 'WeierstrassForm')
  • sage/schemes/toric/weierstrass.py

    diff --git a/sage/schemes/toric/weierstrass.py b/sage/schemes/toric/weierstrass.py
    a b  
    352352
    353353
    354354######################################################################
    355 def WeierstrassForm(polynomial, variables=None):
     355def WeierstrassForm(polynomial, variables=None, transformation=False):
    356356    r"""
    357     Return the Weierstrass form of an anticanonical hypersurface.
     357    Return the Weierstrass form of an anticanonical hypersurface equation.
    358358
    359359    INPUT:
    360360
     
    370370      determined over the function field generated by the remaining
    371371      variables.
    372372
     373    - ``transformation`` -- boolean (default: ``True``). Whether to
     374      return the new variables that bring ``polynomial`` into
     375      Weierstrass form.
     376
    373377    OUTPUT:
    374378
    375379    The pair of coefficients `(f,g)` of the Weierstrass form `y^2 =
    376380    x^3 + f x + g` of the hypersurface equation.
    377381
     382    If ``transformation=True``, a triple `(X,Y,Z)` of polynomials
     383    defining a rational map of the toric hypersurface to its
     384    Weierstrass form in `\mathbb{P}^2[2,3,1]` is returned. That is,
     385    the triple satisfies
     386
     387    .. math::
     388
     389        Y^2 = X^3 + f X Z^4 + Z^6
     390
     391    when restricted to the toric hypersurface.
     392
    378393    EXAMPLES::
    379394
    380395        sage: R.<x,y,z> = QQ[]
    381396        sage: cubic = x^3 + y^3 + z^3
    382         sage: WeierstrassForm(cubic)
     397        sage: f, g = WeierstrassForm(cubic);  (f, g)
    383398        (0, -27/4)
    384399
     400    Same in inhomogeneous coordinates::
     401
     402        sage: R.<x,y> = QQ[]
     403        sage: cubic = x^3 + y^3 + 1
     404        sage: f, g = WeierstrassForm(cubic);  (f, g)
     405        (0, -27/4)
     406
     407        sage: X,Y,Z = WeierstrassForm(cubic, transformation=True);  (X,Y,Z)
     408        (-x^3*y^3 - x^3 - y^3,
     409         1/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,
     410         x*y)
     411
     412    Note that plugging in `[X:Y:Z]` to the Weierstrass equation is a
     413    complicated polynomial, but contains the hypersurface equation as
     414    a factor::
     415
     416        sage: -Y^2 + X^3 + f*X*Z^4 + g*Z^6
     417        -1/4*x^12*y^6 - 1/2*x^9*y^9 - 1/4*x^6*y^12 + 1/2*x^12*y^3
     418        - 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^3
     419        - 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^3
     420        - 7/2*x^3*y^6 - 1/2*y^9 - 1/4*x^6 + 1/2*x^3*y^3 - 1/4*y^6
     421        sage: cubic.divides(-Y^2 + X^3 + f*X*Z^4 + g*Z^6)
     422        True
     423
    385424    Only the affine span of the Newton polytope of the polynomial
    386425    matters. For example::
    387426
     427        sage: R.<x,y,z> = QQ[]
     428        sage: cubic = x^3 + y^3 + z^3
    388429        sage: WeierstrassForm(cubic.subs(z=1))
    389430        (0, -27/4)
    390431        sage: WeierstrassForm(x * cubic)
     
    433474        (-241/48, 3689/864)
    434475        (215/48, -5291/864)
    435476    """
     477    if transformation:
     478        from sage.schemes.toric.weierstrass_covering import WeierstrassMap
     479        return WeierstrassMap(polynomial, variables=variables)
    436480    if variables is None:
    437481        variables = polynomial.variables()
    438482    from sage.geometry.polyhedron.ppl_lattice_polygon import (
  • new file sage/schemes/toric/weierstrass_covering.py

    diff --git a/sage/schemes/toric/weierstrass_covering.py b/sage/schemes/toric/weierstrass_covering.py
    new file mode 100644
    - +  
     1r"""
     2Map to the Weierstrass form of a toric elliptic curve.
     3
     4There are 16 reflexive polygons in 2-d. Each defines a toric fano
     5variety, which (in 2-d) has a unique crepant resolution to a smooth
     6toric surface. An anticanonical hypersurface defines a genus-one curve
     7`C` in this ambient space, with Jacobian elliptic curve `J(C)` which
     8can be defined by the Weierstrass model `y^2 = x^3 + f x + g`. The
     9coefficients `f`, `g` can be computed with the
     10:mod:`~sage.schemes.toric.weierstrass` module. The purpose of this
     11model is to give an explicit rational map `C \to J(C)`. This is a
     12`n^2`-cover, where `n` is the minimal multi-section of `C`.
     13
     14Since it is technically often easier to deal with polynomials than
     15with fractions, we return the rational map in terms of homogeneous
     16coordinates. That is, the ambient space for the Weierstrass model is
     17the weighted projective space `\mathbb{P}^2[2,3,1]` with homogeneous
     18coordinates `[X:Y:Z] = [\lambda^2 X, \lambda^3 Y, \lambda Z]`. The
     19homogenized Weierstrass equation is
     20
     21.. math::
     22
     23    Y^2 = X^3 + f X Z^4 + Z^6
     24
     25EXAMPLES::
     26
     27    sage: R.<x,y> = QQ[]
     28    sage: cubic = x^3 + y^3 + 1
     29    sage: f, g = WeierstrassForm(cubic);  (f,g)
     30    (0, -27/4)
     31
     32That is, this hypersurface `C \in \mathbb{P}^2` has a Weierstrass
     33equation `-Y^2 = X^3 + 0 \cdot X Z^4 - \frac{27}{4} Z^6` where
     34`[X:Y:Z]` are projective coordinates on `\mathbb{P}^2[2,3,1]`. The
     35form of the map `C\to J(C)` is::
     36
     37    sage: X,Y,Z = WeierstrassForm(cubic, transformation=True);  (X,Y,Z)
     38    (-x^3*y^3 - x^3 - y^3,
     39     1/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,
     40     x*y)
     41
     42Note that plugging in `[X:Y:Z]` to the Weierstrass equation is a
     43complicated polynomial, but contains the hypersurface equation as a
     44factor::
     45
     46    sage: -Y^2 + X^3 + f*X*Z^4 + g*Z^6
     47    -1/4*x^12*y^6 - 1/2*x^9*y^9 - 1/4*x^6*y^12 + 1/2*x^12*y^3
     48    - 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^3
     49    - 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^3
     50    - 7/2*x^3*y^6 - 1/2*y^9 - 1/4*x^6 + 1/2*x^3*y^3 - 1/4*y^6
     51    sage: cubic.divides(-Y^2 + X^3 + f*X*Z^4 + g*Z^6)
     52    True
     53
     54If you prefer you can also use homogeneous coordinates for `C \in
     55\mathbb{P}^2` ::
     56
     57    sage: R.<x,y,z> = QQ[]
     58    sage: cubic = x^3 + y^3 + z^3
     59    sage: f, g = WeierstrassForm(cubic);  (f,g)
     60    (0, -27/4)
     61    sage: X,Y,Z = WeierstrassForm(cubic, transformation=True)
     62    sage: cubic.divides(-Y^2 + X^3 + f*X*Z^4 + g*Z^6)
     63    True
     64
     65The 16 toric surfaces corresponding to the 16 reflexive polygons can
     66all be blown down to `\mathbb{P}^2`, `\mathbb{P}^1\times\mathbb{P}^1`,
     67or `\mathbb{P}^{2}[1,1,2]`. Their (and hence in all 16 cases)
     68anticanonical hypersurface can equally be brought into Weierstrass
     69form. For example, here is an anticanonical hypersurface in
     70`\mathbb{P}^{2}[1,1,2]` ::
     71
     72    sage: P2_112 = toric_varieties.P2_112()
     73    sage: C = P2_112.anticanonical_hypersurface(coefficients=[1]*4);  C
     74    Closed subscheme of 2-d CPR-Fano toric variety covered by 3 affine patches defined by:
     75      z0^4 + z2^4 + z0*z1*z2 + z1^2
     76    sage: eq = C.defining_polynomials()[0]
     77    sage: f, g = WeierstrassForm(eq)
     78    sage: X,Y,Z = WeierstrassForm(eq, transformation=True)
     79    sage: (-Y^2 + X^3 + f*X*Z^4 + g*Z^6).reduce(C.defining_ideal())
     80    0
     81
     82Finally, you sometimes have to manually specify the variables to
     83use. This is either because the equation is degenerate or because it
     84contains additional variables that you want to treat as coefficients::
     85
     86    sage: R.<a, x,y,z> = QQ[]
     87    sage: cubic = x^3 + y^3 + z^3 + a*x*y*z
     88    sage: f, g = WeierstrassForm(cubic, variables=[x,y,z])
     89    sage: X,Y,Z = WeierstrassForm(cubic, variables=[x,y,z], transformation=True)
     90    sage: cubic.divides(-Y^2 + X^3 + f*X*Z^4 + g*Z^6)
     91    True
     92
     93REFERENCES:
     94
     95..  [AnEtAl]
     96    An, Sang Yook et al:
     97    Jacobians of Genus One Curves,
     98    Journal of Number Theory 90 (2002), pp.304--315,
     99    http://www.math.arizona.edu/~wmc/Research/JacobianFinal.pdf
     100"""
     101
     102########################################################################
     103#       Copyright (C) 2012 Volker Braun <vbraun.name@gmail.com>
     104#
     105#  Distributed under the terms of the GNU General Public License (GPL)
     106#
     107#                  http://www.gnu.org/licenses/
     108########################################################################
     109
     110from sage.rings.all import ZZ
     111from sage.modules.all import vector
     112from sage.rings.all import invariant_theory
     113from sage.schemes.toric.weierstrass import (
     114    _partial_discriminant,
     115    _check_polynomial_P2,
     116    _check_polynomial_P1xP1,
     117    _check_polynomial_P2_112,
     118)
     119
     120
     121######################################################################
     122
     123def WeierstrassMap(polynomial, variables=None):
     124    r"""
     125    Return the Weierstrass form of an anticanonical hypersurface.
     126
     127    You should use
     128    :meth:`sage.schemes.toric.weierstrass.WeierstrassForm` with
     129    ``transformation=True`` to get the transformation. This function
     130    is only for internal use.
     131
     132    INPUT:
     133
     134    - ``polynomial`` -- a polynomial. The toric hypersurface
     135      equation. Can be either a cubic, a biquadric, or the
     136      hypersurface in `\mathbb{P}^2[1,1,2]`. The equation need not be
     137      in any standard form, only its Newton polynomial is used.
     138
     139    - ``variables`` -- a list of variables of the parent polynomial
     140      ring or ``None`` (default). In the latter case, all variables
     141      are taken to be polynomial ring variables. If a subset of
     142      polynomial ring variables are given, the Weierstras form is
     143      determined over the function field generated by the remaining
     144      variables.
     145
     146    OUTPUT:
     147
     148    A triple `(X,Y,Z)` of polynomials defining a rational map of the
     149    toric hypersurface to its Weierstrass form in
     150    `\mathbb{P}^2[2,3,1]`. That is, the triple satisfies
     151
     152    .. math::
     153
     154        Y^2 = X^3 + f X Z^4 + Z^6
     155
     156    when restricted to the toric hypersurface.
     157
     158    EXAMPLES::
     159
     160        sage: R.<x,y,z> = QQ[]
     161        sage: cubic = x^3 + y^3 + z^3
     162        sage: X,Y,Z = WeierstrassForm(cubic, transformation=True);  (X,Y,Z)
     163        (-x^3*y^3 - x^3*z^3 - y^3*z^3,
     164         1/2*x^6*y^3 - 1/2*x^3*y^6 - 1/2*x^6*z^3 + 1/2*y^6*z^3
     165             + 1/2*x^3*z^6 - 1/2*y^3*z^6,
     166         x*y*z)
     167         sage: f, g = WeierstrassForm(cubic);  (f,g)
     168         (0, -27/4)
     169         sage: cubic.divides(-Y^2 + X^3 + f*X*Z^4 + g*Z^6)
     170         True
     171
     172    Only the affine span of the Newton polytope of the polynomial
     173    matters. For example::
     174
     175        sage: WeierstrassForm(cubic.subs(z=1), transformation=True)
     176        (-x^3*y^3 - x^3 - y^3,
     177         1/2*x^6*y^3 - 1/2*x^3*y^6 - 1/2*x^6
     178             + 1/2*y^6 + 1/2*x^3 - 1/2*y^3,
     179         x*y)
     180        sage: WeierstrassForm(x * cubic, transformation=True)
     181        (-x^3*y^3 - x^3*z^3 - y^3*z^3,
     182         1/2*x^6*y^3 - 1/2*x^3*y^6 - 1/2*x^6*z^3 + 1/2*y^6*z^3
     183             + 1/2*x^3*z^6 - 1/2*y^3*z^6,
     184         x*y*z)
     185
     186    This allows you to work with either homogeneous or inhomogeneous
     187    variables. For example, here is the del Pezzo surface of degree 8::
     188
     189        sage: dP8 = toric_varieties.dP8()
     190        sage: dP8.inject_variables()
     191        Defining t, x, y, z
     192        sage: WeierstrassForm(x*y^2 + y^2*z + t^2*x^3 + t^2*z^3, transformation=True)
     193        (-1/27*t^4*x^6 - 2/27*t^4*x^5*z - 5/27*t^4*x^4*z^2
     194             - 8/27*t^4*x^3*z^3 - 5/27*t^4*x^2*z^4 - 2/27*t^4*x*z^5
     195             - 1/27*t^4*z^6 - 4/81*t^2*x^4*y^2 - 4/81*t^2*x^3*y^2*z
     196             - 4/81*t^2*x*y^2*z^3 - 4/81*t^2*y^2*z^4 - 2/81*x^2*y^4
     197             - 4/81*x*y^4*z - 2/81*y^4*z^2,
     198        0,
     199        1/3*t^2*x^2*z + 1/3*t^2*x*z^2 - 1/9*x*y^2 - 1/9*y^2*z)
     200        sage: WeierstrassForm(x*y^2 + y^2 + x^3 + 1, transformation=True)
     201        (-1/27*x^6 - 4/81*x^4*y^2 - 2/81*x^2*y^4 - 2/27*x^5
     202             - 4/81*x^3*y^2 - 4/81*x*y^4 - 5/27*x^4 - 2/81*y^4 - 8/27*x^3
     203             - 4/81*x*y^2 - 5/27*x^2 - 4/81*y^2 - 2/27*x - 1/27,
     204         0,
     205         -1/9*x*y^2 + 1/3*x^2 - 1/9*y^2 + 1/3*x)
     206
     207    By specifying only certain variables we can compute the
     208    Weierstrass form over the function field generated by the
     209    remaining variables. For example, here is a cubic over `\QQ[a]` ::
     210
     211        sage: R.<a, x,y,z> = QQ[]
     212        sage: cubic = x^3 + a*y^3 + a^2*z^3
     213        sage: WeierstrassForm(cubic, variables=[x,y,z], transformation=True)
     214        (-a^9*y^3*z^3 - a^8*x^3*z^3 - a^7*x^3*y^3,
     215         -1/2*a^14*y^3*z^6 + 1/2*a^13*y^6*z^3 + 1/2*a^13*x^3*z^6
     216             - 1/2*a^11*x^3*y^6 - 1/2*a^11*x^6*z^3 + 1/2*a^10*x^6*y^3,
     217         a^3*x*y*z)
     218
     219    TESTS::
     220
     221        sage: for P in ReflexivePolytopes(2):
     222        ....:     S = ToricVariety(FaceFan(P))
     223        ....:     p = sum( (-S.K()).sections_monomials() )
     224        ....:     f, g = WeierstrassForm(p)
     225        ....:     X,Y,Z = WeierstrassForm(p, transformation=True)
     226        ....:     print P, p.divides(-Y^2 + X^3 + f*X*Z^4 + g*Z^6)
     227        Reflexive polytope    0: 2-dimensional, 3 vertices. True
     228        Reflexive polytope    1: 2-dimensional, 3 vertices. True
     229        Reflexive polytope    2: 2-dimensional, 4 vertices. True
     230        Reflexive polytope    3: 2-dimensional, 4 vertices. True
     231        Reflexive polytope    4: 2-dimensional, 4 vertices. True
     232        Reflexive polytope    5: 2-dimensional, 5 vertices. True
     233        Reflexive polytope    6: 2-dimensional, 3 vertices. True
     234        Reflexive polytope    7: 2-dimensional, 4 vertices. True
     235        Reflexive polytope    8: 2-dimensional, 5 vertices. True
     236        Reflexive polytope    9: 2-dimensional, 6 vertices. True
     237        Reflexive polytope   10: 2-dimensional, 4 vertices. True
     238        Reflexive polytope   11: 2-dimensional, 5 vertices. True
     239        Reflexive polytope   12: 2-dimensional, 3 vertices. True
     240        Reflexive polytope   13: 2-dimensional, 4 vertices. True
     241        Reflexive polytope   14: 2-dimensional, 4 vertices. True
     242        Reflexive polytope   15: 2-dimensional, 3 vertices. True
     243    """
     244    if variables is None:
     245        variables = polynomial.variables()
     246    # switch to suitable inhomogeneous coordinates
     247    from sage.geometry.polyhedron.ppl_lattice_polygon import (
     248        polar_P2_polytope, polar_P1xP1_polytope, polar_P2_112_polytope )
     249    from sage.schemes.toric.weierstrass import Newton_polygon_embedded
     250    newton_polytope, polynomial_aff, variables_aff = \
     251        Newton_polygon_embedded(polynomial, variables)
     252    polygon = newton_polytope.embed_in_reflexive_polytope('polytope')
     253    # Compute the map in inhomogeneous coordinates
     254    if polygon is polar_P2_polytope():
     255        X,Y,Z = WeierstrassMap_P2(polynomial_aff, variables_aff)
     256    elif polygon is polar_P1xP1_polytope():
     257        X,Y,Z = WeierstrassMap_P1xP1(polynomial_aff, variables_aff)
     258    elif polygon is polar_P2_112_polytope():
     259        X,Y,Z = WeierstrassMap_P2_112(polynomial_aff, variables_aff)
     260    else:
     261        assert False, 'Newton polytope is not contained in a reflexive polygon'
     262    # homogenize again
     263    R = polynomial.parent()
     264    x = R.gens().index(variables_aff[0])
     265    y = R.gens().index(variables_aff[1])
     266    hom = newton_polytope.embed_in_reflexive_polytope('hom')
     267    def homogenize(inhomog, degree):
     268        e = tuple(hom._A * vector(ZZ,[inhomog[x], inhomog[y]]) + degree * hom._b)
     269        result = list(inhomog)
     270        for i, var in enumerate(variables):
     271            result[R.gens().index(var)] = e[i]
     272        result = vector(ZZ, result)
     273        result.set_immutable()
     274        return result
     275    X_dict = dict( (homogenize(e,2), v) for e,v in X.dict().iteritems() )
     276    Y_dict = dict( (homogenize(e,3), v) for e,v in Y.dict().iteritems() )
     277    Z_dict = dict( (homogenize(e,1), v) for e,v in Z.dict().iteritems() )
     278    # shift to non-negative exponents if necessary
     279    min_deg = [0]*R.ngens()
     280    for var in variables:
     281        i = R.gens().index(var)
     282        min_X = min([ e[i] for e in X_dict ]) if len(X_dict)>0 else 0
     283        min_Y = min([ e[i] for e in Y_dict ]) if len(Y_dict)>0 else 0
     284        min_Z = min([ e[i] for e in Z_dict ]) if len(Z_dict)>0 else 0
     285        min_deg[i] = min( min_X/2, min_Y/3, min_Z )
     286    min_deg = vector(min_deg)
     287    X_dict = dict( (tuple(e-2*min_deg), v) for e,v in X_dict.iteritems() )
     288    Y_dict = dict( (tuple(e-3*min_deg), v) for e,v in Y_dict.iteritems() )
     289    Z_dict = dict( (tuple(e-1*min_deg), v) for e,v in Z_dict.iteritems() )
     290    return (R(X_dict), R(Y_dict), R(Z_dict))
     291
     292
     293######################################################################
     294#
     295#  Weierstrass form of cubic in P^2
     296#
     297######################################################################
     298
     299def WeierstrassMap_P2(polynomial, variables=None):
     300    r"""
     301    Map a cubic to its Weierstrass form
     302
     303    Input/output is the same as :func:`WeierstrassMap`, except that
     304    the input polynomial must be a cubic in `\mathbb{P}^2`,
     305
     306    .. math::
     307
     308        \begin{split}
     309          p(x,y) =&\;
     310          a_{30} x^{3} + a_{21} x^{2} y + a_{12} x y^{2} +
     311          a_{03} y^{3} + a_{20} x^{2} +
     312          \\ &\;
     313          a_{11} x y +
     314          a_{02} y^{2} + a_{10} x + a_{01} y + a_{00}
     315        \end{split}
     316
     317    EXAMPLES::
     318
     319        sage: from sage.schemes.toric.weierstrass import WeierstrassForm_P2
     320        sage: from sage.schemes.toric.weierstrass_covering import WeierstrassMap_P2
     321        sage: R.<x,y,z> = QQ[]
     322        sage: equation =  x^3+y^3+z^3+x*y*z
     323        sage: f, g = WeierstrassForm_P2(equation)
     324        sage: X,Y,Z = WeierstrassMap_P2(equation)
     325        sage: equation.divides(-Y^2 + X^3 + f*X*Z^4 + g*Z^6)
     326        True
     327
     328        sage: from sage.schemes.toric.weierstrass import WeierstrassForm_P2
     329        sage: from sage.schemes.toric.weierstrass_covering import WeierstrassMap_P2
     330        sage: R.<x,y> = QQ[]
     331        sage: equation =  x^3+y^3+1
     332        sage: f, g = WeierstrassForm_P2(equation)
     333        sage: X,Y,Z = WeierstrassMap_P2(equation)
     334        sage: equation.divides(-Y^2 + X^3 + f*X*Z^4 + g*Z^6)
     335        True
     336    """
     337    x,y,z = _check_polynomial_P2(polynomial, variables)
     338    cubic = invariant_theory.ternary_cubic(polynomial, x,y,z)
     339    H = cubic.Hessian()
     340    Theta = cubic.Theta_covariant()
     341    J = cubic.J_covariant()
     342    F = polynomial.parent().base_ring()
     343    return (Theta, J/F(2), H)
     344   
     345
     346######################################################################
     347#
     348#  Weierstrass form of biquadric in P1 x P1
     349#
     350######################################################################
     351
     352def WeierstrassMap_P1xP1(polynomial, variables=None):
     353    r"""
     354    Map an anticanonical hypersurface in
     355    `\mathbb{P}^1 \times \mathbb{P}^1` into Weierstrass form.
     356
     357    Input/output is the same as :func:`WeierstrassMap`, except that
     358    the input polynomial must be a standard anticanonical hypersurface
     359    in weighted projective space `\mathbb{P}^1 \times \mathbb{P}^1`:
     360
     361    EXAMPLES::
     362
     363        sage: from sage.schemes.toric.weierstrass_covering import WeierstrassMap_P1xP1
     364        sage: from sage.schemes.toric.weierstrass import WeierstrassForm_P1xP1
     365        sage: R.<x0,x1,y0,y1,a>= QQ[]
     366        sage: biquadric = ( x0^2*y0^2 + x1^2*y0^2 + x0^2*y1^2 + x1^2*y1^2 +
     367        ....:     a * x0*x1*y0*y1*5 )
     368        sage: f, g = WeierstrassForm_P1xP1(biquadric, [x0, x1, y0, y1]);  (f,g)
     369        (-625/48*a^4 + 25/3*a^2 - 16/3, 15625/864*a^6 - 625/36*a^4 - 100/9*a^2 + 128/27)
     370        sage: X, Y, Z = WeierstrassMap_P1xP1(biquadric, [x0, x1, y0, y1])
     371        sage: (-Y^2 + X^3 + f*X*Z^4 + g*Z^6).reduce(R.ideal(biquadric))
     372        0
     373
     374        sage: R = PolynomialRing(QQ, 'x,y,s,t', order='lex')
     375        sage: R.inject_variables()
     376        Defining x, y, s, t
     377        sage: equation = ( s^2*(x^2+2*x*y+3*y^2) + s*t*(4*x^2+5*x*y+6*y^2)
     378        ....:              + t^2*(7*x^2+8*x*y+9*y^2) )
     379        sage: X, Y, Z = WeierstrassMap_P1xP1(equation, [x,y,s,t])
     380        sage: f, g = WeierstrassForm_P1xP1(equation, variables=[x,y,s,t])
     381        sage: (-Y^2 + X^3 + f*X*Z^4 + g*Z^6).reduce(R.ideal(equation))
     382        0
     383
     384        sage: R = PolynomialRing(QQ, 'x,s', order='lex')
     385        sage: R.inject_variables()
     386        Defining x, s
     387        sage: equation = s^2*(x^2+2*x+3) + s*(4*x^2+5*x+6) + (7*x^2+8*x+9)
     388        sage: X, Y, Z = WeierstrassMap_P1xP1(equation)
     389        sage: f, g = WeierstrassForm_P1xP1(equation)
     390        sage: (-Y^2 + X^3 + f*X*Z^4 + g*Z^6).reduce(R.ideal(equation))
     391        0
     392    """
     393    x,y,s,t = _check_polynomial_P1xP1(polynomial, variables)
     394    a00 = polynomial.coefficient({s:2})
     395    V = polynomial.coefficient({s:1})
     396    U = - _partial_discriminant(polynomial, s, t) / 4
     397    Q = invariant_theory.binary_quartic(U, x, y)
     398    g = Q.g_covariant()
     399    h = Q.h_covariant()
     400    if t is None:
     401        t = 1
     402        #return ( 4*g*(a00*s+V/2), 4*h, (a00*s+V/2)**3 )
     403    return ( 4*g*t**2, 4*h*t**3, (a00*s+V/2) )
     404
     405
     406######################################################################
     407#
     408#  Weierstrass form of anticanonical hypersurface in WP2[1,1,2]
     409#
     410######################################################################
     411
     412def WeierstrassMap_P2_112(polynomial, variables=None):
     413    r"""
     414    Map an anticanonical hypersurface in `\mathbb{P}^2[1,1,2]` into Weierstrass form.
     415
     416    Input/output is the same as :func:`WeierstrassMap`, except that
     417    the input polynomial must be a standard anticanonical hypersurface
     418    in weighted projective space `\mathbb{P}^2[1,1,2]`:
     419
     420    .. math::
     421
     422        \begin{split}
     423          p(x,y) =&\;
     424          a_{40} x^4 +
     425          a_{30} x^3 +
     426          a_{21} x^2 y +
     427          a_{20} x^2 +
     428          \\ &\;
     429          a_{11} x y +
     430          a_{02} y^2 +
     431          a_{10} x +
     432          a_{01} y +
     433          a_{00}
     434        \end{split}
     435
     436    EXAMPLES::
     437
     438        sage: from sage.schemes.toric.weierstrass_covering import WeierstrassMap_P2_112
     439        sage: from sage.schemes.toric.weierstrass import WeierstrassForm_P2_112
     440        sage: R = PolynomialRing(QQ, 'x,y,a0,a1,a2,a3,a4', order='lex')
     441        sage: R.inject_variables()
     442        Defining x, y, a0, a1, a2, a3, a4
     443        sage: equation = y^2 + a0*x^4 + 4*a1*x^3 + 6*a2*x^2 + 4*a3*x + a4
     444        sage: X, Y, Z = WeierstrassMap_P2_112(equation, [x,y])
     445        sage: f, g = WeierstrassForm_P2_112(equation, variables=[x,y])
     446        sage: (-Y^2 + X^3 + f*X*Z^4 + g*Z^6).reduce(R.ideal(equation))
     447        0
     448
     449    Another example, this time in homogeneous coordinates::
     450
     451        sage: fan = Fan(rays=[(1,0),(0,1),(-1,-2),(0,-1)],cones=[[0,1],[1,2],[2,3],[3,0]])
     452        sage: P112.<x,y,z,t> = ToricVariety(fan)
     453        sage: (-P112.K()).sections_monomials()
     454        (z^4*t^2, x*z^3*t^2, x^2*z^2*t^2, x^3*z*t^2,
     455         x^4*t^2, y*z^2*t, x*y*z*t, x^2*y*t, y^2)
     456        sage: C_eqn = sum(_)
     457        sage: C = P112.subscheme(C_eqn)
     458        sage: WeierstrassForm_P2_112(C_eqn, [x,y,z,t])
     459        (-97/48, 17/864)
     460        sage: X, Y, Z = WeierstrassMap_P2_112(C_eqn, [x,y,z,t])
     461        sage: (-Y^2 + X^3 - 97/48*X*Z^4 + 17/864*Z^6).reduce(C.defining_ideal())
     462        0
     463    """
     464    x,y,z,t = _check_polynomial_P2_112(polynomial, variables)
     465    a00 = polynomial.coefficient({y:2})
     466    V = polynomial.coefficient({y:1})
     467    U = - _partial_discriminant(polynomial, y, t) / 4
     468    Q = invariant_theory.binary_quartic(U, x, z)
     469    g = Q.g_covariant()
     470    h = Q.h_covariant()
     471    if t is None:
     472        t = 1
     473    return ( 4*g*t**2, 4*h*t**3, (a00*y+V/2) )