Skip to content

Commit faee909

Browse files
author
Release Manager
committed
gh-40528: Minor refactor for hyperelliptic curve As in the title. See the code for detail. ### 📝 Checklist <!-- Put an `x` in all the boxes that apply. --> - [x] The title is concise and informative. - [ ] The description explains in detail what this PR is about. - [ ] I have linked a relevant issue or discussion. - [ ] I have created tests covering the changes. - [x] I have updated the documentation and checked the documentation preview. ### ⌛ Dependencies <!-- List all open PRs that this PR logically depends on. For example, --> <!-- - #12345: short description why this is a dependency --> <!-- - #34567: ... --> URL: #40528 Reported by: user202729 Reviewer(s): Michael Orlitzky, user202729
2 parents f508131 + ea74b42 commit faee909

File tree

3 files changed

+133
-61
lines changed

3 files changed

+133
-61
lines changed

src/sage/misc/superseded.py

Lines changed: 39 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -350,15 +350,18 @@ class DeprecatedFunctionAlias:
350350
- Florent Hivert (2009-11-23), with the help of Mike Hansen.
351351
- Luca De Feo (2011-07-11), printing the full module path when different from old path
352352
"""
353-
def __init__(self, issue_number, func, module, instance=None, unbound=None):
353+
def __init__(self, issue_number, func, module, instance=None, unbound=None, *, replacement=None, replacement_rst_doc=None):
354354
r"""
355355
TESTS::
356356
357+
sage: # needs sage.combinat
357358
sage: from sage.misc.superseded import deprecated_function_alias
358-
sage: g = deprecated_function_alias(13109, number_of_partitions) # needs sage.combinat
359-
sage: from sage.misc.superseded import deprecated_function_alias
360-
sage: g.__doc__ # needs sage.combinat
359+
sage: g = deprecated_function_alias(13109, number_of_partitions)
360+
sage: g.__doc__
361361
'Deprecated: Use :func:`number_of_partitions` instead.\nSee :issue:`13109` for details.\n\n'
362+
sage: g = deprecated_function_alias(13109, number_of_partitions, replacement_rst_doc='BLOB')
363+
sage: g.__doc__
364+
'Deprecated: Use BLOB instead.\nSee :issue:`13109` for details.\n\n'
362365
"""
363366
_check_issue_number(issue_number)
364367
try:
@@ -369,14 +372,15 @@ def __init__(self, issue_number, func, module, instance=None, unbound=None):
369372
self.issue_number = issue_number
370373
self.instance = instance # for use with methods
371374
self.unbound = unbound
375+
self._replacement = replacement
372376
self.__module__ = module
373-
if isinstance(func, type(deprecation)):
374-
sphinxrole = "func"
375-
else:
376-
sphinxrole = "meth"
377-
doc = 'Deprecated: '
378-
doc += 'Use :' + sphinxrole + ':`' + self.func.__name__ + '` instead.\n'
379-
doc += 'See :issue:`' + str(self.issue_number) + '` for details.\n\n'
377+
if replacement_rst_doc is None:
378+
if isinstance(func, type(deprecation)):
379+
replacement_rst_doc = f":func:`{self.func.__name__}`"
380+
else:
381+
replacement_rst_doc = f":meth:`{self.func.__name__}`"
382+
doc = f'Deprecated: Use {replacement_rst_doc} instead.\n'
383+
doc += f'See :issue:`{self.issue_number}` for details.\n\n'
380384
self.__doc__ = doc
381385

382386
@lazy_attribute
@@ -389,7 +393,6 @@ def __name__(self):
389393
sage: g.__name__ # needs sage.combinat
390394
'g'
391395
392-
sage: from sage.misc.superseded import deprecated_function_alias
393396
sage: class cls():
394397
....: def new_meth(self): return 42
395398
....: old_meth = deprecated_function_alias(13109, new_meth)
@@ -444,15 +447,21 @@ def __call__(self, *args, **kwds):
444447
doctest:...: DeprecationWarning: blo is deprecated. Please use bla instead.
445448
See https://github.com/sagemath/sage/issues/13109 for details.
446449
42
450+
sage: blo = deprecated_function_alias(13109, bla, replacement='BLOB')
451+
sage: blo()
452+
doctest:...: DeprecationWarning: blo is deprecated. Please use BLOB instead.
453+
See https://github.com/sagemath/sage/issues/13109 for details.
454+
42
447455
"""
448-
if self.instance is None and self.__module__ != self.func.__module__:
449-
other = self.func.__module__ + "." + self.func.__name__
450-
else:
451-
other = self.func.__name__
456+
replacement = self._replacement
457+
if replacement is None:
458+
if self.instance is None and self.__module__ != self.func.__module__:
459+
replacement = self.func.__module__ + "." + self.func.__name__
460+
else:
461+
replacement = self.func.__name__
452462

