Ticket #10975: trac_10975.patch

File trac_10975.patch, 17.5 KB (added by was, 8 years ago)
  • sage/rings/finite_rings/constructor.py

    # HG changeset patch
    # User William Stein <wstein@gmail.com>
    # Date 1300756053 25200
    # Node ID c0a0981fb21ad92bb182a22ff5497004ba6035a7
    # Parent  5b3c91f09f5ab74f07bb4db86a3c8c25d828ff32
    trac 10975 -- creation of certain prime finite fields is double dog slow (compared to Magma)
    
    diff --git a/sage/rings/finite_rings/constructor.py b/sage/rings/finite_rings/constructor.py
    a b  
    205205   
    206206    -  ``check_irreducible`` - verify that the polynomial
    207207       modulus is irreducible
     208
     209    - ``proof`` -- bool (default: True); if True use provable
     210      primality test; otherwise only use pseudoprimality test.
    208211   
    209212    -  ``args`` - additional parameters passed to finite
    210213       field implementations
     
    215218   
    216219    ALIAS: You can also use GF instead of FiniteField - they are
    217220    identical.
    218    
     221
    219222    EXAMPLES::
    220223   
    221224        sage: k.<a> = FiniteField(9); k
     
    225228        sage: charpoly(a, 'y')
    226229        y^2 + 2*y + 2
    227230   
     231    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.)::
     235
     236        sage: k = FiniteField(10^1000 + 453, proof=False)
     237        sage: k = FiniteField((10^1000 + 453)^2, 'a', proof=False)      # long time -- about 5 seconds
     238
    228239    ::
    229240   
    230241        sage: F.<x> = GF(5)[]
     
    308319        sage: k.<a> = GF(2^8,repr='int')
    309320        sage: a
    310321        2
     322
    311323    """
    312     def create_key_and_extra_args(self, order, name=None, modulus=None, names=None, impl=None, **kwds):
     324    def create_key_and_extra_args(self, order, name=None, modulus=None, names=None,
     325                                  impl=None, proof=None, **kwds):
    313326        """
    314327        EXAMPLES::
    315328       
    316329            sage: GF.create_key_and_extra_args(9, 'a')
    317             ((9, ('a',), 'conway', None, '{}'), {})
     330            ((9, ('a',), 'conway', None, '{}', 3, 2, True), {})
    318331            sage: GF.create_key_and_extra_args(9, 'a', foo='value')
    319             ((9, ('a',), 'conway', None, "{'foo': 'value'}"), {'foo': 'value'})
     332            ((9, ('a',), 'conway', None, "{'foo': 'value'}", 3, 2, True), {'foo': 'value'})
    320333        """
    321         order = int(order)
    322         if order == 1:
    323             raise ValueError("the order of a finite field must be > 1")
    324         elif not arith.is_prime_power(order):
    325             raise ValueError("the order of a finite field must be a prime power")
     334        from sage.structure.proof.all import WithProof, arithmetic
     335        if proof is None: proof = arithmetic()
     336        with WithProof('arithmetic', proof):
     337            order = int(order)
     338            if order == 1:
     339                raise ValueError("the order of a finite field must be > 1")
     340            if not arith.is_prime_power(order):
     341                    raise ValueError("the order of a finite field must be a prime power")
    326342
    327         if arith.is_prime(order):
    328             name = None
    329             modulus = None
    330         else:
    331             if not names is None: name = names
    332             name = normalize_names(1,name)
     343            if arith.is_prime(order):
     344                name = None
     345                modulus = None
     346                p = integer.Integer(order)
     347                n = integer.Integer(1)
     348            else:
     349                if not names is None: name = names
     350                name = normalize_names(1,name)
    333351
    334             p,n = arith.factor(order)[0]
     352                p,n = arith.factor(order)[0]
    335353
    336             if modulus is None or modulus == "default":
    337                 if exists_conway_polynomial(p,n):
    338                     modulus = "conway"
    339                 else:
    340                     if p==2:
    341                         modulus = "minimal_weight"
     354                if modulus is None or modulus == "default":
     355                    if exists_conway_polynomial(p,n):
     356                        modulus = "conway"
    342357                    else:
    343                         modulus = "random"
    344             elif modulus == "random":
    345                 modulus += str(random.randint(0, 1<<128))
     358                        if p==2:
     359                            modulus = "minimal_weight"
     360                        else:
     361                            modulus = "random"
     362                elif modulus == "random":
     363                    modulus += str(random.randint(0, 1<<128))
    346364
    347             if isinstance(modulus, (list, tuple)):
    348                 modulus = FiniteField(p)['x'](modulus)
    349             # some classes use 'random' as the modulus to
    350             # generate a random modulus, but we don't want
    351             # to cache it
    352             elif sage.rings.polynomial.polynomial_element.is_Polynomial(modulus):
    353                 modulus = modulus.change_variable_name('x')
    354             elif not isinstance(modulus, str):
    355                 raise ValueError("Modulus parameter not understood")
     365                if isinstance(modulus, (list, tuple)):
     366                    modulus = FiniteField(p)['x'](modulus)
     367                # some classes use 'random' as the modulus to
     368                # generate a random modulus, but we don't want
     369                # to cache it
     370                elif sage.rings.polynomial.polynomial_element.is_Polynomial(modulus):
     371                    modulus = modulus.change_variable_name('x')
     372                elif not isinstance(modulus, str):
     373                    raise ValueError("Modulus parameter not understood")
    356374
    357         return (order, name, modulus, impl, str(kwds)), kwds
     375            return (order, name, modulus, impl, str(kwds), p, n, proof), kwds
    358376   
    359     def create_object(self, version, key, check_irreducible=True, elem_cache=None, names=None, **kwds):
     377    def create_object(self, version, key, check_irreducible=True, elem_cache=None,
     378                      names=None, **kwds):
    360379        """
    361380        EXAMPLES::
    362381       
    363382            sage: K = GF(19)
    364383            sage: TestSuite(K).run()
    365384        """
    366 
    367385        # IMPORTANT!  If you add a new class to the list of classes
    368386        # that get cached by this factor object, then you *must* add
    369387        # the following method to that class in order to fully support
     
    376394        # fields need not be created using this factory object, e.g., residue
    377395        # class fields.
    378396       
    379         order, name, modulus, impl, _ = key
     397        order, name, modulus, impl, _, p, n, proof = key
    380398       
    381399        if isinstance(modulus, str) and modulus.startswith("random"):
    382400            modulus = "random"
     
    384402        if elem_cache is None:
    385403            elem_cache = order < 500
    386404
    387         if arith.is_prime(order) and (impl is None or impl == 'modn'):
     405        if n == 1 and (impl is None or impl == 'modn'):
    388406            from finite_field_prime_modn import FiniteField_prime_modn
    389             K = FiniteField_prime_modn(order, **kwds)
     407            # Using a check option here is probably a worthwhile
     408            # compromise since this constructor is simple and used a
     409            # huge amount.
     410            K = FiniteField_prime_modn(order, check=False, **kwds)
    390411        else:
    391             if check_irreducible and polynomial_element.is_Polynomial(modulus):
    392                 if modulus.parent().base_ring().characteristic() == 0:
    393                     p = arith.factor(order)[0][0]
    394                     modulus = modulus.change_ring(FiniteField(p))
    395                 if not modulus.is_irreducible():
    396                     raise ValueError, "finite field modulus must be irreducible but it is not"
    397             if name is None:
    398                 raise TypeError, "you must specify the generator name"
    399             if order < zech_log_bound: 
    400                 # DO *NOT* use for prime subfield, since that would lead to
    401                 # a circular reference in the call to ParentWithGens in the
    402                 # __init__ method.
    403                 K = FiniteField_givaro(order, name, modulus, cache=elem_cache,**kwds)
    404             else:
    405                 if order % 2 == 0 and (impl is None or impl == 'ntl'):
    406                     from element_ntl_gf2e import FiniteField_ntl_gf2e
    407                     K = FiniteField_ntl_gf2e(order, name, modulus, **kwds)
     412            # We have to do this with block so that the finite field
     413            # constructors below will use the proof flag that was
     414            # passed in when checking for primality, factoring, etc.
     415            # Otherwise, we would have to complicate all of their
     416            # constructors with check options (like above).
     417            from sage.structure.proof.all import WithProof
     418            with WithProof('arithmetic', proof):
     419                if check_irreducible and polynomial_element.is_Polynomial(modulus):
     420                    if modulus.parent().base_ring().characteristic() == 0:
     421                        modulus = modulus.change_ring(FiniteField(p))
     422                    if not modulus.is_irreducible():
     423                        raise ValueError, "finite field modulus must be irreducible but it is not"
     424                if name is None:
     425                    raise TypeError, "you must specify the generator name"
     426                if order < zech_log_bound: 
     427                    # DO *NOT* use for prime subfield, since that would lead to
     428                    # a circular reference in the call to ParentWithGens in the
     429                    # __init__ method.
     430                    K = FiniteField_givaro(order, name, modulus, cache=elem_cache,**kwds)
    408431                else:
    409                     from finite_field_ext_pari import FiniteField_ext_pari
    410                     K = FiniteField_ext_pari(order, name, modulus, **kwds)
     432                    if order % 2 == 0 and (impl is None or impl == 'ntl'):
     433                        from element_ntl_gf2e import FiniteField_ntl_gf2e
     434                        K = FiniteField_ntl_gf2e(order, name, modulus, **kwds)
     435                    else:
     436                        from finite_field_ext_pari import FiniteField_ext_pari
     437                        K = FiniteField_ext_pari(order, name, modulus, **kwds)
    411438
    412439        return K
    413440
     
    416443        EXAMPLES::
    417444       
    418445            sage: key, extra = GF.create_key_and_extra_args(9, 'a'); key
    419             (9, ('a',), 'conway', None, '{}')
     446            (9, ('a',), 'conway', None, '{}', 3, 2, True)
    420447            sage: K = GF.create_object(0, key); K
    421448            Finite Field in a of size 3^2
    422449            sage: GF.other_keys(key, K)
    423             [(9, ('a',), x^2 + 2*x + 2, None, '{}'),
    424              (9, ('a',), x^2 + 2*x + 2, 'givaro', '{}')]
     450            [(9, ('a',), x^2 + 2*x + 2, None, '{}', 3, 2, True),
     451             (9, ('a',), x^2 + 2*x + 2, 'givaro', '{}', 3, 2, True)]
    425452        """
    426         order, name, modulus, impl, _ = key
    427         if K.degree() > 1:
    428             modulus = K.modulus().change_variable_name('x')
    429         new_keys = [(order, name, modulus, impl, _)]
    430         from finite_field_prime_modn import FiniteField_prime_modn
    431         if isinstance(K, FiniteField_prime_modn):
    432             impl = 'modn'
    433         elif isinstance(K, FiniteField_givaro):
    434             impl = 'givaro'
    435         else:
    436             from element_ntl_gf2e import FiniteField_ntl_gf2e
    437             from finite_field_ext_pari import FiniteField_ext_pari
    438             if isinstance(K, FiniteField_ntl_gf2e):
    439                 impl = 'ntl'
    440             elif isinstance(K, FiniteField_ext_pari):
    441                 impl = 'pari'
    442         new_keys.append( (order, name, modulus, impl, _) )
    443         return new_keys
     453        order, name, modulus, impl, _, p, n, proof = key
     454
     455        from sage.structure.proof.all import WithProof
     456        with WithProof('arithmetic', proof):
     457            if K.degree() > 1:
     458                modulus = K.modulus().change_variable_name('x')
     459            new_keys = [(order, name, modulus, impl, _, p, n, proof)]
     460            from finite_field_prime_modn import FiniteField_prime_modn
     461            if isinstance(K, FiniteField_prime_modn):
     462                impl = 'modn'
     463            elif isinstance(K, FiniteField_givaro):
     464                impl = 'givaro'
     465            else:
     466                from element_ntl_gf2e import FiniteField_ntl_gf2e
     467                from finite_field_ext_pari import FiniteField_ext_pari
     468                if isinstance(K, FiniteField_ntl_gf2e):
     469                    impl = 'ntl'
     470                elif isinstance(K, FiniteField_ext_pari):
     471                    impl = 'pari'
     472            new_keys.append( (order, name, modulus, impl, _, p, n, proof) )
     473            return new_keys
    444474
    445475
    446476GF = FiniteField = FiniteFieldFactory("FiniteField")
  • sage/rings/finite_rings/finite_field_prime_modn.py

    diff --git a/sage/rings/finite_rings/finite_field_prime_modn.py b/sage/rings/finite_rings/finite_field_prime_modn.py
    a b  
    3939
    4040
    4141class FiniteField_prime_modn(FiniteField_generic, integer_mod_ring.IntegerModRing_generic):
    42     def __init__(self, p, name=None):
     42    def __init__(self, p, name=None, check=True):
    4343        """
    4444        Return a new finite field of order $p$ where $p$ is prime.
    4545
    4646        INPUT:
    47             p -- an integer >= 2
    48             name -- ignored
    4947
    50         EXAMPLES:
     48            - p -- an integer >= 2
     49            - ``name`` -- ignored
     50            - ``check`` -- bool (default: True); if False, do not
     51              check p for primality
     52
     53        EXAMPLES::
     54       
    5155            sage: FiniteField(3)
    5256            Finite Field of size 3
    5357           
     
    5559            Finite Field of size 1009
    5660        """
    5761        p = integer.Integer(p)
    58         if not arith.is_prime(p):
     62        if check and not arith.is_prime(p):
    5963            raise ArithmeticError, "p must be prime"
    6064        from sage.categories.finite_fields import FiniteFields
    6165        self.__char = p
  • sage/structure/factory.pyx

    diff --git a/sage/structure/factory.pyx b/sage/structure/factory.pyx
    a b  
    190190            sage: test_factory.create_key_and_extra_args(1, 2, key=5)
    191191            ((1, 2), {})
    192192            sage: GF.create_key_and_extra_args(3, foo='value')
    193             ((3, None, None, None, "{'foo': 'value'}"), {'foo': 'value'})
     193            ((3, None, None, None, "{'foo': 'value'}", 3, 1, True), {'foo': 'value'})
    194194        """
    195195        return self.create_key(*args, **kwds), {}
    196196       
     
    232232
    233233        EXAMPLES:
    234234            sage: key, _ = GF.create_key_and_extra_args(27, 'k'); key
    235             (27, ('k',), 'conway', None, '{}')
     235            (27, ('k',), 'conway', None, '{}', 3, 3, True)
    236236            sage: K = GF.create_object(0, key); K
    237237            Finite Field in k of size 3^3
    238238            sage: GF.other_keys(key, K)
    239             [(27, ('k',), x^3 + 2*x + 1, None, '{}'),
    240              (27, ('k',), x^3 + 2*x + 1, 'givaro', '{}')]
     239            [(27, ('k',), x^3 + 2*x + 1, None, '{}', 3, 3, True),
     240             (27, ('k',), x^3 + 2*x + 1, 'givaro', '{}', 3, 3, True)]
    241241           
    242242            sage: K = GF(7^40, 'a')
    243243            sage: loads(dumps(K)) is K
  • sage/structure/proof/all.py

    diff --git a/sage/structure/proof/all.py b/sage/structure/proof/all.py
    a b  
    152152        return _proof_prefs._require_proof.copy()
    153153    for s in _proof_prefs._require_proof.iterkeys():
    154154        _proof_prefs._require_proof[s] = bool(t)
     155
     156from proof import WithProof
  • sage/structure/proof/proof.py

    diff --git a/sage/structure/proof/proof.py b/sage/structure/proof/proof.py
    a b  
    171171            return _proof_prefs._require_proof["other"]
    172172    return t
    173173
     174class WithProof:
     175    """
     176    Use WithProof to temparily set the value of one of the proof
     177    systems for a block of code, with a guarantee that it will be set
     178    back to how it was before after the block is done, even if there is an error.
     179   
     180    EXAMPLES::
     181
     182        sage: proof.arithmetic(True)
     183        sage: with proof.WithProof('arithmetic',False):    # this would hang "forever" if attempted with proof=True
     184        ...      print (10^1000 + 453).is_prime()
     185        ...      print 1/0
     186        ...
     187        Traceback (most recent call last):
     188        ...
     189        ZeroDivisionError: Rational division by zero
     190        sage: proof.arithmetic()
     191        True
     192    """
     193    def __init__(self, subsystem, t):
     194        """
     195        TESTS::
     196       
     197            sage: proof.arithmetic(True)
     198            sage: P = proof.WithProof('arithmetic',False); P
     199            <sage.structure.proof.proof.WithProof instance at ...>
     200            sage: P._subsystem
     201            'arithmetic'
     202            sage: P._t
     203            False
     204            sage: P._t_orig
     205            True
     206        """
     207        self._subsystem = str(subsystem)
     208        self._t = bool(t)
     209        self._t_orig = _proof_prefs._require_proof[subsystem]
     210       
     211    def __enter__(self):
     212        """
     213        TESTS::
     214       
     215            sage: proof.arithmetic(True)
     216            sage: P = proof.WithProof('arithmetic',False)
     217            sage: P.__enter__()
     218            sage: proof.arithmetic()
     219            False
     220            sage: proof.arithmetic(True)
     221        """
     222        _proof_prefs._require_proof[self._subsystem] = self._t
     223
     224    def __exit__(self, *args):
     225        """
     226        TESTS::
     227       
     228            sage: proof.arithmetic(True)
     229            sage: P = proof.WithProof('arithmetic',False)
     230            sage: P.__enter__()
     231            sage: proof.arithmetic()
     232            False
     233            sage: P.__exit__()
     234            sage: proof.arithmetic()
     235            True
     236        """
     237        _proof_prefs._require_proof[self._subsystem] = self._t_orig
     238