Ticket #14958: trac_14958-pseudo_conway_simplified.patch

File trac_14958-pseudo_conway_simplified.patch, 36.8 KB (added by Peter Bruin, 9 years ago)

implement pseudo-Conway polynomials (replaces both previous patches)

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

    # HG changeset patch
    # User Peter Bruin <peter.bruin@math.uzh.ch>
    # Date 1374591311 -7200
    # Node ID 9768afffdf3666081d2278a6bd4b9767d8c0a766
    # Parent  8a888cf1c0221397eef1d7d0c23a2e1fff791724
    Trac 14958: implement pseudo-Conway polynomials
    
    diff --git a/doc/en/reference/finite_rings/index.rst b/doc/en/reference/finite_rings/index.rst
    a b  
    44.. toctree::
    55   :maxdepth: 2
    66
     7   sage/rings/finite_rings/conway_polynomials
    78   sage/rings/finite_rings/element_givaro
    89   sage/rings/finite_rings/element_ntl_gf2e
    910   sage/rings/finite_rings/element_pari_ffelt
  • sage/rings/finite_rings/all.py

    diff --git a/sage/rings/finite_rings/all.py b/sage/rings/finite_rings/all.py
    a b  
    1818#                  http://www.gnu.org/licenses/
    1919#*****************************************************************************
    2020
    21 from constructor import (FiniteField, is_FiniteField, is_PrimeFiniteField,
    22                           conway_polynomial, exists_conway_polynomial)
     21from constructor import FiniteField, is_FiniteField, is_PrimeFiniteField
     22from conway_polynomials import conway_polynomial, exists_conway_polynomial
    2323GF = FiniteField
    2424
    2525from element_base import FinitePolyExtElement as FiniteFieldElement # for backward compatibility; is this needed?
  • sage/rings/finite_rings/constructor.py

    diff --git a/sage/rings/finite_rings/constructor.py b/sage/rings/finite_rings/constructor.py
    a b  
    168168from finite_field_givaro import FiniteField_givaro
    169169
    170170import sage.interfaces.gap
    171 import sage.databases.conway
    172171
    173172from sage.structure.factory import UniqueFactory
    174173
     
    177176    Return the globally unique finite field of given order with
    178177    generator labeled by the given name and possibly with given
    179178    modulus.
    180    
     179
    181180    INPUT:
    182    
    183    
    184     -  ``order`` - int
    185    
    186     -  ``name`` - string; must be specified if not a prime
    187        field
    188    
    189     -  ``modulus`` - (optional) either a defining polynomial for the
    190        field, i.e., generator of the field will be a root of this
    191        polynomial; or a string:
    192181
    193           - 'conway': force the use of a Conway polynomial, will
    194             raise a RuntimeError if none is found in the database;
    195           - 'random': use a random irreducible polynomial;
    196           - 'default': a Conway polynomial is used if found. Otherwise
    197             a sparse polynomial is used for binary fields and a
    198             random polynomial is used for other characteristics.
     182    - ``order`` -- a prime power
    199183
    200        Other options might be available depending on the
    201        implementation.
    202    
    203     -  ``elem_cache`` - cache all elements to avoid
    204        creation time (default: order < 500)
    205    
    206     -  ``check_irreducible`` - verify that the polynomial
    207        modulus is irreducible
     184    - ``name`` -- string; must be specified unless ``order`` is prime.
    208185
    209     - ``proof`` -- bool (default: True); if True use provable
     186    - ``modulus`` -- (optional) either a defining polynomial for the
     187      field, or a string specifying an algorithm to use to generate
     188      such a polynomial.  If ``modulus`` is a string, it is passed to
     189      :meth:`~sage.rings.polynomial.irreducible_element()` as the
     190      parameter ``algorithm``; see there for the permissible values of
     191      this parameter.
     192
     193    - ``elem_cache`` -- cache all elements to avoid creation time
     194      (default: order < 500)
     195
     196    - ``check_irreducible`` -- verify that the polynomial modulus is
     197      irreducible
     198
     199    - ``proof`` -- bool (default: ``True``): if ``True``, use provable
    210200      primality test; otherwise only use pseudoprimality test.
    211    
    212     -  ``args`` - additional parameters passed to finite
    213        field implementations
    214    
    215     -  ``kwds`` - additional keyword parameters passed to
    216        finite field implementations
    217    
    218    
    219     ALIAS: You can also use GF instead of FiniteField - they are
    220     identical.
     201
     202    - ``args`` -- additional parameters passed to finite field
     203      implementations
     204
     205    - ``kwds`` -- additional keyword parameters passed to finite field
     206      implementations
     207
     208    ALIAS: You can also use ``GF`` instead of ``FiniteField`` -- they
     209    are identical.
    221210
    222211    EXAMPLES::
    223    
     212
    224213        sage: k.<a> = FiniteField(9); k
    225214        Finite Field in a of size 3^2
    226215        sage: parent(a)
    227216        Finite Field in a of size 3^2
    228217        sage: charpoly(a, 'y')
    229218        y^2 + 2*y + 2
    230    
     219
    231220    We illustrate the proof flag.  The following example would hang
    232     for a very long time if we didn't use proof=False.  (NOTE: Magma
    233     only supports proof=False for making finite fields, so falsely
    234     appears to be faster than Sage -- see Trac 10975.)::
     221    for a very long time if we didn't use ``proof=False``.
     222
     223    .. NOTE::
     224
     225        Magma only supports ``proof=False`` for making finite fields,
     226        so falsely appears to be faster than Sage -- see :trac:10975.
     227
     228    ::
    235229
    236230        sage: k = FiniteField(10^1000 + 453, proof=False)
    237231        sage: k = FiniteField((10^1000 + 453)^2, 'a', proof=False)      # long time -- about 5 seconds
     
    244238        x^5 + 4*x + 1
    245239        sage: type(f)
    246240         <type 'sage.rings.polynomial.polynomial_zmod_flint.Polynomial_zmod_flint'>
    247    
     241
    248242    The modulus must be irreducible::
    249    
    250         sage: K.<a> = GF(5**5, name='a', modulus=x^5 - x )
     243
     244        sage: K.<a> = GF(5**5, name='a', modulus=x^5 - x)
    251245        Traceback (most recent call last):
    252246        ...
    253247        ValueError: finite field modulus must be irreducible but it is not.
    254    
    255     You can't accidentally fool the constructor into thinking the modulus
    256     is irreducible when it isn't mod p, since it actually tests
    257     irreducibility modulo p.  Also, the modulus has to be of the right degree.
    258    
    259     ::
    260    
     248
     249    You can't accidentally fool the constructor into thinking the
     250    modulus is irreducible when it is not, since it actually tests
     251    irreducibility modulo `p`.  Also, the modulus has to be of the
     252    right degree::
     253
    261254        sage: F.<x> = QQ[]
    262255        sage: factor(x^5 + 2)
    263256        x^5 + 2
    264         sage: K.<a> = GF(5**5, name='a', modulus=x^5 + 2 )
     257        sage: K.<a> = GF(5**5, name='a', modulus=x^5 + 2)
    265258        Traceback (most recent call last):
    266259        ...
    267260        ValueError: finite field modulus must be irreducible but it is not.
     
    270263        ...
    271264        ValueError: The degree of the modulus does not correspond to the
    272265        cardinality of the field.
    273    
     266
    274267    If you wish to live dangerously, you can tell the constructor not
    275     to test irreducibility using check_irreducible=False, but this can
    276     easily lead to crashes and hangs - so do not do it unless you know
    277     that the modulus really is irreducible and has the correct degree!
    278    
     268    to test irreducibility using ``check_irreducible=False``, but this
     269    can easily lead to crashes and hangs -- so do not do it unless you
     270    know that the modulus really is irreducible and has the correct
     271    degree!
     272
    279273    ::
    280    
     274
    281275        sage: F.<x> = GF(5)[]
    282276        sage: K.<a> = GF(5**2, name='a', modulus=x^2 + 2, check_irreducible=False)
    283277
    284     ::
    285 
    286278        sage: L = GF(3**2, name='a', modulus=QQ[x](x - 1), check_irreducible=False)
    287279        sage: L.list()  # random
    288280        [0, a, 1, 2, 1, 2, 1, 2, 1]
    289281
    290282    The order of a finite field must be a prime power::
    291    
     283
    292284        sage: GF(1)
    293285        Traceback (most recent call last):
    294286        ...
     
    297289        Traceback (most recent call last):
    298290        ...
    299291        ValueError: the order of a finite field must be a prime power.
    300    
     292
    301293    Finite fields with explicit random modulus are not cached::
    302    
     294
    303295        sage: k.<a> = GF(5**10, modulus='random')
    304296        sage: n.<a> = GF(5**10, modulus='random')
    305297        sage: n is k
    306298        False
    307299        sage: GF(5**10, 'a') is GF(5**10, 'a')
    308300        True
    309    
     301
    310302    We check that various ways of creating the same finite field yield
    311     the same object, which is cached.
    312    
    313     ::
    314    
     303    the same object, which is cached::
     304
    315305        sage: K = GF(7, 'a')
    316306        sage: L = GF(7, 'b')
    317307        sage: K is L
     
    325315        sage: K is M
    326316        True
    327317   
    328     You may print finite field elements as integers. This
    329     currently only works if the order of field is `<2^{16}`,
    330     though.
    331    
    332     ::
    333    
     318    You may print finite field elements as integers. This currently
     319    only works if the order of field is `<2^{16}`, though::
     320
    334321        sage: k.<a> = GF(2^8, repr='int')
    335322        sage: a
    336323        2
     
    528515
    529516    return isinstance(x, FiniteField_prime_modn) or \
    530517           (isinstance(x, FiniteField_generic) and x.degree() == 1)
    531    
    532 ##################################################################
    533    
    534 def conway_polynomial(p, n):
    535     r"""
    536     Return the Conway polynomial of degree n over GF(p), which is
    537     loaded from a table.
    538    
    539     If the requested polynomial is not known, this function raises a
    540     RuntimeError exception.
    541    
    542     INPUT:
    543    
    544    
    545     -  ``p`` - int
    546    
    547     -  ``n`` - int
    548    
    549    
    550     OUTPUT:
    551    
    552    
    553     -  ``Polynomial`` - a polynomial over the prime finite
    554        field GF(p).
    555    
    556    
    557     .. note::
    558 
    559        The first time this function is called a table is read from
    560        disk, which takes a fraction of a second. Subsequent calls do
    561        not require reloading the table.
    562    
    563     See also the ``ConwayPolynomials()`` object, which is a
    564     table of Conway polynomials. For example, if
    565     ``c=ConwayPolynomials()``, then
    566     ``c.primes()`` is a list of all primes for which the
    567     polynomials are known, and for a given prime `p`,
    568     ``c.degree(p)`` is a list of all degrees for which the
    569     Conway polynomials are known.
    570    
    571     EXAMPLES::
    572    
    573         sage: conway_polynomial(2,5)
    574         x^5 + x^2 + 1
    575         sage: conway_polynomial(101,5)
    576         x^5 + 2*x + 99
    577         sage: conway_polynomial(97,101)
    578         Traceback (most recent call last):
    579         ...
    580         RuntimeError: requested conway polynomial not in database.
    581     """
    582     (p,n)=(int(p),int(n))
    583     R = FiniteField(p)['x']
    584     try:
    585         return R(sage.databases.conway.ConwayPolynomials()[p][n])
    586     except KeyError:
    587         raise RuntimeError("requested conway polynomial not in database.")
    588 
    589 def exists_conway_polynomial(p, n):
    590     r"""
    591     Return True if the Conway polynomial over `F_p` of degree
    592     `n` is in the database and False otherwise.
    593    
    594     If the Conway polynomial is in the database, to obtain it use the
    595     command ``conway_polynomial(p,n)``.
    596    
    597     EXAMPLES::
    598    
    599         sage: exists_conway_polynomial(2,3)
    600         True
    601         sage: exists_conway_polynomial(2,-1)
    602         False
    603         sage: exists_conway_polynomial(97,200)
    604         False
    605         sage: exists_conway_polynomial(6,6)
    606         False
    607     """
    608     return sage.databases.conway.ConwayPolynomials().has_polynomial(p,n)
    609 
    610518
    611519zech_log_bound = 2**16
  • new file sage/rings/finite_rings/conway_polynomials.py

    diff --git a/sage/rings/finite_rings/conway_polynomials.py b/sage/rings/finite_rings/conway_polynomials.py
    new file mode 100644
    - +  
     1"""
     2Routines for Conway and pseudo-Conway polynomials.
     3
     4AUTHORS:
     5
     6- David Roe
     7
     8- Jean-Pierre Flori
     9
     10- Peter Bruin
     11"""
     12from sage.structure.sage_object import SageObject
     13from sage.rings.finite_rings.constructor import FiniteField
     14import sage.databases.conway
     15
     16def conway_polynomial(p, n):
     17    """
     18    Return the Conway polynomial of degree `n` over ``GF(p)``.
     19
     20    If the requested polynomial is not known, this function raises a
     21    ``RuntimeError`` exception.
     22
     23    INPUT:
     24
     25    - ``p`` -- prime number
     26
     27    - ``n`` -- positive integer
     28
     29    OUTPUT:
     30
     31    - the Conway polynomial of degree `n` over the finite field
     32      ``GF(p)``, loaded from a table.
     33
     34    .. NOTE::
     35
     36       The first time this function is called a table is read from
     37       disk, which takes a fraction of a second. Subsequent calls do
     38       not require reloading the table.
     39
     40    See also the ``ConwayPolynomials()`` object, which is the table of
     41    Conway polynomials used by this function.
     42
     43    EXAMPLES::
     44
     45        sage: conway_polynomial(2,5)
     46        x^5 + x^2 + 1
     47        sage: conway_polynomial(101,5)
     48        x^5 + 2*x + 99
     49        sage: conway_polynomial(97,101)
     50        Traceback (most recent call last):
     51        ...
     52        RuntimeError: requested Conway polynomial not in database.
     53    """
     54    (p, n) = (int(p), int(n))
     55    R = FiniteField(p)['x']
     56    try:
     57        return R(sage.databases.conway.ConwayPolynomials()[p][n])
     58    except KeyError:
     59        raise RuntimeError("requested Conway polynomial not in database.")
     60
     61def exists_conway_polynomial(p, n):
     62    """
     63    Check whether the Conway polynomial of degree `n` over ``GF(p)``
     64    is known.
     65
     66    INPUT:
     67
     68    - ``p`` -- prime number
     69
     70    - ``n`` -- positive integer
     71
     72    OUTPUT:
     73
     74    - boolean: ``True`` if the Conway polynomial of degree `n` over
     75      ``GF(p)`` is in the database, ``False`` otherwise.
     76
     77    If the Conway polynomial is in the database, it can be obtained
     78    using the command ``conway_polynomial(p,n)``.
     79
     80    EXAMPLES::
     81
     82        sage: exists_conway_polynomial(2,3)
     83        True
     84        sage: exists_conway_polynomial(2,-1)
     85        False
     86        sage: exists_conway_polynomial(97,200)
     87        False
     88        sage: exists_conway_polynomial(6,6)
     89        False
     90    """
     91    return sage.databases.conway.ConwayPolynomials().has_polynomial(p,n)
     92
     93class PseudoConwayLattice(SageObject):
     94    r"""
     95    A pseudo-Conway lattice over a given finite prime field.
     96
     97    The Conway polynomial `f_n` of degree `n` over `\Bold{F}_p` is
     98    defined by the following four conditions:
     99
     100    - `f_n` is irreducible.
     101
     102    - In the quotient field `\Bold{F}_p[x]/(f_n)`, the element
     103      `x\bmod f_n` generates the multiplicative group.
     104
     105    - The minimal polynomial of `(x\bmod f_n)^{\frac{p^n-1}{p^m-1}}`
     106      equals the Conway polynomial `f_m`, for every divisor `m` of
     107      `n`.
     108
     109    - `f_n` is lexicographically least among all such polynomials,
     110      under a certain ordering.
     111
     112    The final condition is needed only in order to make the Conway
     113    polynomial unique.  We define a pseudo-Conway lattice to be any
     114    family of polynomials, indexed by the positive integers,
     115    satisfying the first three conditions.
     116
     117    INPUT:
     118
     119    - ``p`` -- prime number
     120
     121    - ``use_database`` -- boolean.  If ``True``, use actual Conway
     122      polynomials whenever they are available in the database.  If
     123      ``False``, always compute pseudo-Conway polynomials.
     124
     125    EXAMPLES::
     126
     127        sage: from sage.rings.finite_rings.conway_polynomials import PseudoConwayLattice
     128        sage: PCL = PseudoConwayLattice(2, use_database=False)
     129        sage: PCL.polynomial(3)
     130        x^3 + x + 1
     131    """
     132
     133    def __init__(self, p, use_database=True):
     134        """
     135        TESTS::
     136
     137            sage: from sage.rings.finite_rings.conway_polynomials import PseudoConwayLattice
     138            sage: PCL = PseudoConwayLattice(3)
     139            sage: PCL.polynomial(3)
     140            x^3 + 2*x + 1
     141
     142            sage: PCL = PseudoConwayLattice(5, use_database=False)
     143            sage: PCL.polynomial(12)
     144            x^12 + 2*x^11 + x^10 + 4*x^9 + 4*x^8 + 4*x^7 + x^6 + 4*x^5 + x^4 + 3*x + 2
     145            sage: PCL.polynomial(6)
     146            x^6 + x^5 + 4*x^4 + 3*x^3 + 3*x^2 + 2*x + 2
     147            sage: PCL.polynomial(11)
     148            x^11 + x^6 + 3*x^3 + 4*x + 3
     149        """
     150        self.p = p
     151        from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
     152        self.ring = PolynomialRing(FiniteField(p), 'x')
     153        if use_database:
     154            C = sage.databases.conway.ConwayPolynomials()
     155            self.nodes = {n: self.ring(C.polynomial(p, n))
     156                          for n in C.degrees(p)}
     157        else:
     158            self.nodes = {}
     159
     160    def polynomial(self, n):
     161        r"""
     162        Return the pseudo-Conway polynomial of degree `n` in this
     163        lattice.
     164
     165        INPUT:
     166
     167        - ``n`` -- positive integer
     168
     169        OUTPUT:
     170
     171        - a pseudo-Conway polynomial of degree `n` for the prime `p`.
     172
     173        ALGORITHM:
     174
     175        Uses an algorithm described in [HL99]_, modified to find
     176        pseudo-Conway polynomials rather than Conway polynomials.  The
     177        major difference is that we stop as soon as we find a
     178        primitive polynomial.
     179
     180        REFERENCE:
     181
     182        .. [HL99] L. Heath and N. Loehr (1999).  New algorithms for
     183           generating Conway polynomials over finite fields.
     184           Proceedings of the tenth annual ACM-SIAM symposium on
     185           discrete algorithms, pp. 429-437.
     186
     187        EXAMPLES::
     188
     189            sage: from sage.rings.finite_rings.conway_polynomials import PseudoConwayLattice
     190            sage: PCL = PseudoConwayLattice(2, use_database=False)
     191            sage: PCL.polynomial(3)
     192            x^3 + x + 1
     193            sage: PCL.polynomial(4)
     194            x^4 + x^3 + 1
     195            sage: PCL.polynomial(60)
     196            x^60 + x^59 + x^58 + x^55 + x^54 + x^53 + x^52 + x^51 + x^48 + x^46 + x^45 + x^42 + x^41 + x^39 + x^38 + x^37 + x^35 + x^32 + x^31 + x^30 + x^28 + x^24 + x^22 + x^21 + x^18 + x^17 + x^16 + x^15 + x^14 + x^10 + x^8 + x^7 + x^5 + x^3 + x^2 + x + 1
     197        """
     198        if self.nodes.has_key(n):
     199            return self.nodes[n]
     200
     201        p = self.p
     202
     203        if n == 1:
     204            f = self.ring.gen() - FiniteField(p).multiplicative_generator()
     205            self.nodes[1] = f
     206            return f
     207
     208        # Work in an arbitrary field K of order p**n.
     209        K = FiniteField(p**n, names='a')
     210
     211        # TODO: something like the following
     212        # gcds = [n.gcd(d) for d in self.nodes.keys()]
     213        # xi = { m: (...) for m in gcds }
     214        xi = {q: self.polynomial(n//q).any_root(K, -n//q, assume_squarefree=True)
     215              for q in n.prime_divisors()}
     216
     217        # The following is needed to ensure that in the concrete instantiation
     218        # of the "new" extension all previous choices are compatible.
     219        _frobenius_shift(K, xi)
     220
     221        # Construct a compatible element having order the lcm of orders
     222        q, x = xi.popitem()
     223        v = p**(n//q) - 1
     224        for q, xitem in xi.iteritems():
     225            w = p**(n//q) - 1
     226            g, alpha, beta = v.xgcd(w)
     227            x = x**beta * xitem**alpha
     228            v = v.lcm(w)
     229
     230        r = p**n - 1
     231        # Get the missing part of the order to be primitive
     232        g = r // v
     233        # Iterate through g-th roots of x until a primitive one is found
     234        z = x.nth_root(g)
     235        root = K.multiplicative_generator()**v
     236        while z.multiplicative_order() != r:
     237            z *= root
     238        # The following should work but tries to create a huge list
     239        # whose length overflows Python's ints for large parameters
     240        #Z = x.nth_root(g, all=True)
     241        #for z in Z:
     242        #    if z.multiplicative_order() == r:
     243        #         break
     244        f = z.minimal_polynomial()
     245        self.nodes[n] = f
     246        return f
     247
     248    def check_consistency(self, n):
     249        """
     250        Check that the pseudo-Conway polynomials of degree dividing
     251        `n` in this lattice satisfy the required compatibility
     252        conditions.
     253
     254        EXAMPLES::
     255
     256            sage: from sage.rings.finite_rings.conway_polynomials import PseudoConwayLattice
     257            sage: PCL = PseudoConwayLattice(2, use_database=False)
     258            sage: PCL.check_consistency(6)
     259            sage: PCL.check_consistency(60)  # long
     260
     261        """
     262        p = self.p
     263        K = FiniteField(p**n, modulus = self.polynomial(n), names='a')
     264        a = K.gen()
     265        for m in n.divisors():
     266            assert (a**((p**n-1)//(p**m-1))).minimal_polynomial() == self.polynomial(m)
     267
     268
     269def _find_pow_of_frobenius(p, n, x, y):
     270    """
     271    Find the power of Frobenius which yields `x` when applied to `y`.
     272
     273    INPUT:
     274
     275    - ``p`` -- prime number
     276
     277    - ``n`` -- positive integer
     278
     279    - ``x`` -- an element of a field `K` of `p^n` elements so that
     280      the multiplicative order of `x` is `p^n - 1`.
     281
     282    - ``y`` -- an element of `K` with the same minimal polynomial as
     283      `x`.
     284
     285    OUTPUT:
     286
     287    - an element `i` of the integers modulo `n` such that `x = y^{p^i}`.
     288
     289    EXAMPLES::
     290
     291        sage: from sage.rings.finite_rings.conway_polynomials import _find_pow_of_frobenius
     292        sage: K.<a> = GF(3^14)
     293        sage: x = K.multiplicative_generator()
     294        sage: y = x^27
     295        sage: _find_pow_of_frobenius(3, 14, x, y)
     296        11
     297
     298    """
     299    from integer_mod import mod
     300    for i in xrange(n):
     301        if x == y: break
     302        y = y**p
     303    else:
     304        raise RuntimeError, "No appropriate power of Frobenius found"
     305    return mod(i, n)
     306
     307def _crt_non_coprime(running, a):
     308    """
     309    Extension of the ``crt`` method of ``IntegerMod`` to the case of
     310    non-relatively prime modulus.
     311
     312    EXAMPLES::
     313
     314        sage: from sage.rings.finite_rings.conway_polynomials import _crt_non_coprime
     315        sage: a = _crt_non_coprime(mod(14, 18), mod(20,30)); a
     316        50
     317        sage: a.modulus()
     318        90
     319        sage: _crt_non_coprime(mod(13, 18), mod(20,30))
     320        Traceback (most recent call last):
     321        ...
     322        AssertionError
     323
     324    """
     325    g = running.modulus().gcd(a.modulus())
     326    if g == 1:
     327        return running.crt(a)
     328    else:
     329        assert running % g == a % g
     330        running_modulus = running.modulus()
     331        a_modulus = a.modulus()
     332        for qq in g.prime_divisors():
     333            a_val_unit = a_modulus.val_unit(qq)
     334            running_val_unit = running_modulus.val_unit(qq)
     335            if a_val_unit[0] > running_val_unit[0]:
     336                running_modulus = running_val_unit[1]
     337            else:
     338                a_modulus = a_val_unit[1]
     339        return (running % running_modulus).crt(a % a_modulus)
     340
     341def _frobenius_shift(K, generators, check_only=False):
     342    """
     343    Given a field `K` of degree `n` over ``GF(p)`` and a dictionary
     344    holding, for each divisor `q` of `n`, an element with minimal
     345    polynomial a pseudo-Conway polynomial of degree `n/q`, modify
     346    these generators into a compatible system.
     347
     348    Such a system of generators is said to be compatible if for each
     349    pair of prime divisors `q_1` and `q_2` and each common divisor `m`
     350    of `n/q_1` and `n/q_2`, the equality
     351
     352    ``generators[q1]^((p^(n/q1)-1)/(p^m-1)) == generators[q2]^((p^(n/q2)-1)/(p^m-1))``
     353
     354    holds.
     355
     356    INPUT:
     357
     358    - ``K`` -- a finite field of degree `n` over its prime field
     359
     360    - ``generators`` -- a dictionary, indexed by prime divisors `q` of
     361      `n`, whose entries are elements of `K` satisfying the `n/q`
     362      pseudo-Conway polynomial.
     363
     364    - ``check_only`` -- if ``True``, just check that the given
     365      generators form a compatible system.
     366
     367    EXAMPLES::
     368
     369        sage: R.<x> = GF(2)[]
     370        sage: f30 = x^30 + x^28 + x^27 + x^25 + x^24 + x^20 + x^19 + x^18 + x^16 + x^15 + x^12 + x^10 + x^7 + x^2 + 1
     371        sage: f20 = x^20 + x^19 + x^15 + x^13 + x^12 + x^11 + x^9 + x^8 + x^7 + x^4 + x^2 + x + 1
     372        sage: f12 = x^12 + x^10 + x^9 + x^8 + x^4 + x^2 + 1
     373        sage: K.<a> = GF(2^60, modulus='first_lexicographic')
     374        sage: x30 = f30.any_root(K)
     375        sage: x20 = f20.any_root(K)
     376        sage: x12 = f12.any_root(K)
     377        sage: generators = {2: x30, 3: x20, 5: x12}
     378        sage: from sage.rings.finite_rings.conway_polynomials import _frobenius_shift, _find_pow_of_frobenius
     379        sage: _frobenius_shift(K, generators)
     380        sage: _find_pow_of_frobenius(2, 30, x30, generators[2])
     381        0
     382        sage: _find_pow_of_frobenius(2, 20, x20, generators[3])
     383        13
     384        sage: _find_pow_of_frobenius(2, 12, x12, generators[5])
     385        8
     386
     387    """
     388    if len(generators) == 1:
     389        return generators
     390    p = K.characteristic()
     391    n = K.degree()
     392    compatible = {}
     393    from integer_mod import mod
     394    for m in n.divisors():
     395        compatible[m] = {}
     396    for q, x in generators.iteritems():
     397        for m in (n//q).divisors():
     398            compatible[m][q] = x**((p**(n//q)-1)//(p**m-1))
     399    if check_only:
     400        for m in n.divisors():
     401            try:
     402                q, x = compatible[m].popitem()
     403            except KeyError:
     404                break
     405            for qq, xx in compatible[m].iteritems():
     406                assert x == xx
     407        return
     408    crt = {}
     409    qlist = sorted(generators.keys())
     410    for j in range(1, len(qlist)):
     411        for i in range(j):
     412            crt[(i, j)] = []
     413    for m in n.divisors():
     414        mqlist = sorted(compatible[m].keys())
     415        for k in range(1,len(mqlist)):
     416            j = qlist.index(mqlist[k])
     417            i = qlist.index(mqlist[k-1])
     418            crt[(i,j)].append(_find_pow_of_frobenius(p, m, compatible[m][qlist[j]], compatible[m][qlist[i]]))
     419    from integer_mod import mod
     420    pairs = crt.keys()
     421    for i, j in pairs:
     422        L = crt[(i,j)]
     423        running = mod(0,1)
     424        for a in L:
     425            running = _crt_non_coprime(running, a)
     426        crt[(i,j)] = [(mod(running, q**(running.modulus().valuation(q))), running.modulus().valuation(q)) for q in qlist]
     427        crt[(j,i)] = [(-a, level) for a, level in crt[(i,j)]]
     428    # Let x_j be the power of Frobenius we apply to generators[qlist[j]], for 0 < j < len(qlist)
     429    # We have some direct conditions on the x_j: x_j reduces to each entry in crt[(0,j)].
     430    # But we also have the equations x_j - x_i reduces to each entry in crt[(i,j)].
     431    # We solve for x_j one prime at a time.  For each prime, we have an equations of the form
     432    # x_j - x_i = c_ij.  The modulus of the currently known value of x_j, x_i and c_ij will all be powers
     433    # (possibly 0, possibly different) of the same prime.
     434
     435    # We can set x_0=0 everywhere, can get an initial setting of x_j from the c_0j.
     436    # We go through prime by prime.
     437    import bisect
     438    frob_powers=[mod(0,1) for q in qlist]
     439    def find_leveller(qindex, level, x, xleveled, searched, i):
     440        searched[i] = True
     441        crt_possibles = []
     442        for j in range(1,len(qlist)):
     443            if i==j: continue
     444            if crt[(i,j)][qindex][1] >= level:
     445                if xleveled[j]:
     446                    return [j]
     447                elif not searched.has_key(j):
     448                    crt_possibles.append(j)
     449        for j in crt_possibles:
     450            path = find_leveller(qindex, level, x, xleveled, searched, j)
     451            if path is not None:
     452                path.append(j)
     453                return path
     454        return None
     455    def propagate_levelling(qindex, level, x, xleveled, i):
     456        for j in range(1, len(qlist)):
     457            if i==j: continue
     458            if not xleveled[j] and crt[(i,j)][qindex][1] >= level:
     459                newxj = x[i][0] + crt[(i,j)][qindex][0]
     460                x[j] = (newxj, min(x[i][1], crt[(i,j)][qindex][1]))
     461                xleveled[j] = True
     462                propagate_levelling(qindex, level, x, xleveled, j)
     463
     464    for qindex in range(len(qlist)):
     465        q = qlist[qindex]
     466        # We include the initial 0 to match up our indexing with crt.
     467        x = [0] + [crt[(0,j)][qindex] for j in range(1,len(qlist))]
     468        # We first check that our equations are consistent and
     469        # determine which powers of q occur as moduli.
     470        levels = []
     471        for j in range(2, len(qlist)):
     472            for i in range(j):
     473                # we need crt[(0,j)] = crt[(0,i)] + crt[(i,j)]
     474                if i != 0:
     475                    assert x[j][0] == x[i][0] + crt[(i,j)][qindex][0]
     476                level = crt[(i,j)][qindex][1]
     477                if level > 0:
     478                    ins = bisect.bisect_left(levels,level)
     479                    if ins == len(levels):
     480                        levels.append(level)
     481                    elif levels[ins] != level:
     482                        levels.insert(ins, level)
     483        for level in levels:
     484            xleveled = [0] + [x[i][1] >= level for i in range(1,len(qlist))]
     485            while True:
     486                try:
     487                    i = xleveled.index(False, 1)
     488                    searched = {}
     489                    levelling_path = find_leveller(qindex, level, x, xleveled, searched, i)
     490                    if levelling_path is None:
     491                        # Any lift will work, since there are no constraints.
     492                        x[i] = (mod(x[i][0].lift(), q**level), level)
     493                        xleveled[i] = True
     494                        propagate_levelling(qindex, level, x, xleveled, i)
     495                    else:
     496                        levelling_path.append(i)
     497                        for m in range(1,len(path)):
     498                            # This point on the path may have already
     499                            # been leveled in a previous propagation.
     500                            if not xleveled[path[m]]:
     501                                newx = x[path[m-1]][0] + crt[(path[m-1],path[m])][qindex][0]
     502                                x[path[m]] = (newx, min(x[path[m-1]][1], crt[(path[m-1],path[m])][qindex][1]))
     503                                xleveled[path[m]] = True
     504                                propagate_levelling(qindex, level, x, xleveled, path[m])
     505                except ValueError:
     506                    break
     507        for j in range(1,len(qlist)):
     508            frob_powers[j] = frob_powers[j].crt(x[j][0])
     509    for j in range(1, len(qlist)):
     510        generators[qlist[j]] = generators[qlist[j]]**(p**(-frob_powers[j]).lift())
     511    _frobenius_shift(K, generators, check_only=True)
  • sage/rings/finite_rings/element_givaro.pyx

    diff --git a/sage/rings/finite_rings/element_givaro.pyx b/sage/rings/finite_rings/element_givaro.pyx
    a b  
    125125    ConwayPolynomials = sage.databases.conway.ConwayPolynomials
    126126   
    127127    import sage.rings.finite_rings.constructor
    128     conway_polynomial = sage.rings.finite_rings.constructor.conway_polynomial
     128    conway_polynomial = sage.rings.finite_rings.conway_polynomials.conway_polynomial
    129129
    130130    import sage.rings.polynomial.multi_polynomial_element
    131131    MPolynomial = sage.rings.polynomial.multi_polynomial_element.MPolynomial
  • sage/rings/finite_rings/element_ntl_gf2e.pyx

    diff --git a/sage/rings/finite_rings/element_ntl_gf2e.pyx b/sage/rings/finite_rings/element_ntl_gf2e.pyx
    a b  
    108108    import sage.databases.conway
    109109    ConwayPolynomials = sage.databases.conway.ConwayPolynomials
    110110   
    111     import sage.rings.finite_rings.constructor
    112     conway_polynomial = sage.rings.finite_rings.constructor.conway_polynomial
     111    import sage.rings.finite_rings.conway_polynomials
     112    conway_polynomial = sage.rings.finite_rings.conway_polynomials.conway_polynomial
    113113
    114114    import sage.rings.polynomial.multi_polynomial_element
    115115    MPolynomial = sage.rings.polynomial.multi_polynomial_element.MPolynomial
  • sage/rings/finite_rings/finite_field_base.pyx

    diff --git a/sage/rings/finite_rings/finite_field_base.pyx b/sage/rings/finite_rings/finite_field_base.pyx
    a b  
    777777            sage: GF(next_prime(2^16, 2), 'a').is_conway()
    778778            False
    779779        """
    780         from constructor import conway_polynomial, exists_conway_polynomial
     780        from conway_polynomials import conway_polynomial, exists_conway_polynomial
    781781        p = self.characteristic()
    782782        n = self.degree()
    783783        return (exists_conway_polynomial(p, n)
  • sage/rings/finite_rings/finite_field_ext_pari.py

    diff --git a/sage/rings/finite_rings/finite_field_ext_pari.py b/sage/rings/finite_rings/finite_field_ext_pari.py
    a b  
    206206        self.__is_field = True
    207207
    208208        if modulus is None or modulus == "default":
    209             from constructor import exists_conway_polynomial
     209            from conway_polynomials import exists_conway_polynomial
    210210            if exists_conway_polynomial(self.__char, self.__degree):
    211211                modulus = "conway"
    212212            else:
     
    214214
    215215        if isinstance(modulus,str):
    216216            if modulus == "conway":
    217                 from constructor import conway_polynomial
     217                from conway_polynomials import conway_polynomial
    218218                modulus = conway_polynomial(self.__char, self.__degree)
    219219            elif modulus == "random":
    220220                # The following is fast/deterministic, but has serious problems since
  • sage/rings/finite_rings/finite_field_givaro.py

    diff --git a/sage/rings/finite_rings/finite_field_givaro.py b/sage/rings/finite_rings/finite_field_givaro.py
    a b  
    128128            if k == 1:
    129129                modulus = 'random' # this will use the gfq_factory_pk function.
    130130            elif ConwayPolynomials().has_polynomial(p, k):
    131                 from sage.rings.finite_rings.constructor import conway_polynomial
     131                from sage.rings.finite_rings.conway_polynomials import conway_polynomial
    132132                modulus = conway_polynomial(p, k)
    133133            elif modulus is None:
    134134                modulus = 'random'
  • sage/rings/finite_rings/finite_field_ntl_gf2e.py

    diff --git a/sage/rings/finite_rings/finite_field_ntl_gf2e.py b/sage/rings/finite_rings/finite_field_ntl_gf2e.py
    a b  
    22Finite Fields of Characteristic 2
    33"""
    44
    5 
    65from sage.rings.finite_rings.finite_field_base import FiniteField
    76from sage.libs.pari.all import pari
    87from finite_field_ext_pari import FiniteField_ext_pari
     
    2928    import sage.rings.finite_rings.finite_field_base
    3029    is_FiniteField = sage.rings.finite_rings.finite_field_base.is_FiniteField
    3130
    32     import sage.rings.finite_rings.constructor
    33     exists_conway_polynomial = sage.rings.finite_rings.constructor.exists_conway_polynomial
    34     conway_polynomial = sage.rings.finite_rings.constructor.conway_polynomial
    35 
    36     import sage.rings.finite_rings.constructor
    37     exists_conway_polynomial = sage.rings.finite_rings.constructor.exists_conway_polynomial
     31    import sage.rings.finite_rings.conway_polynomials
     32    exists_conway_polynomial = sage.rings.finite_rings.conway_polynomials.exists_conway_polynomial
     33    conway_polynomial = sage.rings.finite_rings.conway_polynomials.conway_polynomial
    3834
    3935    import sage.rings.finite_rings.element_ntl_gf2e
    4036    Cache_ntl_gf2e = sage.rings.finite_rings.element_ntl_gf2e.Cache_ntl_gf2e
     
    9692        sage: k.<a> = GF(2^211, modulus='conway')
    9793        sage: k.modulus()
    9894        x^211 + x^9 + x^6 + x^5 + x^3 + x + 1
    99         sage: k.<a> = GF(2^411, modulus='conway')
    100         Traceback (most recent call last):
    101         ...
    102         RuntimeError: requested conway polynomial not in database.
     95        sage: k.<a> = GF(2^23, modulus='conway')
     96        sage: a.multiplicative_order() == k.order() - 1
     97        True
    10398    """
    10499
    105100    def __init__(self, q, names="a",  modulus=None, repr="poly"):
  • sage/rings/polynomial/polynomial_ring.py

    diff --git a/sage/rings/polynomial/polynomial_ring.py b/sage/rings/polynomial/polynomial_ring.py
    a b  
    13581358    def __init__(self, base_ring, name="x", sparse=False, implementation=None,
    13591359            element_class=None):
    13601360        """
    1361         TESTS:
     1361        TESTS::
     1362
    13621363            sage: from sage.rings.polynomial.polynomial_ring import PolynomialRing_integral_domain as PRing
    13631364            sage: R = PRing(ZZ, 'x'); R
    13641365            Univariate Polynomial Ring in x over Integer Ring
     
    13911392   
    13921393    def _repr_(self):
    13931394        """
    1394         TESTS:
     1395        TESTS::
     1396
    13951397            sage: from sage.rings.polynomial.polynomial_ring import PolynomialRing_integral_domain as PRing
    13961398            sage: R = PRing(ZZ, 'x', implementation='NTL'); R
    13971399            Univariate Polynomial Ring in x over Integer Ring (using NTL)
     
    14061408                           ):
    14071409    def __init__(self, base_ring, name="x", sparse=False, element_class=None):
    14081410        """
    1409         TESTS:
     1411        TESTS::
     1412
    14101413            sage: from sage.rings.polynomial.polynomial_ring import PolynomialRing_field as PRing
    14111414            sage: R = PRing(QQ, 'x'); R
    14121415            Univariate Polynomial Ring in x over Rational Field
     
    21722175        - Peter Bruin (June 2013)
    21732176        """
    21742177        from sage.libs.pari.all import pari
    2175         from sage.rings.finite_rings.constructor import (conway_polynomial,
    2176                                                          exists_conway_polynomial)
    2177         from polynomial_gf2x import (GF2X_BuildIrred_list, GF2X_BuildSparseIrred_list,
     2178        from sage.rings.finite_rings.conway_polynomials import (conway_polynomial,
     2179                                                                exists_conway_polynomial)
     2180        from polynomial_gf2x import (GF2X_BuildIrred_list,
     2181                                     GF2X_BuildSparseIrred_list,
    21782182                                     GF2X_BuildRandomIrred_list)
    21792183
    21802184        p = self.characteristic()