453463
deprecation(self.issue_number,
454-
"{} is deprecated. Please use {} instead.".format(
455-
self.__name__, other))
464+
f"{self.__name__} is deprecated. Please use {replacement} instead.")
456465
if self.instance is None:
457466
return self.func(*args, **kwds)
458467
else:
@@ -497,7 +506,7 @@ def __get__(self, inst, cls=None):
497506
unbound=self)
498507

499508

500-
def deprecated_function_alias(issue_number, func):
509+
def deprecated_function_alias(issue_number, func, *, replacement=None, replacement_rst_doc=None):
501510
"""
502511
Create an aliased version of a function or a method which raises a
503512
deprecation warning message.
@@ -513,6 +522,15 @@ def deprecated_function_alias(issue_number, func):
513522
514523
- ``func`` -- the function or method to be aliased
515524
525+
- ``replacement`` -- a plain text string to be inserted
526+
into the warning message to describe the replacement.
527+
If unspecified, use the name of ``func``.
528+
529+
- ``replacement_rst_doc`` -- a reStructuredText snippet to be inserted
530+
into the user documentation to describe the replacement.
531+
If unspecified, this is constructed from the name of ``func``,
532+
with either the ``:meth:`` or the ``:func:`` role, as appropriate.
533+
516534
EXAMPLES::
517535
518536
sage: from sage.misc.superseded import deprecated_function_alias
@@ -554,4 +572,5 @@ def deprecated_function_alias(issue_number, func):
554572
module_name = inspect.getmodulename(frame1.f_code.co_filename)
555573
if module_name is None:
556574
module_name = '__main__'
557-
return DeprecatedFunctionAlias(issue_number, func, module_name)
575+
return DeprecatedFunctionAlias(issue_number, func, module_name,
576+
replacement=replacement, replacement_rst_doc=replacement_rst_doc)

src/sage/schemes/hyperelliptic_curves/hyperelliptic_finite_field.py

Lines changed: 76 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@
5757
from sage.rings.power_series_ring import PowerSeriesRing
5858
from . import hyperelliptic_generic
5959
from sage.misc.cachefunc import cached_method
60+
from sage.misc.superseded import deprecated_function_alias
6061
from sage.matrix.constructor import identity_matrix, matrix
6162
from sage.misc.functional import rank
6263
from sage.misc.lazy_import import lazy_import
@@ -297,7 +298,7 @@ def frobenius_matrix(self, N=None, algorithm='hypellfrob'):
297298
ValueError: In the current implementation, p must be greater than (2g+1)(2N-1) = 81
298299
"""
299300
if algorithm != 'hypellfrob':
300-
raise ValueError("Unknown algorithm")
301+
raise ValueError("unknown algorithm")
301302

302303
# By default, use precision enough to be able to compute the
303304
# frobenius minimal polynomial
@@ -306,48 +307,41 @@ def frobenius_matrix(self, N=None, algorithm='hypellfrob'):
306307

307308
return self.frobenius_matrix_hypellfrob(N=N)
308309

