Skip to content

Commit

Permalink
Trac #17569: Allow creating finite fields without a variable name
Browse files Browse the repository at this point in the history
It should be possible to use `FiniteField(p^n)` (or `FiniteField(p, n)`,
see #17568) without a `name` argument to create the subfield of
`FiniteField(p).algebraic_closure()` of cardinality `p^n`.  This would
mean
{{{
GF(p, n) = GF(p^n) = GF(p).algebraic_closure().subfield(n)[0]
}}}

Discussion on sage-devel: https://groups.google.com/forum/#!topic/sage-
devel/LlstHp950uo

URL: http://trac.sagemath.org/17569
Reported by: pbruin
Ticket author(s): David Roe
Reviewer(s): Volker Braun
  • Loading branch information
Release Manager authored and vbraun committed Feb 24, 2016
2 parents 35fdd31 + 2a92ef3 commit 9d4c988
Show file tree
Hide file tree
Showing 11 changed files with 95 additions and 77 deletions.
6 changes: 3 additions & 3 deletions src/sage/categories/pushout.py
Original file line number Diff line number Diff line change
Expand Up @@ -2851,14 +2851,14 @@ def merge(self,other):
The following demonstrate coercions for finite fields using Conway or
pseudo-Conway polynomials::
sage: k = GF(3^2, conway=True, prefix='z'); a = k.gen()
sage: l = GF(3^3, conway=True, prefix='z'); b = l.gen()
sage: k = GF(3^2, prefix='z'); a = k.gen()
sage: l = GF(3^3, prefix='z'); b = l.gen()
sage: a + b # indirect doctest
z6^5 + 2*z6^4 + 2*z6^3 + z6^2 + 2*z6 + 1
Note that embeddings are compatible in lattices of such finite fields::
sage: m = GF(3^5, conway=True, prefix='z'); c = m.gen()
sage: m = GF(3^5, prefix='z'); c = m.gen()
sage: (a+b)+c == a+(b+c) # indirect doctest
True
sage: from sage.categories.pushout import pushout
Expand Down
4 changes: 2 additions & 2 deletions src/sage/combinat/designs/block_design.py
Original file line number Diff line number Diff line change
Expand Up @@ -551,8 +551,8 @@ def HughesPlane(q2, check=True):
if q2%2 == 0:
raise EmptySetError("No Hughes plane of even order exists.")
q = q2.sqrt()
K = FiniteField(q2, prefix='x', conway=True)
F = FiniteField(q, prefix='y', conway=True)
K = FiniteField(q2, prefix='x')
F = FiniteField(q, prefix='y')
A = q3_minus_one_matrix(F)
A = A.change_ring(K)
m = K.list()
Expand Down
2 changes: 1 addition & 1 deletion src/sage/combinat/designs/database.py
Original file line number Diff line number Diff line change
Expand Up @@ -1477,7 +1477,7 @@ def OA_17_560():
m = 16
n = p**alpha

G = GF(p**alpha,prefix='x',conway=True)
G = GF(p**alpha,prefix='x')
G_set = sorted(G) # sorted by lexicographic order, G[1] = 1
G_to_int = {v:i for i,v in enumerate(G_set)}
# Builds an OA(n+1,n) whose last n-1 colums are
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -686,7 +686,7 @@ def thwart_lemma_3_5(k,n,m,a,b,c,d=0,complement=False,explain_construction=False
assert a<=n and b<=n and c<=n and d<=n, "a,b,c,d (={},{},{},{}) must be <=n(={})".format(a,b,c,d,n)
assert a+b+c<=n+1, "{}={}+{}+{}=a+b+c>n+1={}+1 violates the assumptions".format(a+b+c,a,b,c,n)
assert k+3+bool(d) <= n+1, "There exists no OA({},{}).".format(k+3+bool(d),n)
G = GF(n,prefix='x',conway=True)
G = GF(n,prefix='x')
G_set = sorted(G) # sorted by lexicographic order, G[1] = 1
assert G_set[0] == G.zero() and G_set[1] == G.one(), "problem with the ordering of {}".format(G)
G_to_int = {v:i for i,v in enumerate(G_set)}
Expand Down
2 changes: 1 addition & 1 deletion src/sage/combinat/matrices/hadamard_matrix.py
Original file line number Diff line number Diff line change
Expand Up @@ -783,7 +783,7 @@ def _helper_payley_matrix(n, zero_position=True):
[ 1 -1 1 -1 -1 -1 1 1 -1 1 0]
"""
from sage.rings.finite_rings.finite_field_constructor import FiniteField as GF
K = GF(n,conway=True,prefix='x')
K = GF(n,prefix='x')

# Order the elements of K in K_list
# so that K_list[i] = -K_list[n-i-1]
Expand Down
2 changes: 1 addition & 1 deletion src/sage/graphs/generators/families.py
Original file line number Diff line number Diff line change
Expand Up @@ -2577,7 +2577,7 @@ def MathonPseudocyclicStronglyRegularGraph(t, G=None, L=None):
from sage.matrix.constructor import circulant
L = circulant(range(2*t+1)+map(lambda i: -2*t+i, range(2*t)))
q = 4*t -1
K = GF(q,conway=True,prefix='x')
K = GF(q,prefix='x')
K_pairs = set(frozenset([x,-x]) for x in K)
K_pairs.discard(frozenset([0]))
a = [None]*(q-1) # order the non-0 elements of K as required
Expand Down
2 changes: 2 additions & 0 deletions src/sage/rings/finite_rings/conway_polynomials.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from sage.misc.fast_methods import WithEqualityById
from sage.structure.sage_object import SageObject
from sage.rings.finite_rings.finite_field_constructor import FiniteField
from sage.rings.integer import Integer
import sage.databases.conway

def conway_polynomial(p, n):
Expand Down Expand Up @@ -217,6 +218,7 @@ def polynomial(self, n):
return self.nodes[n]

p = self.p
n = Integer(n)

if n == 1:
f = self.ring.gen() - FiniteField(p).multiplicative_generator()
Expand Down
32 changes: 16 additions & 16 deletions src/sage/rings/finite_rings/finite_field_base.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -1042,8 +1042,8 @@ cdef class FiniteField(Field):
...
TypeError: no canonical coercion from Rational Field to Finite Field in a of size 2^2
sage: FiniteField(16, 'a', conway=True, prefix='z')._coerce_(FiniteField(4, 'a', conway=True, prefix='z').0)
a^2 + a
sage: FiniteField(16)._coerce_(FiniteField(4).0)
z4^2 + z4
sage: FiniteField(8, 'a')._coerce_(FiniteField(4, 'a').0)
Traceback (most recent call last):
Expand Down Expand Up @@ -1082,7 +1082,7 @@ cdef class FiniteField(Field):
EXAMPLES::
sage: v = GF(3^3, conway=True, prefix='z').construction(); v
sage: v = GF(3^3).construction(); v
(AlgebraicExtensionFunctor, Finite Field of size 3)
sage: v[0].polys[0]
3
Expand All @@ -1093,10 +1093,10 @@ cdef class FiniteField(Field):
if self.degree() == 1:
# this is not of type FiniteField_prime_modn
from sage.rings.integer import Integer
return AlgebraicExtensionFunctor([self.polynomial()], [None], [None], conway=1), self.base_ring()
return AlgebraicExtensionFunctor([self.polynomial()], [None], [None]), self.base_ring()
elif hasattr(self, '_prefix'):
return (AlgebraicExtensionFunctor([self.degree()], [self.variable_name()], [None],
conway=True, prefix=self._prefix),
prefix=self._prefix),
self.base_ring())
else:
return (AlgebraicExtensionFunctor([self.polynomial()], [self.variable_name()], [None]),
Expand Down Expand Up @@ -1135,9 +1135,9 @@ cdef class FiniteField(Field):
sage: R.<x> = k[]
sage: k.extension(x^1000 + x^5 + x^4 + x^3 + 1, 'a')
Finite Field in a of size 2^1000
sage: k = GF(3^4, conway=True, prefix='z')
sage: k = GF(3^4)
sage: R.<x> = k[]
sage: k.extension(3, conway=True, prefix='z')
sage: k.extension(3)
Finite Field in z12 of size 3^12
An example using the ``map`` argument::
Expand Down Expand Up @@ -1231,28 +1231,28 @@ cdef class FiniteField(Field):
EXAMPLES::
sage: k.<a> = GF(2^21, conway=True, prefix='z')
sage: k = GF(2^21)
sage: k.subfields()
[(Finite Field of size 2,
Ring morphism:
From: Finite Field of size 2
To: Finite Field in a of size 2^21
To: Finite Field in z21 of size 2^21
Defn: 1 |--> 1),
(Finite Field in z3 of size 2^3,
Ring morphism:
From: Finite Field in z3 of size 2^3
To: Finite Field in a of size 2^21
Defn: z3 |--> a^20 + a^19 + a^17 + a^15 + a^11 + a^9 + a^8 + a^6 + a^2),
To: Finite Field in z21 of size 2^21
Defn: z3 |--> z21^20 + z21^19 + z21^17 + z21^15 + z21^11 + z21^9 + z21^8 + z21^6 + z21^2),
(Finite Field in z7 of size 2^7,
Ring morphism:
From: Finite Field in z7 of size 2^7
To: Finite Field in a of size 2^21
Defn: z7 |--> a^20 + a^19 + a^17 + a^15 + a^14 + a^6 + a^4 + a^3 + a),
To: Finite Field in z21 of size 2^21
Defn: z7 |--> z21^20 + z21^19 + z21^17 + z21^15 + z21^14 + z21^6 + z21^4 + z21^3 + z21),
(Finite Field in z21 of size 2^21,
Ring morphism:
From: Finite Field in z21 of size 2^21
To: Finite Field in a of size 2^21
Defn: z21 |--> a)]
To: Finite Field in z21 of size 2^21
Defn: z21 |--> z21)]
"""
from sage.rings.integer import Integer
from finite_field_constructor import GF
Expand All @@ -1263,7 +1263,7 @@ cdef class FiniteField(Field):
if not degree.divides(n):
return []
elif hasattr(self, '_prefix'):
K = GF(p**degree, name=name, conway=True, prefix=self._prefix)
K = GF(p**degree, name=name, prefix=self._prefix)
return [(K, self.coerce_map_from(K))]
elif degree == 1:
K = GF(p)
Expand Down
112 changes: 64 additions & 48 deletions src/sage/rings/finite_rings/finite_field_constructor.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,21 @@
contains a database of Conway polynomials which also can be queried
independently of finite field construction.
A pseudo-Conway polynomial satisfies all of the conditions required
of a Conway polynomial except the condition that it is lexicographically
first. They are therefore not unique. If no variable name is
specified for an extension field, Sage will fit the finite field
into a compatible lattice of field extensions defined by pseudo-Conway
polynomials. This lattice is stored in an
:class:`~sage.rings.algebraic_closure_finite_field.AlgebraicClosureFiniteField`
object; different algebraic closure objects can be created by using
a different ``prefix`` keyword to the finite field constructor.
Note that the computation of pseudo-Conway polynomials is expensive
when the degree is large and highly composite. If a variable
name is specified then a random polynomial is used instead, which
will be much faster to find.
While Sage supports basic arithmetic in finite fields some more
advanced features for computing with finite fields are still not
implemented. For instance, Sage does not calculate embeddings of
Expand Down Expand Up @@ -181,15 +196,22 @@ class FiniteFieldFactory(UniqueFactory):
- ``order`` -- a prime power
- ``name`` -- string; must be specified unless ``order`` is prime.
- ``name`` -- string, optional. Note that there can be a
substantial speed penalty (in creating extension fields) when
omitting the variable name, since doing so triggers the
computation of pseudo-Conway polynomials in order to define a
coherent lattice of extensions of the prime field. The speed
penalty grows with the size of extension degree and with
the number of factors of the extension degree.
- ``modulus`` -- (optional) either a defining polynomial for the
field, or a string specifying an algorithm to use to generate
such a polynomial. If ``modulus`` is a string, it is passed to
:meth:`~sage.rings.polynomial.irreducible_element()` as the
parameter ``algorithm``; see there for the permissible values of
this parameter. In particular, you can specify
``modulus="primitive"`` to get a primitive polynomial.
``modulus="primitive"`` to get a primitive polynomial. You
may not specify a modulus if you do not specify a variable name.
- ``impl`` -- (optional) a string specifying the implementation of
the finite field. Possible values are:
Expand Down Expand Up @@ -374,15 +396,15 @@ class FiniteFieldFactory(UniqueFactory):
The following demonstrate coercions for finite fields using Conway
polynomials::
sage: k = GF(5^2, conway=True, prefix='z'); a = k.gen()
sage: l = GF(5^5, conway=True, prefix='z'); b = l.gen()
sage: k = GF(5^2); a = k.gen()
sage: l = GF(5^5); b = l.gen()
sage: a + b
3*z10^5 + z10^4 + z10^2 + 3*z10 + 1
Note that embeddings are compatible in lattices of such finite
fields::
sage: m = GF(5^3, conway=True, prefix='z'); c = m.gen()
sage: m = GF(5^3); c = m.gen()
sage: (a+b)+c == a+(b+c)
True
sage: (a*b)*c == a*(b*c)
Expand All @@ -396,11 +418,33 @@ class FiniteFieldFactory(UniqueFactory):
Another check that embeddings are defined properly::
sage: k = GF(3**10, conway=True, prefix='z')
sage: l = GF(3**20, conway=True, prefix='z')
sage: k = GF(3**10)
sage: l = GF(3**20)
sage: l(k.gen()**10) == l(k.gen())**10
True
Using pseudo-Conway polynomials is slow for highly
composite extension degrees::
sage: k = GF(3^120) # long time -- about 3 seconds
sage: GF(3^40).gen().minimal_polynomial()(k.gen()^((3^120-1)/(3^40-1))) # long time because of previous line
0
Before :trac:`17569`, the boolean keyword argument ``conway``
was required when creating finite fields without a variable
name. This keyword argument is now deprecated. You
can still pass in ``prefix`` as an argument, which has the
effect of changing the variable name of the algebraic closure::
sage: K = GF(3^10, conway=True, prefix='w'); L = GF(3^10); K is L
doctest:...: DeprecationWarning: the 'conway' argument is deprecated, pseudo-conway polynomials are now used by default if no variable name is given
See http://trac.sagemath.org/17569 for details.
False
sage: K.variable_name(), L.variable_name()
('w10', 'z10')
sage: list(K.polynomial()) == list(L.polynomial())
True
Check that :trac:`16934` has been fixed::
sage: k1.<a> = GF(17^14, impl="pari_ffelt")
Expand Down Expand Up @@ -444,51 +488,23 @@ def create_key_and_extra_args(self, order, name=None, modulus=None, names=None,
name = normalize_names(1, name)

p, n = order.factor()[0]

# The following is a temporary solution that allows us
# to construct compatible systems of finite fields
# until algebraic closures of finite fields are
# implemented in Sage. It requires the user to
# specify two parameters:
#
# - `conway` -- boolean; if True, this field is
# constructed to fit in a compatible system using
# a Conway polynomial.
# - `prefix` -- a string used to generate names for
# automatically constructed finite fields
#
# See the docstring of FiniteFieldFactory for examples.
#
# Once algebraic closures of finite fields are
# implemented, this syntax should be superseded by
# something like the following:
#
# sage: Fpbar = GF(5).algebraic_closure('z')
# sage: F, e = Fpbar.subfield(3) # e is the embedding into Fpbar
# sage: F
# Finite field in z3 of size 5^3
#
# This temporary solution only uses actual Conway
# polynomials (no pseudo-Conway polynomials), since
# pseudo-Conway polynomials are not unique, and until
# we have algebraic closures of finite fields, there
# is no good place to store a specific choice of
# pseudo-Conway polynomials.
if name is None:
if not ('conway' in kwds and kwds['conway']):
raise ValueError("parameter 'conway' is required if no name given")
if 'prefix' not in kwds:
raise ValueError("parameter 'prefix' is required if no name given")
kwds['prefix'] = 'z'
name = kwds['prefix'] + str(n)

if 'conway' in kwds and kwds['conway']:
from conway_polynomials import conway_polynomial
if 'prefix' not in kwds:
raise ValueError("a prefix must be specified if conway=True")
if modulus is not None:
raise ValueError("no modulus may be specified if conway=True")
# The following raises a RuntimeError if no polynomial is found.
modulus = conway_polynomial(p, n)
raise ValueError("no modulus may be specified if variable name not given")
if 'conway' in kwds:
del kwds['conway']
from sage.misc.superseded import deprecation
deprecation(17569, "the 'conway' argument is deprecated, pseudo-conway polynomials are now used by default if no variable name is given")
# Fpbar will have a strong reference, since algebraic_closure caches its results,
# and the coefficients of modulus lie in GF(p)
Fpbar = GF(p).algebraic_closure(kwds.get('prefix','z'))
# This will give a Conway polynomial if p,n is small enough to be in the database
# and a pseudo-Conway polynomial if it's not.
modulus = Fpbar._get_polynomial(n)
check_irreducible = False

if impl is None:
if order < zech_log_bound:
Expand Down
4 changes: 2 additions & 2 deletions src/sage/rings/finite_rings/finite_field_givaro.py
Original file line number Diff line number Diff line change
Expand Up @@ -378,8 +378,8 @@ def _element_constructor_(self, e):
sage: k(48771/1225)
28
sage: F9 = FiniteField(9, impl='givaro', conway=True, prefix='a')
sage: F81 = FiniteField(81, impl='givaro', conway=True, prefix='a')
sage: F9 = FiniteField(9, impl='givaro', prefix='a')
sage: F81 = FiniteField(81, impl='givaro', prefix='a')
sage: F81(F9.gen())
2*a4^3 + 2*a4^2 + 1
"""
Expand Down
4 changes: 2 additions & 2 deletions src/sage/rings/polynomial/polynomial_ring.py
Original file line number Diff line number Diff line change
Expand Up @@ -377,8 +377,8 @@ def _element_constructor_(self, x=None, check=True, is_gen = False, construct=Fa
Check that the bug in :trac:`11239` is fixed::
sage: K.<a> = GF(5^2, conway=True, prefix='z')
sage: L.<b> = GF(5^4, conway=True, prefix='z')
sage: K.<a> = GF(5^2, prefix='z')
sage: L.<b> = GF(5^4, prefix='z')
sage: f = K['x'].gen() + a
sage: L['x'](f)
x + b^3 + b^2 + b + 3
Expand Down

0 comments on commit 9d4c988

Please sign in to comment.