From f67d72da4754832c7ed0b85cf8c08be42725a6bd Mon Sep 17 00:00:00 2001 From: user202729 <25191436+user202729@users.noreply.github.com> Date: Wed, 1 Oct 2025 21:13:58 +0700 Subject: [PATCH 1/2] Fix finite field GF(p).extension(1, names=tuple) --- .../rings/finite_rings/finite_field_base.pyx | 15 +++++++++ .../finite_rings/finite_field_constructor.py | 33 +++++++++++++++++-- 2 files changed, 46 insertions(+), 2 deletions(-) diff --git a/src/sage/rings/finite_rings/finite_field_base.pyx b/src/sage/rings/finite_rings/finite_field_base.pyx index 3eed6a7e4b8..09543a1846f 100644 --- a/src/sage/rings/finite_rings/finite_field_base.pyx +++ b/src/sage/rings/finite_rings/finite_field_base.pyx @@ -1421,6 +1421,21 @@ cdef class FiniteField(Field): sage: L. = K.extension(b) sage: L(u).minpoly() == u.minpoly() True + + Check the test above when `a=b=1`, see :issue:`40926`. + While in general it doesn't make much sense to talk about the generator + of a prime finite field (:meth:`gen` returns 1), generic code may find + it convenient to always specify the variable name when it is not known + in advance whether the exponent is 1. + + The reason why one may want to specify ``name`` is :issue:`38376`. + + :: + + sage: K. = GF((random_prime(10^100), 1)) + sage: L. = K.extension(1) + sage: L(u).minpoly() == u.minpoly() + True """ from sage.rings.finite_rings.finite_field_constructor import GF from sage.rings.polynomial.polynomial_element import Polynomial diff --git a/src/sage/rings/finite_rings/finite_field_constructor.py b/src/sage/rings/finite_rings/finite_field_constructor.py index 2a9f1952a47..015144db4ed 100644 --- a/src/sage/rings/finite_rings/finite_field_constructor.py +++ b/src/sage/rings/finite_rings/finite_field_constructor.py @@ -597,7 +597,7 @@ def create_key_and_extra_args(self, order, name=None, modulus=None, names=None, sage: GF((5, 1), 3) Traceback (most recent call last): ... - TypeError: variable name 3 must be a string, not + TypeError: 'sage.rings.integer.Integer' object is not iterable sage: GF((5, 2), 3) Traceback (most recent call last): ... @@ -610,6 +610,35 @@ def create_key_and_extra_args(self, order, name=None, modulus=None, names=None, Traceback (most recent call last): ... ValueError: the order of a finite field must be a prime power + + We expect ``name`` to be a string (if it is a single name) and ``names`` to be + a tuple of strings, but for backwards compatibility this is not enforced. + This behavior might change in the future. :: + + sage: GF(7, name='aa') + Finite Field of size 7 + sage: GF(7^2, name='aa') + Finite Field in aa of size 7^2 + sage: GF(7, name=('aa',)) + Finite Field of size 7 + sage: GF(7^2, name=('aa',)) + Finite Field in aa of size 7^2 + sage: GF(7, name=['aa']) + Finite Field of size 7 + sage: GF(7^2, name=['aa']) + Finite Field in aa of size 7^2 + sage: GF(7, names='aa') + Finite Field of size 7 + sage: GF(7^2, names='aa') + Finite Field in aa of size 7^2 + sage: GF(7, names=('aa',)) + Finite Field of size 7 + sage: GF(7^2, names=('aa',)) + Finite Field in aa of size 7^2 + sage: GF(7, names=['aa']) + Finite Field of size 7 + sage: GF(7^2, names=['aa']) + Finite Field in aa of size 7^2 """ for key, val in kwds.items(): if key not in ['structure', 'implementation', 'prec', 'embedding', 'latex_names']: @@ -646,7 +675,7 @@ def create_key_and_extra_args(self, order, name=None, modulus=None, names=None, if impl is None: impl = 'modn' if name is not None: - certify_names((name,)) + certify_names((name,) if isinstance(name, str) else name) name = ('x',) # Ignore name # Every polynomial of degree 1 is irreducible check_irreducible = False From 7b59ba9373e42b0c820b2dd9f4a474f6e469ac71 Mon Sep 17 00:00:00 2001 From: user202729 <25191436+user202729@users.noreply.github.com> Date: Wed, 1 Oct 2025 21:47:53 +0700 Subject: [PATCH 2/2] Deprecate name=('a',) for FiniteField --- src/sage/modules/ore_module.py | 5 +++++ .../rings/finite_rings/conway_polynomials.py | 2 +- .../rings/finite_rings/finite_field_base.pyx | 21 ++++++++++++------- .../finite_rings/finite_field_constructor.py | 4 ++++ 4 files changed, 23 insertions(+), 9 deletions(-) diff --git a/src/sage/modules/ore_module.py b/src/sage/modules/ore_module.py index 6115537582a..c49b93e763b 100644 --- a/src/sage/modules/ore_module.py +++ b/src/sage/modules/ore_module.py @@ -269,6 +269,11 @@ def normalize_names(names, rank): r""" Return a normalized form of ``names``. + .. WARNING:: + + This has different signature and slightly different functionality + from :func:`sage.structure.category_object.normalize_names`! + INPUT: - ``names`` -- a string, a list of strings or ``None`` diff --git a/src/sage/rings/finite_rings/conway_polynomials.py b/src/sage/rings/finite_rings/conway_polynomials.py index 70a851990ad..4f6f8f6838a 100644 --- a/src/sage/rings/finite_rings/conway_polynomials.py +++ b/src/sage/rings/finite_rings/conway_polynomials.py @@ -234,7 +234,7 @@ def polynomial(self, n): return f # Work in an arbitrary field K of order p**n. - K = FiniteField(p**n, names='a') + K = FiniteField(p**n, name='a') # TODO: something like the following # gcds = [n.gcd(d) for d in self.nodes.keys()] diff --git a/src/sage/rings/finite_rings/finite_field_base.pyx b/src/sage/rings/finite_rings/finite_field_base.pyx index 09543a1846f..0db9b898543 100644 --- a/src/sage/rings/finite_rings/finite_field_base.pyx +++ b/src/sage/rings/finite_rings/finite_field_base.pyx @@ -1440,22 +1440,27 @@ cdef class FiniteField(Field): from sage.rings.finite_rings.finite_field_constructor import GF from sage.rings.polynomial.polynomial_element import Polynomial from sage.rings.integer import Integer - if name is None and names is not None: - name = names + if name is not None and names is None: + if isinstance(name, str): + names = (name,) + else: + from sage.misc.superseded import deprecation + deprecation(40948, "name should be a str, if you want to pass a tuple use names instead") + names = name if latex_name is None and latex_names is not None: latex_name = latex_names if self.degree() == 1: if isinstance(modulus, (int, Integer)): - E = GF((self.characteristic(), modulus), name=name, **kwds) + E = GF((self.characteristic(), modulus), names=names, **kwds) elif isinstance(modulus, (list, tuple)): - E = GF((self.characteristic(), len(modulus) - 1), name=name, modulus=modulus, **kwds) + E = GF((self.characteristic(), len(modulus) - 1), names=names, modulus=modulus, **kwds) elif isinstance(modulus, Polynomial): if modulus.change_ring(self).is_irreducible(): - E = GF((self.characteristic(), modulus.degree()), name=name, modulus=modulus, **kwds) + E = GF((self.characteristic(), modulus.degree()), names=names, modulus=modulus, **kwds) else: - E = Field.extension(self, modulus, name=name, embedding=embedding, **kwds) + E = Field.extension(self, modulus, names=names, embedding=embedding, **kwds) elif isinstance(modulus, (int, Integer)): - E = GF((self.characteristic(), self.degree() * modulus), name=name, **kwds) + E = GF((self.characteristic(), self.degree() * modulus), names=names, **kwds) if E is self: pass # coercion map (identity map) is automatically found elif hasattr(E, '_prefix') and hasattr(self, '_prefix'): @@ -1470,7 +1475,7 @@ cdef class FiniteField(Field): except AssertionError: # coercion already exists pass else: - E = Field.extension(self, modulus, name=name, embedding=embedding, latex_name=latex_name, **kwds) + E = Field.extension(self, modulus, names=names, embedding=embedding, latex_name=latex_name, **kwds) if map: return (E, E.coerce_map_from(self)) else: diff --git a/src/sage/rings/finite_rings/finite_field_constructor.py b/src/sage/rings/finite_rings/finite_field_constructor.py index 015144db4ed..aea78b329bc 100644 --- a/src/sage/rings/finite_rings/finite_field_constructor.py +++ b/src/sage/rings/finite_rings/finite_field_constructor.py @@ -671,6 +671,10 @@ def create_key_and_extra_args(self, order, name=None, modulus=None, names=None, # at this point, order = p**n # note that we haven't tested p for primality + if name is not None and not isinstance(name, str): + from sage.misc.superseded import deprecation + deprecation(40948, "name should be a str, if you want to pass a tuple use names instead") + if n == 1: if impl is None: impl = 'modn'