309-
def frobenius_polynomial_cardinalities(self, a=None):
310+
def _frobenius_polynomial_cardinalities(self, a=None):
310311
r"""
311-
Compute the charpoly of frobenius, as an element of `\ZZ[x]`,
312-
by computing the number of points on the curve over `g` extensions
313-
of the base field where `g` is the genus of the curve.
314-
315-
.. WARNING::
316-
317-
This is highly inefficient when the base field or the genus of the
318-
curve are large.
312+
Helper method for :meth:`frobenius_polynomial`.
319313
320314
EXAMPLES::
321315
322316
sage: R.<t> = PolynomialRing(GF(37))
323317
sage: H = HyperellipticCurve(t^5 + t + 2)
324-
sage: H.frobenius_polynomial_cardinalities()
318+
sage: H.frobenius_polynomial(algorithm='cardinalities')
325319
x^4 + x^3 - 52*x^2 + 37*x + 1369
326320
327321
A quadratic twist::
328322
329323
sage: H = HyperellipticCurve(2*t^5 + 2*t + 4)
330-
sage: H.frobenius_polynomial_cardinalities()
324+
sage: H.frobenius_polynomial(algorithm='cardinalities')
331325
x^4 - x^3 - 52*x^2 - 37*x + 1369
332326
333327
Curve over a non-prime field::
334328
335329
sage: K.<z> = GF(7**2)
336330
sage: R.<t> = PolynomialRing(K)
337331
sage: H = HyperellipticCurve(t^5 + z*t + z^2)
338-
sage: H.frobenius_polynomial_cardinalities()
332+
sage: H.frobenius_polynomial(algorithm='cardinalities')
339333
x^4 + 8*x^3 + 70*x^2 + 392*x + 2401
340334
341335
This method may actually be useful when ``hypellfrob`` does not work::
342336
343337
sage: K = GF(7)
344338
sage: R.<t> = PolynomialRing(K)
345339
sage: H = HyperellipticCurve(t^9 + t^3 + 1)
346-
sage: H.frobenius_polynomial_matrix(algorithm='hypellfrob')
340+
sage: H.frobenius_polynomial(algorithm='matrix')
347341
Traceback (most recent call last):
348342
...
349343
ValueError: In the current implementation, p must be greater than (2g+1)(2N-1) = 81
350-
sage: H.frobenius_polynomial_cardinalities()
344+
sage: H.frobenius_polynomial(algorithm='cardinalities')
351345
x^8 - 5*x^7 + 7*x^6 + 36*x^5 - 180*x^4 + 252*x^3 + 343*x^2 - 1715*x + 2401
352346
"""
353347
g = self.genus()
@@ -372,37 +366,33 @@ def frobenius_polynomial_cardinalities(self, a=None):
372366

373367
return ZZ['x'](coeffs).reverse()
374368

