Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
sagemath
GitHub Repository: sagemath/sagesmc
Path: blob/master/src/sage/schemes/toric/weierstrass.py
8820 views
1
r"""
2
Weierstrass form of a toric elliptic curve.
3
4
There are 16 reflexive polygons in the plane, see
5
:func:`~sage.geometry.lattice_polytope.ReflexivePolytopes`. Each of
6
them defines a toric Fano variety. And each of them has a unique
7
crepant resolution to a smooth toric surface [CLSsurfaces]_ by
8
subdividing the face fan. An anticanonical hypersurface defines an
9
elliptic curve in this ambient space, which we call a toric elliptic
10
curve. The purpose of this module is to write an anticanonical
11
hypersurface equation in the short Weierstrass form `y^2 = x^3 + f x +
12
g`. This works over any base ring as long as its characteristic `\not=
13
2,3`.
14
15
For an analogous treatment of elliptic curves defined as complete
16
intersection in higher dimensional toric varieties, see
17
the module :mod:`~sage.schemes.toric.weierstrass_higher`.
18
19
Technically, this module computes the Weierstrass form of the Jacobian
20
of the elliptic curve. This is why you will never have to specify the
21
origin (or zero section) in the following.
22
23
It turns out [VolkerBraun]_ that the anticanonical hypersurface
24
equation of any one of the above 16 toric surfaces is a specialization
25
(that is, set one or more of the coefficients to zero) of the
26
following three cases. In inhomogeneous coordinates, they are
27
28
* Cubic in `\mathbb{P}^2`:
29
30
.. math::
31
32
\begin{split}
33
p(x,y) =&\;
34
a_{30} x^{3} + a_{21} x^{2} y + a_{12} x y^{2} +
35
a_{03} y^{3} + a_{20} x^{2} +
36
\\ &\;
37
a_{11} x y +
38
a_{02} y^{2} + a_{10} x + a_{01} y + a_{00}
39
\end{split}
40
41
* Biquadric in `\mathbb{P}^1\times \mathbb{P}^1`:
42
43
.. math::
44
45
\begin{split}
46
p(x,y) =&\;
47
a_{22} x^2 y^2 + a_{21} x^2 y + a_{20} x^2 +
48
a_{12} x y^2 +
49
\\ &\;
50
a_{11} x y + x a_{10} +
51
y^2 a_{02} + y a_{01} + a_{00}
52
\end{split}
53
54
* Anticanonical hypersurface in weighted projective space
55
`\mathbb{P}^2[1,1,2]`:
56
57
.. math::
58
59
\begin{split}
60
p(x,y) =&\;
61
a_{40} x^4 +
62
a_{30} x^3 +
63
a_{21} x^2 y +
64
a_{20} x^2 +
65
\\ &\;
66
a_{11} x y +
67
a_{02} y^2 +
68
a_{10} x +
69
a_{01} y +
70
a_{00}
71
\end{split}
72
73
EXAMPLES:
74
75
The main functionality is provided by :func:`WeierstrassForm`, which
76
brings each of the above hypersurface equations into Weierstrass
77
form::
78
79
sage: R.<x,y> = QQ[]
80
sage: cubic = x^3 + y^3 + 1
81
sage: WeierstrassForm(cubic)
82
(0, -27/4)
83
sage: WeierstrassForm(x^4 + y^2 + 1)
84
(-4, 0)
85
sage: WeierstrassForm(x^2*y^2 + x^2 + y^2 + 1)
86
(-16/3, 128/27)
87
88
Only the affine span of the Newton polytope of the polynomial
89
matters. For example::
90
91
sage: R.<x,y,z> = QQ[]
92
sage: WeierstrassForm(x^3 + y^3 + z^3)
93
(0, -27/4)
94
sage: WeierstrassForm(x * cubic)
95
(0, -27/4)
96
97
This allows you to work with either homogeneous or inhomogeneous
98
variables. For exmple, here is the del Pezzo surface of degree 8::
99
100
sage: dP8 = toric_varieties.dP8()
101
sage: dP8.inject_variables()
102
Defining t, x, y, z
103
sage: WeierstrassForm(x*y^2 + y^2*z + t^2*x^3 + t^2*z^3)
104
(-3, -2)
105
sage: WeierstrassForm(x*y^2 + y^2 + x^3 + 1)
106
(-3, -2)
107
108
By specifying only certain variables we can compute the Weierstrass
109
form over the polynomial ring generated by the remaining
110
variables. For example, here is a cubic over `\QQ[a]` ::
111
112
sage: R.<a, x, y, z> = QQ[]
113
sage: cubic = x^3 + a*y^3 + a^2*z^3
114
sage: WeierstrassForm(cubic, variables=[x,y,z])
115
(0, -27/4*a^6)
116
117
TESTS::
118
119
sage: R.<f, g, x, y> = QQ[]
120
sage: cubic = -y^2 + x^3 + f*x + g
121
sage: WeierstrassForm(cubic, variables=[x,y])
122
(f, g)
123
124
REFERENCES:
125
126
.. [VolkerBraun]
127
Volker Braun:
128
Toric Elliptic Fibrations and F-Theory Compactifications
129
:arxiv:`1110.4883`
130
131
.. [Duistermaat]
132
J. J. Duistermaat,
133
Discrete integrable systems. QRT maps and elliptic surfaces.
134
Springer Monographs in Mathematics. Berlin: Springer. xxii, 627 p., 2010
135
136
.. [ArtinVillegasTate]
137
Michael Artin, Fernando Rodriguez-Villegas, John Tate,
138
On the Jacobians of plane cubics,
139
Advances in Mathematics 198 (2005) 1, pp. 366--382
140
:doi:`10.1016/j.aim.2005.06.004`
141
http://www.math.utexas.edu/users/villegas/publications/jacobian-cubics.pdf
142
143
.. [CLSsurfaces]
144
Section 10.4 in
145
David A. Cox, John B. Little, Hal Schenck,
146
"Toric Varieties", Graduate Studies in Mathematics,
147
Amer. Math. Soc., Providence, RI, 2011
148
"""
149
150
########################################################################
151
# Copyright (C) 2012 Volker Braun <[email protected]>
152
#
153
# Distributed under the terms of the GNU General Public License (GPL)
154
#
155
# http://www.gnu.org/licenses/
156
########################################################################
157
158
from sage.misc.all import prod
159
from sage.rings.infinity import Infinity
160
from sage.modules.all import vector
161
from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL
162
from sage.rings.all import invariant_theory
163
164
######################################################################
165
#
166
# Discriminant and j-invariant
167
#
168
######################################################################
169
170
171
def Discriminant(polynomial, variables=None):
172
r"""
173
The discriminant of the elliptic curve.
174
175
INPUT:
176
177
See :func:`WeierstrassForm` for how to specify the input
178
polynomial(s) and variables.
179
180
OUTPUT:
181
182
The discriminant of the elliptic curve.
183
184
EXAMPLES::
185
186
sage: from sage.schemes.toric.weierstrass import Discriminant
187
sage: R.<x, y, z> = QQ[]
188
sage: Discriminant(x^3+y^3+z^3)
189
19683/16
190
sage: Discriminant(x*y*z)
191
0
192
sage: R.<w,x,y,z> = QQ[]
193
sage: quadratic1 = w^2+x^2+y^2
194
sage: quadratic2 = z^2 + w*x
195
sage: Discriminant([quadratic1, quadratic2])
196
-1/16
197
"""
198
(f, g) = WeierstrassForm(polynomial, variables)
199
return 4*f**3+27*g**2
200
201
202
######################################################################
203
def j_invariant(polynomial, variables=None):
204
r"""
205
Return the `j`-invariant of the elliptic curve.
206
207
INPUT:
208
209
See :func:`WeierstrassForm` for how to specify the input
210
polynomial(s) and variables.
211
212
OUTPUT:
213
214
The j-invariant of the (irreducible) cubic. Notable special values:
215
216
* The Fermat cubic: `j(x^3+y^3+z^3) = 0`
217
218
* A nodal cubic: `j(-y^2 + x^2 + x^3) = \infty`
219
220
* A cuspidal cubic `y^2=x^3` has undefined `j`-invariant. In this
221
case, a ``ValueError`` is returned.
222
223
EXAMPLES::
224
225
sage: from sage.schemes.toric.weierstrass import j_invariant
226
sage: R.<x,y,z> = QQ[]
227
sage: j_invariant(x^3+y^3+z^3)
228
0
229
sage: j_invariant(-y^2 + x^2 + x^3)
230
+Infinity
231
sage: R.<x,y,z, a,b> = QQ[]
232
sage: j_invariant( -y^2*z + x^3 + a*x*z^2, [x,y,z])
233
1728
234
235
TESTS::
236
237
sage: j_invariant(x*y*z)
238
Traceback (most recent call last):
239
...
240
ValueError: curve is singular and has no well-defined j-invariant
241
"""
242
(f, g) = WeierstrassForm(polynomial, variables)
243
disc = 4*f**3+27*g**2
244
if disc != 0:
245
return 1728 * 4*f**3/disc
246
if f != 0:
247
return Infinity
248
raise ValueError('curve is singular and has no well-defined j-invariant')
249
250
251
######################################################################
252
#
253
# Weierstrass form of any elliptic curve
254
#
255
######################################################################
256
def Newton_polytope_vars_coeffs(polynomial, variables):
257
"""
258
Return the Newton polytope in the given variables.
259
260
INPUT:
261
262
See :func:`WeierstrassForm` for how to specify the input
263
polynomial and variables.
264
265
OUTPUT:
266
267
A tuple containing of the affine span of the Netwton polytope and
268
a dictionary with keys the integral values of the Newton polytope
269
and values the corresponding coefficient of ``polynomial``.
270
271
EXAMPLES::
272
273
sage: from sage.schemes.toric.weierstrass import Newton_polytope_vars_coeffs
274
sage: R.<x,y,z,a30,a21,a12,a03,a20,a11,a02,a10,a01,a00> = QQ[]
275
sage: p = (a30*x^3 + a21*x^2*y + a12*x*y^2 + a03*y^3 + a20*x^2*z +
276
....: a11*x*y*z + a02*y^2*z + a10*x*z^2 + a01*y*z^2 + a00*z^3)
277
sage: p_data = Newton_polytope_vars_coeffs(p, [x,y,z]); p_data
278
{(2, 1, 0): a21, (0, 3, 0): a03, (1, 0, 2): a10, (0, 2, 1): a02,
279
(0, 1, 2): a01, (3, 0, 0): a30, (2, 0, 1): a20, (1, 2, 0): a12,
280
(1, 1, 1): a11, (0, 0, 3): a00}
281
282
sage: from sage.geometry.polyhedron.ppl_lattice_polytope import LatticePolytope_PPL
283
sage: polytope = LatticePolytope_PPL(p_data.keys()); polytope
284
A 2-dimensional lattice polytope in ZZ^3 with 3 vertices
285
sage: polytope.vertices()
286
((0, 0, 3), (3, 0, 0), (0, 3, 0))
287
sage: polytope.embed_in_reflexive_polytope()
288
The map A*x+b with A=
289
[-1 -1]
290
[ 0 1]
291
[ 1 0]
292
b =
293
(3, 0, 0)
294
"""
295
R = polynomial.parent()
296
var_indices = [R.gens().index(x) for x in variables]
297
result = dict()
298
for c, m in polynomial:
299
e = m.exponents()[0]
300
v = tuple([e[i] for i in var_indices])
301
m_red = m // prod(x**i for x, i in zip(variables, v))
302
result[v] = result.get(v, R.zero()) + c*m_red
303
return result
304
305
306
######################################################################
307
def Newton_polygon_embedded(polynomial, variables):
308
r"""
309
Embed the Newton polytope of the polynomial in one of the three
310
maximal reflexive polygons.
311
312
This function is a helper for :func:`WeierstrassForm`
313
314
INPUT:
315
316
Same as :func:`WeierstrassForm` with only a single polynomial passed.
317
318
OUTPUT:
319
320
A tuple `(\Delta, P, (x,y))` where
321
322
* `\Delta` is the Newton polytope of ``polynomial``.
323
324
* `P(x,y)` equals the input ``polynomial`` but with redefined variables
325
such that its Newton polytope is `\Delta`.
326
327
EXAMPLES::
328
329
sage: from sage.schemes.toric.weierstrass import Newton_polygon_embedded
330
sage: R.<x,y,z> = QQ[]
331
sage: cubic = x^3 + y^3 + z^3
332
sage: Newton_polygon_embedded(cubic, [x,y,z])
333
(A 2-dimensional lattice polytope in ZZ^3 with 3 vertices,
334
x^3 + y^3 + 1,
335
(x, y))
336
337
sage: R.<a, x,y,z> = QQ[]
338
sage: cubic = x^3 + a*y^3 + a^2*z^3
339
sage: Newton_polygon_embedded(cubic, variables=[x,y,z])
340
(A 2-dimensional lattice polytope in ZZ^3 with 3 vertices,
341
a^2*x^3 + y^3 + a,
342
(x, y))
343
344
sage: R.<s,t,x,y> = QQ[]
345
sage: biquadric = (s+t)^2 * (x+y)^2
346
sage: Newton_polygon_embedded(biquadric, [s,t,x,y])
347
(A 2-dimensional lattice polytope in ZZ^4 with 4 vertices,
348
s^2*t^2 + 2*s^2*t + 2*s*t^2 + s^2 + 4*s*t + t^2 + 2*s + 2*t + 1,
349
(s, t))
350
"""
351
p_dict = Newton_polytope_vars_coeffs(polynomial, variables)
352
newton_polytope = LatticePolytope_PPL(p_dict.keys())
353
assert newton_polytope.affine_dimension() <= 2
354
embedding = newton_polytope.embed_in_reflexive_polytope('points')
355
x, y = variables[0:2]
356
embedded_polynomial = polynomial.parent().zero()
357
for e, c in p_dict.iteritems():
358
e_embed = embedding[e]
359
embedded_polynomial += c * x**(e_embed[0]) * y**(e_embed[1])
360
return newton_polytope, embedded_polynomial, (x, y)
361
362
363
######################################################################
364
def WeierstrassForm(polynomial, variables=None, transformation=False):
365
r"""
366
Return the Weierstrass form of an elliptic curve inside either
367
inside a toric surface or $\mathbb{P}^3$.
368
369
INPUT:
370
371
- ``polynomial`` -- either a polynomial or a list of polynomials
372
defining the elliptic curve.
373
A single polynomial can be either a cubic, a biquadric, or the
374
hypersurface in `\mathbb{P}^2[1,1,2]`. In this case the
375
equation need not be in any standard form, only its Newton
376
polyhedron is used.
377
If two polynomials are passed, they must both be quadratics in
378
`\mathbb{P}^3`.
379
380
- ``variables`` -- a list of variables of the parent polynomial
381
ring or ``None`` (default). In the latter case, all variables
382
are taken to be polynomial ring variables. If a subset of
383
polynomial ring variables are given, the Weierstrass form is
384
determined over the function field generated by the remaining
385
variables.
386
387
- ``transformation`` -- boolean (default: ``False``). Whether to
388
return the new variables that bring ``polynomial`` into
389
Weierstrass form.
390
391
OUTPUT:
392
393
The pair of coefficients `(f,g)` of the Weierstrass form `y^2 =
394
x^3 + f x + g` of the hypersurface equation.
395
396
If ``transformation=True``, a triple `(X,Y,Z)` of polynomials
397
defining a rational map of the toric hypersurface or complete
398
intersection in `\mathbb{P}^3` to its Weierstrass form in
399
`\mathbb{P}^2[2,3,1]` is returned.
400
That is, the triple satisfies
401
402
.. math::
403
404
Y^2 = X^3 + f X Z^4 + g Z^6
405
406
when restricted to the toric hypersurface or complete intersection.
407
408
EXAMPLES::
409
410
sage: R.<x,y,z> = QQ[]
411
sage: cubic = x^3 + y^3 + z^3
412
sage: f, g = WeierstrassForm(cubic); (f, g)
413
(0, -27/4)
414
415
Same in inhomogeneous coordinates::
416
417
sage: R.<x,y> = QQ[]
418
sage: cubic = x^3 + y^3 + 1
419
sage: f, g = WeierstrassForm(cubic); (f, g)
420
(0, -27/4)
421
422
sage: X,Y,Z = WeierstrassForm(cubic, transformation=True); (X,Y,Z)
423
(-x^3*y^3 - x^3 - y^3,
424
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,
425
x*y)
426
427
Note that plugging in `[X:Y:Z]` to the Weierstrass equation is a
428
complicated polynomial, but contains the hypersurface equation as
429
a factor::
430
431
sage: -Y^2 + X^3 + f*X*Z^4 + g*Z^6
432
-1/4*x^12*y^6 - 1/2*x^9*y^9 - 1/4*x^6*y^12 + 1/2*x^12*y^3
433
- 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
434
- 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
435
- 7/2*x^3*y^6 - 1/2*y^9 - 1/4*x^6 + 1/2*x^3*y^3 - 1/4*y^6
436
sage: cubic.divides(-Y^2 + X^3 + f*X*Z^4 + g*Z^6)
437
True
438
439
Only the affine span of the Newton polytope of the polynomial
440
matters. For example::
441
442
sage: R.<x,y,z> = QQ[]
443
sage: cubic = x^3 + y^3 + z^3
444
sage: WeierstrassForm(cubic.subs(z=1))
445
(0, -27/4)
446
sage: WeierstrassForm(x * cubic)
447
(0, -27/4)
448
449
This allows you to work with either homogeneous or inhomogeneous
450
variables. For example, here is the del Pezzo surface of degree 8::
451
452
sage: dP8 = toric_varieties.dP8()
453
sage: dP8.inject_variables()
454
Defining t, x, y, z
455
sage: WeierstrassForm(x*y^2 + y^2*z + t^2*x^3 + t^2*z^3)
456
(-3, -2)
457
sage: WeierstrassForm(x*y^2 + y^2 + x^3 + 1)
458
(-3, -2)
459
460
By specifying only certain variables we can compute the
461
Weierstrass form over the function field generated by the
462
remaining variables. For example, here is a cubic over `\QQ[a]` ::
463
464
sage: R.<a, x,y,z> = QQ[]
465
sage: cubic = x^3 + a*y^3 + a^2*z^3
466
sage: WeierstrassForm(cubic, variables=[x,y,z])
467
(0, -27/4*a^6)
468
469
TESTS::
470
471
sage: for P in ReflexivePolytopes(2):
472
....: S = ToricVariety(FaceFan(P))
473
....: p = sum((-S.K()).sections_monomials())
474
....: print WeierstrassForm(p)
475
(-25/48, -1475/864)
476
(-97/48, 17/864)
477
(-25/48, -611/864)
478
(-27/16, 27/32)
479
(47/48, -199/864)
480
(47/48, -71/864)
481
(5/16, -21/32)
482
(23/48, -235/864)
483
(-1/48, 161/864)
484
(-25/48, 253/864)
485
(5/16, 11/32)
486
(-25/48, 125/864)
487
(-67/16, 63/32)
488
(-11/16, 3/32)
489
(-241/48, 3689/864)
490
(215/48, -5291/864)
491
"""
492
if isinstance(polynomial, (list, tuple)):
493
from sage.schemes.toric.weierstrass_higher import WeierstrassForm2
494
return WeierstrassForm2(polynomial, variables=variables, transformation=transformation)
495
if transformation:
496
from sage.schemes.toric.weierstrass_covering import WeierstrassMap
497
return WeierstrassMap(polynomial, variables=variables)
498
if variables is None:
499
variables = polynomial.variables()
500
from sage.geometry.polyhedron.ppl_lattice_polygon import (
501
polar_P2_polytope, polar_P1xP1_polytope, polar_P2_112_polytope)
502
newton_polytope, polynomial, variables = \
503
Newton_polygon_embedded(polynomial, variables)
504
polygon = newton_polytope.embed_in_reflexive_polytope('polytope')
505
if polygon is polar_P2_polytope():
506
return WeierstrassForm_P2(polynomial, variables)
507
if polygon is polar_P1xP1_polytope():
508
return WeierstrassForm_P1xP1(polynomial, variables)
509
if polygon is polar_P2_112_polytope():
510
return WeierstrassForm_P2_112(polynomial, variables)
511
raise ValueError('Newton polytope is not contained in a reflexive polygon')
512
513
514
######################################################################
515
#
516
# Weierstrass form of cubic in P^2
517
#
518
######################################################################
519
def _check_homogeneity(polynomial, variables, weights, total_weight=None):
520
"""
521
Raise ``ValueError`` if the polynomial is not weighted
522
homogeneous.
523
524
INPUT:
525
526
- ``polynomial`` -- the input polynomial. See
527
:func:`WeierstrassForm` for details.
528
529
- ``variables`` -- the variables. See :func:`WeierstrassForm` for
530
details.
531
532
- ``weights`` -- list of integers, one per variable. the weights
533
of the variables.
534
535
- ``total_weight`` -- an integer or ``None`` (default). If an
536
integer is passed, it is also checked that the weighted total
537
degree of polynomial is this value.
538
539
OUTPUT:
540
541
This function returns nothing. If the polynomial is not weighted
542
homogeneous, a ``ValueError`` is raised.
543
544
EXAMPLES::
545
546
sage: from sage.schemes.toric.weierstrass import _check_homogeneity
547
sage: R.<x,y,z,a30,a21,a12,a03,a20,a11,a02,a10,a01,a00> = QQ[]
548
sage: p = (a30*x^3 + a21*x^2*y + a12*x*y^2 + a03*y^3 + a20*x^2*z +
549
....: a11*x*y*z + a02*y^2*z + a10*x*z^2 + a01*y*z^2 + a00*z^3)
550
sage: _check_homogeneity(p, [x,y,z], (1,1,1), 3)
551
552
sage: _check_homogeneity(p+x^4, [x,y,z], (1,1,1), 3)
553
Traceback (most recent call last):
554
...
555
ValueError: The polynomial is not homogeneous with weights (1, 1, 1)
556
"""
557
w = vector(weights)
558
n = w.degree()
559
all_variables = polynomial.parent().gens()
560
variable_indices = [all_variables.index(x) for x in variables]
561
total_weight = None
562
for e in polynomial.exponents():
563
weight_e = sum(e[variable_indices[i]] * weights[i] for i in range(n))
564
if total_weight is None:
565
total_weight = weight_e
566
else:
567
if weight_e != total_weight:
568
raise ValueError('The polynomial is not homogeneous with '
569
'weights '+str(weights))
570
571
572
######################################################################
573
def _extract_coefficients(polynomial, monomials, variables):
574
"""
575
Return the coefficients of ``monomials``.
576
577
INPUT:
578
579
- ``polynomial`` -- the input polynomial
580
581
- ``monomials`` -- a list of monomials in the polynomial ring
582
583
- ``variables`` -- a list of variables in the polynomial ring
584
585
OUTPUT:
586
587
A tuple containing the coefficients of the monomials in the given
588
polynomial.
589
590
EXAMPLES::
591
592
sage: from sage.schemes.toric.weierstrass import _extract_coefficients
593
sage: R.<x,y,z,a30,a21,a12,a03,a20,a11,a02,a10,a01,a00> = QQ[]
594
sage: p = (a30*x^3 + a21*x^2*y + a12*x*y^2 + a03*y^3 + a20*x^2*z +
595
....: a11*x*y*z + a02*y^2*z + a10*x*z^2 + a01*y*z^2 + a00*z^3)
596
sage: 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]
597
sage: _extract_coefficients(p, m, [x,y,z])
598
(a30, a03, a00, a21, a20, a12, a02, a10, a01, a11)
599
600
sage: m = [x^3, y^3, 1, x^2*y, x^2, x*y^2, y^2, x, y, x*y]
601
sage: _extract_coefficients(p.subs(z=1), m, [x,y])
602
(a30, a03, a00, a21, a20, a12, a02, a10, a01, a11)
603
"""
604
R = polynomial.parent()
605
indices = [R.gens().index(x) for x in variables]
606
607
def index(monomial):
608
if monomial in R.base_ring():
609
return tuple(0 for i in indices)
610
e = monomial.exponents()[0]
611
return tuple(e[i] for i in indices)
612
coeffs = dict()
613
for c, m in polynomial:
614
i = index(m)
615
coeffs[i] = c*m + coeffs.pop(i, R.zero())
616
result = tuple(coeffs.pop(index(m), R.zero()) // m for m in monomials)
617
if len(coeffs) != 0:
618
raise ValueError('The polynomial contains more monomials than '
619
'given: '+str(coeffs))
620
return result
621
622
623
######################################################################
624
def _check_polynomial_P2(cubic, variables):
625
"""
626
Check the polynomial is weighted homogeneous in standard variables.
627
628
INPUT:
629
630
- ``cubic`` -- the input polynomial. See
631
:func:`WeierstrassForm` for details.
632
633
- ``variables`` -- the variables or ``None``. See
634
:func:`WeierstrassForm` for details.
635
636
OUTPUT:
637
638
This functions returns ``variables``, potentially guessed from the
639
polynomial ring. A ``ValueError`` is raised if the polynomial is
640
not homogeneous.
641
642
EXAMPLES:
643
644
sage: from sage.schemes.toric.weierstrass import _check_polynomial_P2
645
sage: R.<x,y,z> = QQ[]
646
sage: cubic = x^3+y^3+z^3
647
sage: _check_polynomial_P2(cubic, [x,y,z])
648
(x, y, z)
649
sage: _check_polynomial_P2(cubic, None)
650
(x, y, z)
651
sage: _check_polynomial_P2(cubic.subs(z=1), None)
652
(x, y, None)
653
sage: R.<x,y,z,t> = QQ[]
654
sage: cubic = x^3+y^3+z^3 + t*x*y*z
655
sage: _check_polynomial_P2(cubic, [x,y,z])
656
(x, y, z)
657
sage: _check_polynomial_P2(cubic, [x,y,t])
658
Traceback (most recent call last):
659
...
660
ValueError: The polynomial is not homogeneous with weights (1, 1, 1)
661
"""
662
if variables is None:
663
variables = cubic.variables()
664
if len(variables) == 3:
665
x, y, z = variables
666
_check_homogeneity(cubic, [x, y, z], (1, 1, 1), 3)
667
elif len(variables) == 2:
668
x, y = variables
669
z = None
670
else:
671
raise ValueError('Need two or three variables, got '+str(variables))
672
return (x, y, z)
673
674
675
######################################################################
676
def WeierstrassForm_P2(polynomial, variables=None):
677
r"""
678
Bring a cubic into Weierstrass form.
679
680
Input/output is the same as :func:`WeierstrassForm`, except that
681
the input polynomial must be a standard cubic in `\mathbb{P}^2`,
682
683
.. math::
684
685
\begin{split}
686
p(x,y) =&\;
687
a_{30} x^{3} + a_{21} x^{2} y + a_{12} x y^{2} +
688
a_{03} y^{3} + a_{20} x^{2} +
689
\\ &\;
690
a_{11} x y +
691
a_{02} y^{2} + a_{10} x + a_{01} y + a_{00}
692
\end{split}
693
694
EXAMPLES::
695
696
sage: from sage.schemes.toric.weierstrass import WeierstrassForm_P2
697
sage: R.<x,y,z> = QQ[]
698
sage: WeierstrassForm_P2( x^3+y^3+z^3 )
699
(0, -27/4)
700
701
sage: R.<x,y,z, a,b> = QQ[]
702
sage: WeierstrassForm_P2( -y^2*z+x^3+a*x*z^2+b*z^3, [x,y,z] )
703
(a, b)
704
705
TESTS::
706
707
sage: R.<x,y,z,a30,a21,a12,a03,a20,a11,a02,a10,a01,a00> = QQ[]
708
sage: p = ( a30*x^3 + a21*x^2*y + a12*x*y^2 + a03*y^3 + a20*x^2*z +
709
....: a11*x*y*z + a02*y^2*z + a10*x*z^2 + a01*y*z^2 + a00*z^3 )
710
sage: WeierstrassForm_P2(p, [x,y,z])
711
(-1/48*a11^4 + 1/6*a20*a11^2*a02 - 1/3*a20^2*a02^2 - 1/2*a03*a20*a11*a10
712
+ 1/6*a12*a11^2*a10 + 1/3*a12*a20*a02*a10 - 1/2*a21*a11*a02*a10
713
+ a30*a02^2*a10 - 1/3*a12^2*a10^2 + a21*a03*a10^2 + a03*a20^2*a01
714
- 1/2*a12*a20*a11*a01 + 1/6*a21*a11^2*a01 + 1/3*a21*a20*a02*a01
715
- 1/2*a30*a11*a02*a01 + 1/3*a21*a12*a10*a01 - 3*a30*a03*a10*a01
716
- 1/3*a21^2*a01^2 + a30*a12*a01^2 + a12^2*a20*a00 - 3*a21*a03*a20*a00
717
- 1/2*a21*a12*a11*a00 + 9/2*a30*a03*a11*a00 + a21^2*a02*a00
718
- 3*a30*a12*a02*a00,
719
1/864*a11^6 - 1/72*a20*a11^4*a02 + 1/18*a20^2*a11^2*a02^2
720
- 2/27*a20^3*a02^3 + 1/24*a03*a20*a11^3*a10 - 1/72*a12*a11^4*a10
721
- 1/6*a03*a20^2*a11*a02*a10 + 1/36*a12*a20*a11^2*a02*a10
722
+ 1/24*a21*a11^3*a02*a10 + 1/9*a12*a20^2*a02^2*a10
723
- 1/6*a21*a20*a11*a02^2*a10 - 1/12*a30*a11^2*a02^2*a10
724
+ 1/3*a30*a20*a02^3*a10 + 1/4*a03^2*a20^2*a10^2
725
- 1/6*a12*a03*a20*a11*a10^2 + 1/18*a12^2*a11^2*a10^2
726
- 1/12*a21*a03*a11^2*a10^2 + 1/9*a12^2*a20*a02*a10^2
727
- 1/6*a21*a03*a20*a02*a10^2 - 1/6*a21*a12*a11*a02*a10^2
728
+ a30*a03*a11*a02*a10^2 + 1/4*a21^2*a02^2*a10^2
729
- 2/3*a30*a12*a02^2*a10^2 - 2/27*a12^3*a10^3 + 1/3*a21*a12*a03*a10^3
730
- a30*a03^2*a10^3 - 1/12*a03*a20^2*a11^2*a01 + 1/24*a12*a20*a11^3*a01
731
- 1/72*a21*a11^4*a01 + 1/3*a03*a20^3*a02*a01 - 1/6*a12*a20^2*a11*a02*a01
732
+ 1/36*a21*a20*a11^2*a02*a01 + 1/24*a30*a11^3*a02*a01
733
+ 1/9*a21*a20^2*a02^2*a01 - 1/6*a30*a20*a11*a02^2*a01
734
- 1/6*a12*a03*a20^2*a10*a01 - 1/6*a12^2*a20*a11*a10*a01
735
+ 5/6*a21*a03*a20*a11*a10*a01 + 1/36*a21*a12*a11^2*a10*a01
736
- 3/4*a30*a03*a11^2*a10*a01 + 1/18*a21*a12*a20*a02*a10*a01
737
- 3/2*a30*a03*a20*a02*a10*a01 - 1/6*a21^2*a11*a02*a10*a01
738
+ 5/6*a30*a12*a11*a02*a10*a01 - 1/6*a30*a21*a02^2*a10*a01
739
+ 1/9*a21*a12^2*a10^2*a01 - 2/3*a21^2*a03*a10^2*a01
740
+ a30*a12*a03*a10^2*a01 + 1/4*a12^2*a20^2*a01^2
741
- 2/3*a21*a03*a20^2*a01^2 - 1/6*a21*a12*a20*a11*a01^2
742
+ a30*a03*a20*a11*a01^2 + 1/18*a21^2*a11^2*a01^2
743
- 1/12*a30*a12*a11^2*a01^2 + 1/9*a21^2*a20*a02*a01^2
744
- 1/6*a30*a12*a20*a02*a01^2 - 1/6*a30*a21*a11*a02*a01^2
745
+ 1/4*a30^2*a02^2*a01^2 + 1/9*a21^2*a12*a10*a01^2
746
- 2/3*a30*a12^2*a10*a01^2 + a30*a21*a03*a10*a01^2
747
- 2/27*a21^3*a01^3 + 1/3*a30*a21*a12*a01^3 - a30^2*a03*a01^3
748
- a03^2*a20^3*a00 + a12*a03*a20^2*a11*a00 - 1/12*a12^2*a20*a11^2*a00
749
- 3/4*a21*a03*a20*a11^2*a00 + 1/24*a21*a12*a11^3*a00
750
+ 5/8*a30*a03*a11^3*a00 - 2/3*a12^2*a20^2*a02*a00
751
+ a21*a03*a20^2*a02*a00 + 5/6*a21*a12*a20*a11*a02*a00
752
- 3/2*a30*a03*a20*a11*a02*a00 - 1/12*a21^2*a11^2*a02*a00
753
- 3/4*a30*a12*a11^2*a02*a00 - 2/3*a21^2*a20*a02^2*a00
754
+ a30*a12*a20*a02^2*a00 + a30*a21*a11*a02^2*a00
755
- a30^2*a02^3*a00 + 1/3*a12^3*a20*a10*a00
756
- 3/2*a21*a12*a03*a20*a10*a00 + 9/2*a30*a03^2*a20*a10*a00
757
- 1/6*a21*a12^2*a11*a10*a00 + a21^2*a03*a11*a10*a00
758
- 3/2*a30*a12*a03*a11*a10*a00 - 1/6*a21^2*a12*a02*a10*a00
759
+ a30*a12^2*a02*a10*a00 - 3/2*a30*a21*a03*a02*a10*a00
760
- 1/6*a21*a12^2*a20*a01*a00 + a21^2*a03*a20*a01*a00
761
- 3/2*a30*a12*a03*a20*a01*a00 - 1/6*a21^2*a12*a11*a01*a00
762
+ a30*a12^2*a11*a01*a00 - 3/2*a30*a21*a03*a11*a01*a00
763
+ 1/3*a21^3*a02*a01*a00 - 3/2*a30*a21*a12*a02*a01*a00
764
+ 9/2*a30^2*a03*a02*a01*a00 + 1/4*a21^2*a12^2*a00^2
765
- a30*a12^3*a00^2 - a21^3*a03*a00^2
766
+ 9/2*a30*a21*a12*a03*a00^2 - 27/4*a30^2*a03^2*a00^2)
767
"""
768
x, y, z = _check_polynomial_P2(polynomial, variables)
769
cubic = invariant_theory.ternary_cubic(polynomial, x, y, z)
770
F = polynomial.base_ring()
771
S = cubic.S_invariant()
772
T = cubic.T_invariant()
773
return (27*S, -27/F(4)*T)
774
775
776
######################################################################
777
#
778
# Weierstrass form of biquadric in P1 x P1
779
#
780
######################################################################
781
def _check_polynomial_P1xP1(biquadric, variables):
782
"""
783
Check the polynomial is weighted homogeneous in standard variables.
784
785
INPUT:
786
787
- ``biquadric`` -- the input polynomial. See
788
:func:`WeierstrassForm` for details.
789
790
- ``variables`` -- the variables or ``None``. See
791
:func:`WeierstrassForm` for details.
792
793
OUTPUT:
794
795
This functions returns ``variables``, potentially guessed from the
796
polynomial ring. A ``ValueError`` is raised if the polynomial is
797
not homogeneous.
798
799
EXAMPLES::
800
801
sage: from sage.schemes.toric.weierstrass import _check_polynomial_P1xP1
802
sage: R.<x0,x1,y0,y1> = QQ[]
803
sage: biquadric = ( x0^2*y0^2 + x0*x1*y0^2*2 + x1^2*y0^2*3
804
....: + x0^2*y0*y1*4 + x0*x1*y0*y1*5 + x1^2*y0*y1*6
805
....: + x0^2*y1^2*7 + x0*x1*y1^2*8 )
806
sage: _check_polynomial_P1xP1(biquadric, [x0,x1,y0,y1])
807
[x0, x1, y0, y1]
808
sage: _check_polynomial_P1xP1(biquadric, None)
809
(x0, x1, y0, y1)
810
sage: _check_polynomial_P1xP1(biquadric.subs(y0=1, y1=1), None)
811
[x0, None, x1, None]
812
sage: _check_polynomial_P1xP1(biquadric, [x0,y0,x1,y1])
813
Traceback (most recent call last):
814
...
815
ValueError: The polynomial is not homogeneous with weights (1, 1, 0, 0)
816
"""
817
if variables is None:
818
variables = biquadric.variables()
819
if len(variables) == 4:
820
_check_homogeneity(biquadric, variables, (1, 1, 0, 0), 2)
821
_check_homogeneity(biquadric, variables, (0, 0, 1, 1), 2)
822
elif len(variables) == 2:
823
variables = [variables[0], None, variables[1], None]
824
else:
825
raise ValueError('Need two or four variables, got '+str(variables))
826
return variables
827
828
829
######################################################################
830
def _partial_discriminant(quadric, y0, y1=None):
831
"""
832
Return the partial discriminant wrt. `(y_0, y_1)`.
833
834
INPUT:
835
836
- ``quadric`` -- a biquadric.
837
838
- ``y_0``, ``y_1`` -- the variables of the quadric. The ``y_1``
839
variable can be omitted if the quadric is inhomogeneous.
840
841
OUTPUT:
842
843
A plane quartic in ``x0``, ``x1``.
844
845
EXAMPLES::
846
847
sage: R.<x0,x1,y0,y1,a00,a10,a20,a01,a11,a21,a02,a12,a22> = QQ[]
848
sage: biquadric = ( x0^2*y0^2*a00 + x0*x1*y0^2*a10 + x1^2*y0^2*a20
849
....: + x0^2*y0*y1*a01 + x0*x1*y0*y1*a11 + x1^2*y0*y1*a21
850
....: + x0^2*y1^2*a02 + x0*x1*y1^2*a12 + x1^2*y1^2*a22 )
851
sage: from sage.schemes.toric.weierstrass import _partial_discriminant
852
sage: _partial_discriminant(biquadric, y0, y1)
853
x0^4*a01^2 + 2*x0^3*x1*a01*a11 + x0^2*x1^2*a11^2
854
+ 2*x0^2*x1^2*a01*a21 + 2*x0*x1^3*a11*a21 + x1^4*a21^2
855
- 4*x0^4*a00*a02 - 4*x0^3*x1*a10*a02 - 4*x0^2*x1^2*a20*a02
856
- 4*x0^3*x1*a00*a12 - 4*x0^2*x1^2*a10*a12 - 4*x0*x1^3*a20*a12
857
- 4*x0^2*x1^2*a00*a22 - 4*x0*x1^3*a10*a22 - 4*x1^4*a20*a22
858
sage: _partial_discriminant(biquadric, x0, x1)
859
y0^4*a10^2 - 4*y0^4*a00*a20 - 4*y0^3*y1*a20*a01
860
+ 2*y0^3*y1*a10*a11 + y0^2*y1^2*a11^2 - 4*y0^3*y1*a00*a21
861
- 4*y0^2*y1^2*a01*a21 - 4*y0^2*y1^2*a20*a02 - 4*y0*y1^3*a21*a02
862
+ 2*y0^2*y1^2*a10*a12 + 2*y0*y1^3*a11*a12 + y1^4*a12^2
863
- 4*y0^2*y1^2*a00*a22 - 4*y0*y1^3*a01*a22 - 4*y1^4*a02*a22
864
"""
865
if y1 is None:
866
monomials = (quadric.parent().one(), y0, y0**2)
867
variables = [y0]
868
else:
869
monomials = (y1**2, y0*y1, y0**2)
870
variables = [y0, y1]
871
c = _extract_coefficients(quadric, monomials, variables)
872
return c[1]**2 - 4*c[0]*c[2]
873
874
875
######################################################################
876
def WeierstrassForm_P1xP1(biquadric, variables=None):
877
r"""
878
Bring a biquadric into Weierstrass form
879
880
Input/output is the same as :func:`WeierstrassForm`, except that
881
the input polynomial must be a standard biquadric in `\mathbb{P}^2`,
882
883
.. math::
884
885
\begin{split}
886
p(x,y) =&\;
887
a_{40} x^4 +
888
a_{30} x^3 +
889
a_{21} x^2 y +
890
a_{20} x^2 +
891
\\ &\;
892
a_{11} x y +
893
a_{02} y^2 +
894
a_{10} x +
895
a_{01} y +
896
a_{00}
897
\end{split}
898
899
EXAMPLES::
900
901
sage: from sage.schemes.toric.weierstrass import WeierstrassForm_P1xP1
902
sage: R.<x0,x1,y0,y1>= QQ[]
903
sage: biquadric = ( x0^2*y0^2 + x0*x1*y0^2*2 + x1^2*y0^2*3
904
....: + x0^2*y0*y1*4 + x0*x1*y0*y1*5 + x1^2*y0*y1*6
905
....: + x0^2*y1^2*7 + x0*x1*y1^2*8 )
906
sage: WeierstrassForm_P1xP1(biquadric, [x0, x1, y0, y1])
907
(1581/16, -3529/32)
908
909
Since there is no `x_1^2 y_1^2` term in ``biquadric``, we can
910
dehomogenize it and get a cubic::
911
912
sage: from sage.schemes.toric.weierstrass import WeierstrassForm_P2
913
sage: WeierstrassForm_P2(biquadric(x0=1,y0=1))
914
(1581/16, -3529/32)
915
916
TESTS::
917
918
sage: R.<x0,x1,y0,y1,a00,a10,a20,a01,a11,a21,a02,a12,a22> = QQ[]
919
sage: biquadric = ( x0^2*y0^2*a00 + x0*x1*y0^2*a10 + x1^2*y0^2*a20
920
....: + x0^2*y0*y1*a01 + x0*x1*y0*y1*a11 + x1^2*y0*y1*a21
921
....: + x0^2*y1^2*a02 + x0*x1*y1^2*a12 )
922
sage: WeierstrassForm_P1xP1(biquadric, [x0, x1, y0, y1])
923
(-1/48*a11^4 + 1/6*a01*a11^2*a21 - 1/3*a01^2*a21^2
924
+ 1/6*a20*a11^2*a02 + 1/3*a20*a01*a21*a02 - 1/2*a10*a11*a21*a02
925
+ a00*a21^2*a02 - 1/3*a20^2*a02^2 - 1/2*a20*a01*a11*a12
926
+ 1/6*a10*a11^2*a12 + 1/3*a10*a01*a21*a12 - 1/2*a00*a11*a21*a12
927
+ 1/3*a10*a20*a02*a12 - 1/3*a10^2*a12^2 + a00*a20*a12^2, 1/864*a11^6
928
- 1/72*a01*a11^4*a21 + 1/18*a01^2*a11^2*a21^2 - 2/27*a01^3*a21^3
929
- 1/72*a20*a11^4*a02 + 1/36*a20*a01*a11^2*a21*a02
930
+ 1/24*a10*a11^3*a21*a02 + 1/9*a20*a01^2*a21^2*a02
931
- 1/6*a10*a01*a11*a21^2*a02 - 1/12*a00*a11^2*a21^2*a02
932
+ 1/3*a00*a01*a21^3*a02 + 1/18*a20^2*a11^2*a02^2
933
+ 1/9*a20^2*a01*a21*a02^2 - 1/6*a10*a20*a11*a21*a02^2
934
+ 1/4*a10^2*a21^2*a02^2 - 2/3*a00*a20*a21^2*a02^2 - 2/27*a20^3*a02^3
935
+ 1/24*a20*a01*a11^3*a12 - 1/72*a10*a11^4*a12
936
- 1/6*a20*a01^2*a11*a21*a12 + 1/36*a10*a01*a11^2*a21*a12
937
+ 1/24*a00*a11^3*a21*a12 + 1/9*a10*a01^2*a21^2*a12
938
- 1/6*a00*a01*a11*a21^2*a12 - 1/6*a20^2*a01*a11*a02*a12
939
+ 1/36*a10*a20*a11^2*a02*a12 + 1/18*a10*a20*a01*a21*a02*a12
940
- 1/6*a10^2*a11*a21*a02*a12 + 5/6*a00*a20*a11*a21*a02*a12
941
- 1/6*a00*a10*a21^2*a02*a12 + 1/9*a10*a20^2*a02^2*a12
942
+ 1/4*a20^2*a01^2*a12^2 - 1/6*a10*a20*a01*a11*a12^2
943
+ 1/18*a10^2*a11^2*a12^2 - 1/12*a00*a20*a11^2*a12^2
944
+ 1/9*a10^2*a01*a21*a12^2 - 1/6*a00*a20*a01*a21*a12^2
945
- 1/6*a00*a10*a11*a21*a12^2 + 1/4*a00^2*a21^2*a12^2
946
+ 1/9*a10^2*a20*a02*a12^2 - 2/3*a00*a20^2*a02*a12^2
947
- 2/27*a10^3*a12^3 + 1/3*a00*a10*a20*a12^3)
948
949
sage: _ == WeierstrassForm_P1xP1(biquadric.subs(x1=1,y1=1), [x0, y0])
950
True
951
"""
952
x, y, s, t = _check_polynomial_P1xP1(biquadric, variables)
953
delta = _partial_discriminant(biquadric, s, t)
954
Q = invariant_theory.binary_quartic(delta, x, y)
955
g2 = Q.EisensteinD()
956
g3 = -Q.EisensteinE()
957
return (-g2/4, -g3/4)
958
959
960
######################################################################
961
#
962
# Weierstrass form of anticanonical hypersurface in WP2[1,1,2]
963
#
964
######################################################################
965
def _check_polynomial_P2_112(polynomial, variables):
966
"""
967
Check the polynomial is weighted homogeneous in standard variables.
968
969
INPUT:
970
971
- ``polynomial`` -- the input polynomial. See
972
:func:`WeierstrassForm` for details.
973
974
- ``variables`` -- the variables or ``None``. See
975
:func:`WeierstrassForm` for details.
976
977
OUTPUT:
978
979
This functions returns ``variables``, potentially guessed from the
980
polynomial ring. A ``ValueError`` is raised if the polynomial is
981
not homogeneous.
982
983
EXAMPLES:
984
985
sage: from sage.schemes.toric.weierstrass import _check_polynomial_P2_112
986
sage: R.<x,y,z,t> = QQ[]
987
sage: polynomial = z^4*t^2 + x*z^3*t^2 + x^2*z^2*t^2 + x^3*z*t^2 + \
988
....: x^4*t^2 + y*z^2*t + x*y*z*t + x^2*y*t + y^2
989
sage: _check_polynomial_P2_112(polynomial, [x,y,z,t])
990
(x, y, z, t)
991
sage: _check_polynomial_P2_112(polynomial, None)
992
(x, y, z, t)
993
sage: _check_polynomial_P2_112(polynomial(z=1, t=1), None)
994
(x, y, None, None)
995
sage: _check_polynomial_P2_112(polynomial, [x,y,t,z])
996
Traceback (most recent call last):
997
...
998
ValueError: The polynomial is not homogeneous with weights (1, 0, 1, -2)
999
"""
1000
if variables is None:
1001
variables = polynomial.variables()
1002
else:
1003
variables = tuple(variables)
1004
if len(variables) == 4:
1005
_check_homogeneity(polynomial, variables, (1, 0, 1, -2), 0)
1006
_check_homogeneity(polynomial, variables, (0, 1, 0, 1), 2)
1007
elif len(variables) == 2:
1008
variables = tuple([variables[0], variables[1], None, None])
1009
else:
1010
raise ValueError('Need two or four variables, got '+str(variables))
1011
return variables
1012
1013
1014
def WeierstrassForm_P2_112(polynomial, variables=None):
1015
r"""
1016
Bring an anticanonical hypersurface in `\mathbb{P}^2[1,1,2]` into Weierstrass form.
1017
1018
Input/output is the same as :func:`WeierstrassForm`, except that
1019
the input polynomial must be a standard anticanonical hypersurface
1020
in weighted projective space `\mathbb{P}^2[1,1,2]`:
1021
1022
.. math::
1023
1024
\begin{split}
1025
p(x,y) =&\;
1026
a_{40} x^4 +
1027
a_{30} x^3 +
1028
a_{21} x^2 y +
1029
a_{20} x^2 +
1030
\\ &\;
1031
a_{11} x y +
1032
a_{02} y^2 +
1033
a_{10} x +
1034
a_{01} y +
1035
a_{00}
1036
\end{split}
1037
1038
EXAMPLES::
1039
1040
sage: from sage.schemes.toric.weierstrass import WeierstrassForm_P2_112
1041
sage: fan = Fan(rays=[(1,0),(0,1),(-1,-2),(0,-1)],cones=[[0,1],[1,2],[2,3],[3,0]])
1042
sage: P112.<x,y,z,t> = ToricVariety(fan)
1043
sage: (-P112.K()).sections_monomials()
1044
(z^4*t^2, x*z^3*t^2, x^2*z^2*t^2, x^3*z*t^2,
1045
x^4*t^2, y*z^2*t, x*y*z*t, x^2*y*t, y^2)
1046
sage: WeierstrassForm_P2_112(sum(_), [x,y,z,t])
1047
(-97/48, 17/864)
1048
1049
TESTS::
1050
1051
sage: R.<x,y,z,t,a40,a30,a20,a10,a00,a21,a11,a01,a02> = QQ[]
1052
sage: 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 +
1053
....: a00*z^4*t^2 + a21*x^2*y*t + a11*x*y*z*t + a01*y*z^2*t + a02*y^2 )
1054
sage: WeierstrassForm_P2_112(p, [x,y,z,t])
1055
(-1/48*a11^4 + 1/6*a21*a11^2*a01 - 1/3*a21^2*a01^2 + a00*a21^2*a02
1056
- 1/2*a10*a21*a11*a02 + 1/6*a20*a11^2*a02 + 1/3*a20*a21*a01*a02
1057
- 1/2*a30*a11*a01*a02 + a40*a01^2*a02 - 1/3*a20^2*a02^2 + a30*a10*a02^2
1058
- 4*a40*a00*a02^2, 1/864*a11^6 - 1/72*a21*a11^4*a01
1059
+ 1/18*a21^2*a11^2*a01^2 - 2/27*a21^3*a01^3 - 1/12*a00*a21^2*a11^2*a02
1060
+ 1/24*a10*a21*a11^3*a02 - 1/72*a20*a11^4*a02 + 1/3*a00*a21^3*a01*a02
1061
- 1/6*a10*a21^2*a11*a01*a02 + 1/36*a20*a21*a11^2*a01*a02
1062
+ 1/24*a30*a11^3*a01*a02 + 1/9*a20*a21^2*a01^2*a02
1063
- 1/6*a30*a21*a11*a01^2*a02 - 1/12*a40*a11^2*a01^2*a02
1064
+ 1/3*a40*a21*a01^3*a02 + 1/4*a10^2*a21^2*a02^2
1065
- 2/3*a20*a00*a21^2*a02^2 - 1/6*a20*a10*a21*a11*a02^2
1066
+ a30*a00*a21*a11*a02^2 + 1/18*a20^2*a11^2*a02^2
1067
- 1/12*a30*a10*a11^2*a02^2 - 2/3*a40*a00*a11^2*a02^2
1068
+ 1/9*a20^2*a21*a01*a02^2 - 1/6*a30*a10*a21*a01*a02^2
1069
- 4/3*a40*a00*a21*a01*a02^2 - 1/6*a30*a20*a11*a01*a02^2
1070
+ a40*a10*a11*a01*a02^2 + 1/4*a30^2*a01^2*a02^2
1071
- 2/3*a40*a20*a01^2*a02^2 - 2/27*a20^3*a02^3
1072
+ 1/3*a30*a20*a10*a02^3 - a40*a10^2*a02^3 - a30^2*a00*a02^3
1073
+ 8/3*a40*a20*a00*a02^3)
1074
1075
sage: _ == WeierstrassForm_P2_112(p.subs(z=1,t=1), [x,y])
1076
True
1077
1078
sage: cubic = p.subs(a40=0)
1079
sage: a,b = WeierstrassForm_P2_112(cubic, [x,y,z,t])
1080
sage: a = a.subs(t=1,z=1)
1081
sage: b = b.subs(t=1,z=1)
1082
sage: from sage.schemes.toric.weierstrass import WeierstrassForm_P2
1083
sage: (a,b) == WeierstrassForm_P2(cubic.subs(t=1,z=1), [x,y])
1084
True
1085
"""
1086
x, y, z, t = _check_polynomial_P2_112(polynomial, variables)
1087
delta = _partial_discriminant(polynomial, y, t)
1088
Q = invariant_theory.binary_quartic(delta, x, z)
1089
g2 = Q.EisensteinD()
1090
g3 = -Q.EisensteinE()
1091
return (-g2/4, -g3/4)
1092
1093