375-
def frobenius_polynomial_matrix(self, M=None, algorithm='hypellfrob'):
369+
def _frobenius_polynomial_matrix(self, M=None, algorithm='hypellfrob'):
376370
r"""
377-
Compute the charpoly of frobenius, as an element of `\ZZ[x]`,
378-
by computing the charpoly of the frobenius matrix.
379-
380-
This is currently only supported when the base field is prime
381-
and large enough using the ``hypellfrob`` library.
371+
Helper method for :meth:`frobenius_polynomial`.
382372
383373
EXAMPLES::
384374
385375
sage: R.<t> = PolynomialRing(GF(37))
386376
sage: H = HyperellipticCurve(t^5 + t + 2)
387-
sage: H.frobenius_polynomial_matrix()
377+
sage: H.frobenius_polynomial(algorithm='matrix')
388378
x^4 + x^3 - 52*x^2 + 37*x + 1369
389379
390380
A quadratic twist::
391381
392382
sage: H = HyperellipticCurve(2*t^5 + 2*t + 4)
393-
sage: H.frobenius_polynomial_matrix()
383+
sage: H.frobenius_polynomial(algorithm='matrix')
394384
x^4 - x^3 - 52*x^2 - 37*x + 1369
395385
396386
Curves defined over larger prime fields::
397387
398388
sage: K = GF(49999)
399389
sage: R.<t> = PolynomialRing(K)
400390
sage: H = HyperellipticCurve(t^9 + t^5 + 1)
401-
sage: H.frobenius_polynomial_matrix()
391+
sage: H.frobenius_polynomial(algorithm='matrix')
402392
x^8 + 281*x^7 + 55939*x^6 + 14144175*x^5 + 3156455369*x^4 + 707194605825*x^3
403393
+ 139841906155939*x^2 + 35122892542149719*x + 6249500014999800001
404394
sage: H = HyperellipticCurve(t^15 + t^5 + 1)
405-
sage: H.frobenius_polynomial_matrix() # long time, 8s on a Corei7
395+
sage: H.frobenius_polynomial(algorithm='matrix') # long time, 8s on a Corei7
406396
x^14 - 76*x^13 + 220846*x^12 - 12984372*x^11 + 24374326657*x^10 - 1203243210304*x^9
407397
+ 1770558798515792*x^8 - 74401511415210496*x^7 + 88526169366991084208*x^6
408398
- 3007987702642212810304*x^5 + 3046608028331197124223343*x^4
@@ -440,52 +430,51 @@ def frobenius_polynomial_matrix(self, M=None, algorithm='hypellfrob'):
440430

441431
return ZZ['x'](f)
442432

443-
def frobenius_polynomial_pari(self):
433+
def _frobenius_polynomial_pari(self):
444434
r"""
445-
Compute the charpoly of frobenius, as an element of `\ZZ[x]`,
446-
by calling the PARI function ``hyperellcharpoly``.
435+
Helper method for :meth:`frobenius_polynomial`.
447436
448437
EXAMPLES::
449438
450439
sage: R.<t> = PolynomialRing(GF(37))
451440
sage: H = HyperellipticCurve(t^5 + t + 2)
452-
sage: H.frobenius_polynomial_pari()
441+
sage: H.frobenius_polynomial(algorithm='pari')
453442
x^4 + x^3 - 52*x^2 + 37*x + 1369
454443
455444
A quadratic twist::
456445
457446
sage: H = HyperellipticCurve(2*t^5 + 2*t + 4)
458-
sage: H.frobenius_polynomial_pari()
447+
sage: H.frobenius_polynomial(algorithm='pari')
459448
x^4 - x^3 - 52*x^2 - 37*x + 1369
460449
461450
Slightly larger example::
462451
463452
sage: K = GF(2003)
464453
sage: R.<t> = PolynomialRing(K)
465454
sage: H = HyperellipticCurve(t^7 + 487*t^5 + 9*t + 1)
466-
sage: H.frobenius_polynomial_pari()
455+
sage: H.frobenius_polynomial(algorithm='pari')
467456
x^6 - 14*x^5 + 1512*x^4 - 66290*x^3 + 3028536*x^2 - 56168126*x + 8036054027
468457
469458
Curves defined over a non-prime field are supported as well::
470459
471460
sage: K.<a> = GF(7^2)
472461
sage: R.<t> = PolynomialRing(K)
473462
sage: H = HyperellipticCurve(t^5 + a*t + 1)
474-
sage: H.frobenius_polynomial_pari()
463+
sage: H.frobenius_polynomial(algorithm='pari')
475464
x^4 + 4*x^3 + 84*x^2 + 196*x + 2401
476465
477466
sage: K.<z> = GF(23**3)
478467
sage: R.<t> = PolynomialRing(K)
479468
sage: H = HyperellipticCurve(t^3 + z*t + 4)
480-
sage: H.frobenius_polynomial_pari()
469+
sage: H.frobenius_polynomial(algorithm='pari')
481470
x^2 - 15*x + 12167
482471
483472
Over prime fields of odd characteristic, `h` may be nonzero::
484473
485474
sage: K = GF(101)
486475
sage: R.<t> = PolynomialRing(K)
487476
sage: H = HyperellipticCurve(t^5 + 27*t + 3, t)
488-
sage: H.frobenius_polynomial_pari()
477+
sage: H.frobenius_polynomial(algorithm='pari')
489478
x^4 + 2*x^3 - 58*x^2 + 202*x + 10201
490479
491480
TESTS:
@@ -495,17 +484,54 @@ def frobenius_polynomial_pari(self):
495484
sage: P.<x> = PolynomialRing(GF(3))
496485
sage: u = x^10 + x^9 + x^8 + x
497486
sage: C = HyperellipticCurve(u)
498-
sage: C.frobenius_polynomial_pari()
487+
sage: C.frobenius_polynomial(algorithm='pari')
499488
x^8 + 2*x^7 + 6*x^6 + 9*x^5 + 18*x^4 + 27*x^3 + 54*x^2 + 54*x + 81
500489
"""
501490
f, h = self.hyperelliptic_polynomials()
502491
return ZZ['x'](pari([f, h]).hyperellcharpoly())
503492

493+
frobenius_polynomial_cardinalities = deprecated_function_alias(
494+
40528, _frobenius_polynomial_cardinalities,
495+
replacement='frobenius_polynomial(algorithm="cardinalities")',
496+
replacement_rst_doc=':meth:`frobenius_polynomial(algorithm="cardinalities") <frobenius_polynomial>`')
497+
frobenius_polynomial_matrix = deprecated_function_alias(
498+
40528, _frobenius_polynomial_matrix,
499+
replacement='frobenius_polynomial(algorithm="matrix")',
500+
replacement_rst_doc=':meth:`frobenius_polynomial(algorithm="matrix") <frobenius_polynomial>`')
501+
frobenius_polynomial_pari = deprecated_function_alias(
502+
40528, _frobenius_polynomial_pari,
503+
replacement='frobenius_polynomial(algorithm="pari")',
504+
replacement_rst_doc=':meth:`frobenius_polynomial(algorithm="pari") <frobenius_polynomial>`')
505+
504506
@cached_method
505-
def frobenius_polynomial(self):
507+
def frobenius_polynomial(self, algorithm=None, **kwargs):
506508
r"""
507509
Compute the charpoly of frobenius, as an element of `\ZZ[x]`.
508510
511+
INPUT:
512+
513+
- ``algorithm`` -- the algorithm to use, one of
514+
515+
- ``None`` (default) -- automatically select an algorithm.
516+
517+
- ``'pari'`` -- use the PARI function ``hyperellcharpoly``.
518+
519+
- ``'cardinalities'`` -- compute the number of points on the curve over `g`
520+
extensions of the base field where `g` is the genus of the curve.
521+
522+
.. WARNING::
523+
524+
This is highly inefficient when the base field or the genus of the
525+
curve are large.
526+
527+
- ``'matrix'`` -- compute the charpoly of the frobenius matrix.
528+
529+
This is currently only supported when the base field is prime
530+
and large enough using the ``hypellfrob`` library.
531+
532+
- ``**kwargs`` -- additional keyword arguments passed to the
533+
internal method. Undocumented feature, may be removed in the future.
534+
509535
EXAMPLES::
510536
511537
sage: R.<t> = PolynomialRing(GF(37))
@@ -578,6 +604,15 @@ def frobenius_polynomial(self):
578604
sage: C.frobenius_polynomial()
579605
x^8 + 2*x^7 + 6*x^6 + 9*x^5 + 18*x^4 + 27*x^3 + 54*x^2 + 54*x + 81
580606
"""
607+
if algorithm == "cardinalities":
608+
return self._frobenius_polynomial_cardinalities(**kwargs)
609+
elif algorithm == "matrix":
610+
return self._frobenius_polynomial_matrix(**kwargs)
611+
elif algorithm == "pari":
612+
return self._frobenius_polynomial_pari(**kwargs)
613+
elif algorithm is not None:
614+
raise ValueError(f"unknown algorithm {algorithm}")
615+
581616
K = self.base_ring()
582617
e = K.degree()
583618
q = K.cardinality()
@@ -588,11 +623,11 @@ def frobenius_polynomial(self):
588623
if (e == 1 and
589624
q >= (2*g+1)*(2*self._frobenius_coefficient_bound_charpoly()-1) and
590625
h == 0 and f.degree() % 2):
591-
return self.frobenius_polynomial_matrix()
626+
return self.frobenius_polynomial(algorithm='matrix')
592627
elif q % 2 == 1:
593-
return self.frobenius_polynomial_pari()
628+
return self.frobenius_polynomial(algorithm='pari')
594629
else:
595-
return self.frobenius_polynomial_cardinalities()
630+
return self.frobenius_polynomial(algorithm='cardinalities')
596631

597632
def _points_fast_sqrt(self):
598633
"""
@@ -1031,7 +1066,7 @@ def count_points_exhaustive(self, n=1, naive=False):
10311066
a.append(self.cardinality_exhaustive(extension_degree=i))
10321067

10331068
# let's not be too naive and compute the frobenius polynomial
1034-
f = self.frobenius_polynomial_cardinalities(a=a)
1069+
f = self._frobenius_polynomial_cardinalities(a=a)
10351070
return self.count_points_frobenius_polynomial(n=n, f=f)
10361071

10371072
def count_points_hypellfrob(self, n=1, N=None, algorithm=None):
@@ -1116,7 +1151,7 @@ def count_points_hypellfrob(self, n=1, N=None, algorithm=None):
11161151
M = self.frobenius_matrix(N=N, algorithm='hypellfrob')
11171152
return self.count_points_matrix_traces(n=n,M=M,N=N)
11181153
elif algorithm == 'charpoly':
1119-
f = self.frobenius_polynomial_matrix(algorithm='hypellfrob')
1154+
f = self._frobenius_polynomial_matrix(algorithm='hypellfrob')
11201155
return self.count_points_frobenius_polynomial(n=n,f=f)
11211156
else:
11221157
raise ValueError("Unknown algorithm")

0 commit comments

Comments
 (0)