예제 #1
0
def hadamard_matrix(n):
    """
    Tries to construct a Hadamard matrix using a combination of Paley
    and Sylvester constructions.

    EXAMPLES::

        sage: hadamard_matrix(12).det()
        2985984
        sage: 12^6
        2985984
        sage: hadamard_matrix(2)
        [ 1  1]
        [ 1 -1]
        sage: hadamard_matrix(8)
        [ 1  1  1  1  1  1  1  1]
        [ 1 -1  1 -1  1 -1  1 -1]
        [ 1  1 -1 -1  1  1 -1 -1]
        [ 1 -1 -1  1  1 -1 -1  1]
        [ 1  1  1  1 -1 -1 -1 -1]
        [ 1 -1  1 -1 -1  1 -1  1]
        [ 1  1 -1 -1 -1 -1  1  1]
        [ 1 -1 -1  1 -1  1  1 -1]
        sage: hadamard_matrix(8).det() == 8^4
        True
    """
    if not (n % 4 == 0) and (n != 2):
        raise ValueError("The Hadamard matrix of order %s does not exist" % n)
    if n == 2:
        return matrix([[1, 1], [1, -1]])
    if is_even(n):
        N = Integer(n / 2)
    elif n == 1:
        return matrix([1])
    if is_prime(N - 1) and (N - 1) % 4 == 1:
        return hadamard_matrix_paleyII(n)
    elif n == 4 or n % 8 == 0:
        had = hadamard_matrix(Integer(n / 2))
        chad1 = matrix([list(r) + list(r) for r in had.rows()])
        mhad = (-1) * had
        R = len(had.rows())
        chad2 = matrix(
            [list(had.rows()[i]) + list(mhad.rows()[i]) for i in range(R)])
        return chad1.stack(chad2)
    elif is_prime(N - 1) and (N - 1) % 4 == 3:
        return hadamard_matrix_paleyI(n)
    else:
        raise ValueError(
            "The Hadamard matrix of order %s is not yet implemented." % n)
예제 #2
0
def hadamard_matrix(n):
    """
    Tries to construct a Hadamard matrix using a combination of Paley
    and Sylvester constructions.

    EXAMPLES::

        sage: hadamard_matrix(12).det()
        2985984
        sage: 12^6
        2985984
        sage: hadamard_matrix(2)
        [ 1  1]
        [ 1 -1]
        sage: hadamard_matrix(8)
        [ 1  1  1  1  1  1  1  1]
        [ 1 -1  1 -1  1 -1  1 -1]
        [ 1  1 -1 -1  1  1 -1 -1]
        [ 1 -1 -1  1  1 -1 -1  1]
        [ 1  1  1  1 -1 -1 -1 -1]
        [ 1 -1  1 -1 -1  1 -1  1]
        [ 1  1 -1 -1 -1 -1  1  1]
        [ 1 -1 -1  1 -1  1  1 -1]
        sage: hadamard_matrix(8).det() == 8^4
        True
    """
    if not(n % 4 == 0) and (n != 2):
        raise ValueError("The Hadamard matrix of order %s does not exist" % n)
    if n == 2:
        return matrix([[1, 1], [1, -1]])
    if is_even(n):
        N = Integer(n / 2)
    elif n == 1:
        return matrix([1])
    if is_prime(N - 1) and (N - 1) % 4 == 1:
        return hadamard_matrix_paleyII(n)
    elif n == 4 or n % 8 == 0:
        had = hadamard_matrix(Integer(n / 2))
        chad1 = matrix([list(r) + list(r) for r in had.rows()])
        mhad = (-1) * had
        R = len(had.rows())
        chad2 = matrix([list(had.rows()[i]) + list(mhad.rows()[i])
                       for i in range(R)])
        return chad1.stack(chad2)
    elif is_prime(N - 1) and (N - 1) % 4 == 3:
        return hadamard_matrix_paleyI(n)
    else:
        raise ValueError("The Hadamard matrix of order %s is not yet implemented." % n)
예제 #3
0
def hadamard_matrix_paleyI(n):
    """
    Implements the Paley type I construction.

    The Paley type I case corresponds to the case `p \cong 3 \mod{4}` for a
    prime `p` (see [Hora]_).

    EXAMPLES:

    We note that this method returns a normalised Hadamard matrix ::

        sage: sage.combinat.matrices.hadamard_matrix.hadamard_matrix_paleyI(4)
        [ 1  1  1  1]
        [ 1 -1 -1  1]
        [ 1  1 -1 -1]
        [ 1 -1  1 -1]
    """
    p = n - 1
    if not (is_prime(p) and (p % 4 == 3)):
        raise ValueError(
            "The order %s is not covered by the Paley type I construction." %
            n)
    H = matrix(ZZ, [[H1(i, j, p) for i in range(n)] for j in range(n)])
    # normalising H so that first row and column have only +1 entries.
    return normalise_hadamard(H)
예제 #4
0
    def create_key_and_extra_args(self,
                                  order,
                                  name=None,
                                  modulus=None,
                                  names=None,
                                  impl=None,
                                  proof=None,
                                  **kwds):
        """
        EXAMPLES::
        
            sage: GF.create_key_and_extra_args(9, 'a')
            ((9, ('a',), 'conway', None, '{}', 3, 2, True), {})
            sage: GF.create_key_and_extra_args(9, 'a', foo='value')
            ((9, ('a',), 'conway', None, "{'foo': 'value'}", 3, 2, True), {'foo': 'value'})
        """
        from sage.structure.proof.all import WithProof, arithmetic
        if proof is None: proof = arithmetic()
        with WithProof('arithmetic', proof):
            order = int(order)
            if order <= 1:
                raise ValueError("the order of a finite field must be > 1.")

            if arith.is_prime(order):
                name = None
                modulus = None
                p = integer.Integer(order)
                n = integer.Integer(1)
            elif arith.is_prime_power(order):
                if not names is None: name = names
                name = normalize_names(1, name)

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

                if modulus is None or modulus == "default":
                    if exists_conway_polynomial(p, n):
                        modulus = "conway"
                    else:
                        if p == 2:
                            modulus = "minimal_weight"
                        else:
                            modulus = "random"
                elif modulus == "random":
                    modulus += str(random.randint(0, 1 << 128))

                if isinstance(modulus, (list, tuple)):
                    modulus = FiniteField(p)['x'](modulus)
                # some classes use 'random' as the modulus to
                # generate a random modulus, but we don't want
                # to cache it
                elif sage.rings.polynomial.polynomial_element.is_Polynomial(
                        modulus):
                    modulus = modulus.change_variable_name('x')
                elif not isinstance(modulus, str):
                    raise ValueError("Modulus parameter not understood.")
            else:  # Neither a prime, nor a prime power
                raise ValueError(
                    "the order of a finite field must be a prime power.")

            return (order, name, modulus, impl, str(kwds), p, n, proof), kwds
예제 #5
0
    def __init__(self, p, name=None, check=True):
        """
        Return a new finite field of order `p` where `p` is prime.

        INPUT:

        - ``p`` -- an integer at least 2

        - ``name`` -- ignored

        - ``check`` -- bool (default: ``True``); if ``False``, do not
          check ``p`` for primality

        EXAMPLES::

            sage: F = FiniteField(3); F
            Finite Field of size 3
        """
        p = integer.Integer(p)
        if check and not arith.is_prime(p):
            raise ArithmeticError("p must be prime")
        self.__char = p
        self._kwargs = {}
        # FiniteField_generic does nothing more than IntegerModRing_generic, and
        # it saves a non trivial overhead
        integer_mod_ring.IntegerModRing_generic.__init__(self, p, category = _FiniteFields)
예제 #6
0
    def __init__(self, p, name=None, check=True):
        """
        Return a new finite field of order $p$ where $p$ is prime.

        INPUT:

        - p -- an integer >= 2
        - ``name`` -- ignored
        - ``check`` -- bool (default: True); if False, do not
          check p for primality

        EXAMPLES::
        
            sage: FiniteField(3)
            Finite Field of size 3
            
            sage: FiniteField(next_prime(1000))
            Finite Field of size 1009
        """
        p = integer.Integer(p)
        if check and not arith.is_prime(p):
            raise ArithmeticError, "p must be prime"
        self.__char = p
        self._IntegerModRing_generic__factored_order = factorization.Factorization([(p,1)], integer.Integer(1))
        self._kwargs = {}
        # FiniteField_generic does nothing more than IntegerModRing_generic, and
        # it saves a non trivial overhead
        integer_mod_ring.IntegerModRing_generic.__init__(self, p, category = _FiniteFields)
예제 #7
0
    def __init__(self, p, name=None, check=True):
        """
        Return a new finite field of order `p` where `p` is prime.

        INPUT:

        - ``p`` -- an integer at least 2

        - ``name`` -- ignored

        - ``check`` -- bool (default: ``True``); if ``False``, do not
          check ``p`` for primality

        EXAMPLES::

            sage: F = FiniteField(3); F
            Finite Field of size 3
        """
        p = integer.Integer(p)
        if check and not arith.is_prime(p):
            raise ArithmeticError, "p must be prime"
        self.__char = p
        self._IntegerModRing_generic__factored_order = factorization.Factorization(
            [(p, 1)], integer.Integer(1))
        self._kwargs = {}
        # FiniteField_generic does nothing more than IntegerModRing_generic, and
        # it saves a non trivial overhead
        integer_mod_ring.IntegerModRing_generic.__init__(
            self, p, category=_FiniteFields)
예제 #8
0
    def apply_sparse(self, x):
        """
        Return the image of x under self. If x is not in self.domain(),
        raise a TypeError.

        EXAMPLES:
            sage: M = ModularSymbols(17,4,-1)
            sage: T = M.hecke_operator(4)
            sage: T.apply_sparse(M.0)
            64*[X^2,(1,8)] + 24*[X^2,(1,10)] - 9*[X^2,(1,13)] + 37*[X^2,(1,16)]
            sage: [ T.apply_sparse(x) == T.hecke_module_morphism()(x) for x in M.basis() ]
            [True, True, True, True]
            sage: N = ModularSymbols(17,4,1)
            sage: T.apply_sparse(N.0)
            Traceback (most recent call last):
            ...
            TypeError: x (=[X^2,(0,1)]) must be in Modular Symbols space of dimension 4 for Gamma_0(17) of weight 4 with sign -1 over Rational Field
        """
        if x not in self.domain():
            raise TypeError("x (=%s) must be in %s"%(x, self.domain()))

        # old version just to check for correctness
        #return self.hecke_module_morphism()(x)

        p = self.index()
        if is_prime(p):
            H = heilbronn.HeilbronnCremona(p)
        else:
            H = heilbronn.HeilbronnMerel(p)

        M = self.parent().module()
        mod2term = M._mod2term
        syms = M.manin_symbols()
        K = M.base_ring()
        R = M.manin_gens_to_basis()

        W = R.new_matrix(nrows=1, ncols = R.nrows())

        B = M.manin_basis()

        #from sage.all import cputime
        #t = cputime()
        v = x.element()
        for i in v.nonzero_positions():
            for h in H:
                entries = syms.apply(B[i], h)
                for k, w in entries:
                    f, s = mod2term[k]
                    if s:
                        W[0,f] += s*K(w)*v[i]

        #print 'sym', cputime(t)
        #t = cputime()
        ans = M( v.parent()((W * R).row(0)) )
        #print 'mul', cputime(t)
        #print 'density: ', len(W.nonzero_positions())/(W.nrows()*float(W.ncols()))

        return ans
예제 #9
0
    def apply_sparse(self, x):
        """
        Return the image of x under self. If x is not in self.domain(),
        raise a TypeError.

        EXAMPLES:
            sage: M = ModularSymbols(17,4,-1)
            sage: T = M.hecke_operator(4)
            sage: T.apply_sparse(M.0)
            64*[X^2,(1,8)] + 24*[X^2,(1,10)] - 9*[X^2,(1,13)] + 37*[X^2,(1,16)]
            sage: [ T.apply_sparse(x) == T.hecke_module_morphism()(x) for x in M.basis() ]
            [True, True, True, True]
            sage: N = ModularSymbols(17,4,1)
            sage: T.apply_sparse(N.0)
            Traceback (most recent call last):
            ...
            TypeError: x (=[X^2,(0,1)]) must be in Modular Symbols space of dimension 4 for Gamma_0(17) of weight 4 with sign -1 over Rational Field
        """
        if x not in self.domain():
            raise TypeError, "x (=%s) must be in %s"%(x, self.domain())

        # old version just to check for correctness
        #return self.hecke_module_morphism()(x)

        p = self.index()
        if is_prime(p):
            H = heilbronn.HeilbronnCremona(p)
        else:
            H = heilbronn.HeilbronnMerel(p)

        M = self.parent().module()
        mod2term = M._mod2term
        syms = M.manin_symbols()
        K = M.base_ring()
        R = M.manin_gens_to_basis()

        W = R.new_matrix(nrows=1, ncols = R.nrows())

        B = M.manin_basis()

        #from sage.all import cputime
        #t = cputime()
        v = x.element()
        for i in v.nonzero_positions():
            for h in H:
                entries = syms.apply(B[i], h)
                for k, w in entries:
                    f, s = mod2term[k]
                    if s:
                        W[0,f] += s*K(w)*v[i]

        #print 'sym', cputime(t)
        #t = cputime()
        ans = M( v.parent()((W * R).row(0)) )
        #print 'mul', cputime(t)
        #print 'density: ', len(W.nonzero_positions())/(W.nrows()*float(W.ncols()))

        return ans
예제 #10
0
    def is_primitive(self,return_base=False):
        r"""
        A pillowcase cover is primitive if it does not cover an other pillowcase
        cover.
        """
        from sage.rings.arith import is_prime
        if is_prime(self.degree()):
            return True

        return bool(gap.IsPrimitive(self.monodromy()))
예제 #11
0
    def create_key_and_extra_args(self, order, name=None, modulus=None, names=None, impl=None, proof=None, **kwds):
        """
        EXAMPLES::

            sage: GF.create_key_and_extra_args(9, 'a')
            ((9, ('a',), 'conway', None, '{}', 3, 2, True), {})
            sage: GF.create_key_and_extra_args(9, 'a', foo='value')
            ((9, ('a',), 'conway', None, "{'foo': 'value'}", 3, 2, True), {'foo': 'value'})
        """
        from sage.structure.proof.all import WithProof, arithmetic

        if proof is None:
            proof = arithmetic()
        with WithProof("arithmetic", proof):
            order = int(order)
            if order <= 1:
                raise ValueError("the order of a finite field must be > 1.")

            if arith.is_prime(order):
                name = None
                modulus = None
                p = integer.Integer(order)
                n = integer.Integer(1)
            elif arith.is_prime_power(order):
                if not names is None:
                    name = names
                name = normalize_names(1, name)

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

                if modulus is None or modulus == "default":
                    if exists_conway_polynomial(p, n):
                        modulus = "conway"
                    else:
                        if p == 2:
                            modulus = "minimal_weight"
                        else:
                            modulus = "random"
                elif modulus == "random":
                    modulus += str(random.randint(0, 1 << 128))

                if isinstance(modulus, (list, tuple)):
                    modulus = FiniteField(p)["x"](modulus)
                # some classes use 'random' as the modulus to
                # generate a random modulus, but we don't want
                # to cache it
                elif sage.rings.polynomial.polynomial_element.is_Polynomial(modulus):
                    modulus = modulus.change_variable_name("x")
                elif not isinstance(modulus, str):
                    raise ValueError("Modulus parameter not understood.")
            else:  # Neither a prime, nor a prime power
                raise ValueError("the order of a finite field must be a prime power.")

            return (order, name, modulus, impl, str(kwds), p, n, proof), kwds
예제 #12
0
    def is_integral_domain(self, proof = True):
        """
        Return True if and only if the order of self is prime.

        EXAMPLES::

            sage: Integers(389).is_integral_domain()
            True
            sage: Integers(389^2).is_integral_domain()
            False
        """
        return is_prime(self.order())
예제 #13
0
 def is_integral_domain(self, proof=True):
     """
     Return True if and only if the order of self is prime.
     
     EXAMPLES::
     
         sage: Integers(389).is_integral_domain()
         True
         sage: Integers(389^2).is_integral_domain()
         False
     """
     return is_prime(self.order())
예제 #14
0
    def create_key_and_extra_args(self,
                                  order,
                                  name=None,
                                  modulus=None,
                                  names=None,
                                  impl=None,
                                  proof=None,
                                  **kwds):
        """
        EXAMPLES::

            sage: GF.create_key_and_extra_args(9, 'a')
            ((9, ('a',), x^2 + 2*x + 2, None, '{}', 3, 2, True), {})
            sage: GF.create_key_and_extra_args(9, 'a', foo='value')
            ((9, ('a',), x^2 + 2*x + 2, None, "{'foo': 'value'}", 3, 2, True), {'foo': 'value'})
        """
        from sage.structure.proof.all import WithProof, arithmetic
        if proof is None: proof = arithmetic()
        with WithProof('arithmetic', proof):
            order = int(order)
            if order <= 1:
                raise ValueError("the order of a finite field must be > 1.")

            if arith.is_prime(order):
                name = None
                modulus = None
                p = integer.Integer(order)
                n = integer.Integer(1)
            elif arith.is_prime_power(order):
                if not names is None: name = names
                name = normalize_names(1, name)

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

                if modulus is None or isinstance(modulus, str):
                    # A string specifies an algorithm to find a suitable modulus.
                    if modulus == "default":  # for backward compatibility
                        modulus = None
                    modulus = GF(p)['x'].irreducible_element(n,
                                                             algorithm=modulus)
                elif isinstance(modulus, (list, tuple)):
                    modulus = GF(p)['x'](modulus)
                elif sage.rings.polynomial.polynomial_element.is_Polynomial(
                        modulus):
                    modulus = modulus.change_variable_name('x')
                else:
                    raise TypeError("wrong type for modulus parameter")
            else:
                raise ValueError(
                    "the order of a finite field must be a prime power.")

            return (order, name, modulus, impl, str(kwds), p, n, proof), kwds
예제 #15
0
def hadamard_matrix_paleyI(n):
    """
    Implements the Paley type I construction.

    EXAMPLES::

        sage: sage.combinat.matrices.hadamard_matrix.hadamard_matrix_paleyI(4)
        [ 1 -1 -1 -1]
        [ 1  1  1 -1]
        [ 1 -1  1  1]
        [ 1  1 -1  1]
    """
    p = n - 1
    if not(is_prime(p) and (p % 4 == 3)):
        raise ValueError("The order %s is not covered by the Paley type I construction." % n)
    return matrix(ZZ, [[H1(i, j, p) for i in range(n)] for j in range(n)])
예제 #16
0
def hadamard_matrix_paleyI(n):
    """
    Implements the Paley type I construction.

    EXAMPLES::
        sage: sage.combinat.matrices.hadamard_matrix.hadamard_matrix_paleyI(4)
        [ 1 -1 -1 -1]
        [ 1  1  1 -1]
        [ 1 -1  1  1]
        [ 1  1 -1  1]
    """
    if is_prime(n-1) and (n-1)%4==3:
        p = n-1
    else:
        raise ValueError, "The order %s is not covered by the Paley type I construction."%n
    return matrix(ZZ,[[H1(i,j,p) for i in range(n)] for j in range(n)])
예제 #17
0
    def _element_constructor_(self, e):
        """
        TESTS::

            sage: P = Sets().example()
            sage: P._element_constructor_(13) == 13
            True
            sage: P._element_constructor_(13).parent()
            Integer Ring
            sage: P._element_constructor_(14)
            Traceback (most recent call last):
            ...
            AssertionError: 14 is not a prime number
        """
        p = self.element_class(e)
        assert is_prime(p), "%s is not a prime number"%(p)
        return p
예제 #18
0
파일: dims.py 프로젝트: thalespaiva/sagelib
def CO_delta(r, p, N, eps):
    r"""
    This is used as an intermediate value in computations related to
    the paper of Cohen-Oesterle.
    
    INPUT:
    
    
    -  ``r`` - positive integer
    
    -  ``p`` - a prime
    
    -  ``N`` - positive integer
    
    -  ``eps`` - character
    
    
    OUTPUT: element of the base ring of the character
    
    EXAMPLES::
    
        sage: G.<eps> = DirichletGroup(7)
        sage: sage.modular.dims.CO_delta(1,5,7,eps^3)
        2
    """
    if not is_prime(p):
        raise ValueError, "p must be prime"
    K = eps.base_ring()
    if p % 4 == 3:
        return K(0)
    if p == 2:
        if r == 1:
            return K(1)
        return K(0)
    # interesting case: p=1(mod 4).
    # omega is a primitive 4th root of unity mod p.
    omega = (IntegerModRing(p).unit_gens()[0])**((p - 1) // 4)
    # this n is within a p-power root of a "local" 4th root of 1 modulo p.
    n = Mod(int(omega.crt(Mod(1, N // (p**r)))), N)
    n = n**(p**(r - 1))  # this is correct now
    t = eps(n)
    if t == K(1):
        return K(2)
    if t == K(-1):
        return K(-2)
    return K(0)
예제 #19
0
def hadamard_matrix_paleyII(n):
    """
    Implements the Paley type II construction.

    EXAMPLES::

        sage: sage.combinat.matrices.hadamard_matrix.hadamard_matrix_paleyI(12).det()
        2985984
        sage: 12^6
        2985984
    """
    N = Integer(n/2)
    p = N - 1
    if not(is_prime(p) and (p % 4 == 1)):
        raise ValueError("The order %s is not covered by the Paley type II construction." % n)
    S = matrix(ZZ, [[H2(i, j, p) for i in range(N)] for j in range(N)])
    return block_matrix([[S + 1, S - 1], [S - 1, -S - 1]])
예제 #20
0
파일: dims.py 프로젝트: Etn40ff/sage
def CO_delta(r,p,N,eps):
    r"""
    This is used as an intermediate value in computations related to
    the paper of Cohen-Oesterle.

    INPUT:


    -  ``r`` - positive integer

    -  ``p`` - a prime

    -  ``N`` - positive integer

    -  ``eps`` - character


    OUTPUT: element of the base ring of the character

    EXAMPLES::

        sage: G.<eps> = DirichletGroup(7)
        sage: sage.modular.dims.CO_delta(1,5,7,eps^3)
        2
    """
    if not is_prime(p):
        raise ValueError("p must be prime")
    K = eps.base_ring()
    if p%4 == 3:
        return K(0)
    if p==2:
        if r==1:
            return K(1)
        return K(0)
    # interesting case: p=1(mod 4).
    # omega is a primitive 4th root of unity mod p.
    omega = (IntegerModRing(p).unit_gens()[0])**((p-1)//4)
    # this n is within a p-power root of a "local" 4th root of 1 modulo p.
    n = Mod(int(omega.crt(Mod(1,N//(p**r)))),N)
    n = n**(p**(r-1))   # this is correct now
    t = eps(n)
    if t==K(1):
        return K(2)
    if t==K(-1):
        return K(-2)
    return K(0)
예제 #21
0
    def _element_constructor_(self, e):
        """
        TESTS::

            sage: P = Sets().example()
            sage: P._element_constructor_(13) == 13
            True
            sage: P._element_constructor_(13).parent()
            Integer Ring
            sage: P._element_constructor_(14)
            Traceback (most recent call last):
            ...
            AssertionError: 14 is not a prime number
        """
        p = self.element_class(e)
        assert is_prime(p), "%s is not a prime number"%(p)
        return p
예제 #22
0
def hadamard_matrix_paleyII(n):
    """
    Implements the Paley type II construction.

    EXAMPLES::
        sage: sage.combinat.matrices.hadamard_matrix.hadamard_matrix_paleyI(12).det()
        2985984
        sage: 12^6
        2985984

    """
    N = ZZ(n/2)
    if is_prime(N-1) and (N-1)%4==1:
        p = N-1
    else:
        raise ValueError, "The order %s is not covered by the Paley type II construction."%n
    S = matrix(ZZ,[[H2(i,j,p) for i in range(N)] for j in range(N)])
    return block_matrix([[S+1,S-1],[S-1,-S-1]])
예제 #23
0
파일: constructor.py 프로젝트: CETHop/sage
    def create_key_and_extra_args(self, order, name=None, modulus=None, names=None,
                                  impl=None, proof=None, **kwds):
        """
        EXAMPLES::

            sage: GF.create_key_and_extra_args(9, 'a')
            ((9, ('a',), x^2 + 2*x + 2, None, '{}', 3, 2, True), {})
            sage: GF.create_key_and_extra_args(9, 'a', foo='value')
            ((9, ('a',), x^2 + 2*x + 2, None, "{'foo': 'value'}", 3, 2, True), {'foo': 'value'})
        """
        from sage.structure.proof.all import WithProof, arithmetic
        if proof is None: proof = arithmetic()
        with WithProof('arithmetic', proof):
            order = int(order)
            if order <= 1:
                raise ValueError("the order of a finite field must be > 1.")

            if arith.is_prime(order):
                name = None
                modulus = None
                p = integer.Integer(order)
                n = integer.Integer(1)
            elif arith.is_prime_power(order):
                if not names is None: name = names
                name = normalize_names(1,name)

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

                if modulus is None or isinstance(modulus, str):
                    # A string specifies an algorithm to find a suitable modulus.
                    if modulus == "default":    # for backward compatibility
                        modulus = None
                    modulus = GF(p)['x'].irreducible_element(n, algorithm=modulus)
                elif isinstance(modulus, (list, tuple)):
                    modulus = GF(p)['x'](modulus)
                elif sage.rings.polynomial.polynomial_element.is_Polynomial(modulus):
                    modulus = modulus.change_variable_name('x')
                else:
                    raise TypeError("wrong type for modulus parameter")
            else:
                raise ValueError("the order of a finite field must be a prime power.")

            return (order, name, modulus, impl, str(kwds), p, n, proof), kwds
예제 #24
0
def eisen(p):
    """
    Return the Eisenstein number `n` which is the numerator of
    `(p-1)/12`.

    INPUT:

    -  ``p`` - a prime

    OUTPUT: Integer

    EXAMPLES::

        sage: [(p,sage.modular.dims.eisen(p)) for p in prime_range(24)]
        [(2, 1), (3, 1), (5, 1), (7, 1), (11, 5), (13, 1), (17, 4), (19, 3), (23, 11)]
    """
    if not is_prime(p):
        raise ValueError, "p must be prime"
    return frac(p-1,12).numerator()
예제 #25
0
def hadamard_matrix_paleyII(n):
    """
    Implements the Paley type II construction.

    The Paley type II case corresponds to the case `p \cong 1 \mod{4}` for a
    prime `p` (see [Hora]_).

    EXAMPLES::

        sage: sage.combinat.matrices.hadamard_matrix.hadamard_matrix_paleyII(12).det()
        2985984
        sage: 12^6
        2985984

    We note that the method returns a normalised Hadamard matrix ::

        sage: sage.combinat.matrices.hadamard_matrix.hadamard_matrix_paleyII(12)
        [ 1  1  1  1  1  1| 1  1  1  1  1  1]
        [ 1  1  1 -1 -1  1|-1 -1  1 -1 -1  1]
        [ 1  1  1  1 -1 -1|-1  1 -1  1 -1 -1]
        [ 1 -1  1  1  1 -1|-1 -1  1 -1  1 -1]
        [ 1 -1 -1  1  1  1|-1 -1 -1  1 -1  1]
        [ 1  1 -1 -1  1  1|-1  1 -1 -1  1 -1]
        [-----------------+-----------------]
        [ 1 -1 -1 -1 -1 -1|-1  1  1  1  1  1]
        [ 1 -1  1 -1 -1  1| 1 -1 -1  1  1 -1]
        [ 1  1 -1  1 -1 -1| 1 -1 -1 -1  1  1]
        [ 1 -1  1 -1  1 -1| 1  1 -1 -1 -1  1]
        [ 1 -1 -1  1 -1  1| 1  1  1 -1 -1 -1]
        [ 1  1 -1 -1  1 -1| 1 -1  1  1 -1 -1]
    """
    N = Integer(n / 2)
    p = N - 1
    if not (is_prime(p) and (p % 4 == 1)):
        raise ValueError(
            "The order %s is not covered by the Paley type II construction." %
            n)
    S = matrix(ZZ, [[H2(i, j, p) for i in range(N)] for j in range(N)])
    H = block_matrix([[S + 1, S - 1], [1 - S, S + 1]])
    # normalising H so that first row and column have only +1 entries.
    return normalise_hadamard(H)
예제 #26
0
def hadamard_matrix_paleyII(n):
    """
    Implements the Paley type II construction.

    The Paley type II case corresponds to the case `p \cong 1 \mod{4}` for a
    prime `p` (see [Hora]_).

    EXAMPLES::

        sage: sage.combinat.matrices.hadamard_matrix.hadamard_matrix_paleyII(12).det()
        2985984
        sage: 12^6
        2985984

    We note that the method returns a normalised Hadamard matrix ::

        sage: sage.combinat.matrices.hadamard_matrix.hadamard_matrix_paleyII(12)
        [ 1  1  1  1  1  1| 1  1  1  1  1  1]
        [ 1  1  1 -1 -1  1|-1 -1  1 -1 -1  1]
        [ 1  1  1  1 -1 -1|-1  1 -1  1 -1 -1]
        [ 1 -1  1  1  1 -1|-1 -1  1 -1  1 -1]
        [ 1 -1 -1  1  1  1|-1 -1 -1  1 -1  1]
        [ 1  1 -1 -1  1  1|-1  1 -1 -1  1 -1]
        [-----------------+-----------------]
        [ 1 -1 -1 -1 -1 -1|-1  1  1  1  1  1]
        [ 1 -1  1 -1 -1  1| 1 -1 -1  1  1 -1]
        [ 1  1 -1  1 -1 -1| 1 -1 -1 -1  1  1]
        [ 1 -1  1 -1  1 -1| 1  1 -1 -1 -1  1]
        [ 1 -1 -1  1 -1  1| 1  1  1 -1 -1 -1]
        [ 1  1 -1 -1  1 -1| 1 -1  1  1 -1 -1]
    """
    N = Integer(n/2)
    p = N - 1
    if not(is_prime(p) and (p % 4 == 1)):
        raise ValueError("The order %s is not covered by the Paley type II construction." % n)
    S = matrix(ZZ, [[H2(i, j, p) for i in range(N)] for j in range(N)])
    H = block_matrix([[S + 1, S - 1], [1 - S, S + 1]])
    # normalising H so that first row and column have only +1 entries.
    return normalise_hadamard(H)
예제 #27
0
def is_blum_prime(n):
    r"""
    Determine whether or not ``n`` is a Blum prime.

    INPUT:

    - ``n`` a positive prime.

    OUTPUT:

    - ``True`` if ``n`` is a Blum prime; ``False`` otherwise.

    Let `n` be a positive prime. Then `n` is a Blum prime if `n` is
    congruent to 3 modulo 4, i.e. `n \equiv 3 \pmod{4}`.

    EXAMPLES:

    Testing some integers to see if they are Blum primes::

        sage: from sage.crypto.util import is_blum_prime
        sage: from sage.crypto.util import random_blum_prime
        sage: is_blum_prime(101)
        False
        sage: is_blum_prime(7)
        True
        sage: p = random_blum_prime(10**3, 10**5)
        sage: is_blum_prime(p)
        True
    """
    if n < 0:
        return False
    if is_prime(n):
        if mod(n, 4).lift() == 3:
            return True
        else:
            return False
    else:
        return False
예제 #28
0
def hadamard_matrix_paleyI(n):
    """
    Implements the Paley type I construction.

    The Paley type I case corresponds to the case `p \cong 3 \mod{4}` for a
    prime `p` (see [Hora]_).

    EXAMPLES:

    We note that this method returns a normalised Hadamard matrix ::

        sage: sage.combinat.matrices.hadamard_matrix.hadamard_matrix_paleyI(4)
        [ 1  1  1  1]
        [ 1 -1 -1  1]
        [ 1  1 -1 -1]
        [ 1 -1  1 -1]
    """
    p = n - 1
    if not(is_prime(p) and (p % 4 == 3)):
        raise ValueError("The order %s is not covered by the Paley type I construction." % n)
    H = matrix(ZZ, [[H1(i, j, p) for i in range(n)] for j in range(n)])
    # normalising H so that first row and column have only +1 entries.
    return normalise_hadamard(H)
예제 #29
0
    def green_function(self, G, v, **kwds):
        r"""
        Evaluates the local Green's function with respect to the morphism ``G``
        at the place ``v`` for ``self`` with ``N`` terms of the
        series or to within a given error bound.  Must be over a number field
        or order of a number field. Note that this is the absolute local Green's function
        so is scaled by the degree of the base field.

        Use ``v=0`` for the archimedean place over `\QQ` or field embedding. Non-archimedean
        places are prime ideals for number fields or primes over `\QQ`.

        ALGORITHM:

        See Exercise 5.29 and Figure 5.6 of ``The Arithmetic of Dynamics Systems``, Joseph H. Silverman, Springer, GTM 241, 2007.

        INPUT:

        - ``G`` - a projective morphism whose local Green's function we are computing

        - ``v`` - non-negative integer. a place, use v=0 for the archimedean place

        kwds:

        - ``N`` - positive integer. number of terms of the series to use, default: 10

        - ``prec`` - positive integer, float point or p-adic precision, default: 100

        - ``error_bound`` - a positive real number

        OUTPUT:

        - a real number

        EXAMPLES::

            sage: P.<x,y>=ProjectiveSpace(QQ,1)
            sage: H=Hom(P,P)
            sage: f=H([x^2+y^2,x*y]);
            sage: Q=P(5,1)
            sage: f.green_function(Q,0,N=30)
            1.6460930159932946233759277576

        ::

            sage: P.<x,y>=ProjectiveSpace(QQ,1)
            sage: H=Hom(P,P)
            sage: f=H([x^2+y^2,x*y]);
            sage: Q=P(5,1)
            sage: Q.green_function(f,0,N=200,prec=200)
            1.6460930160038721802875250367738355497198064992657997569827

        ::

            sage: K.<w> = QuadraticField(3)
            sage: P.<x,y> = ProjectiveSpace(K,1)
            sage: H = Hom(P,P)
            sage: f = H([17*x^2+1/7*y^2,17*w*x*y])
            sage: f.green_function(P.point([w,2],False), K.places()[1])
            1.7236334013785676107373093775
            sage: print f.green_function(P([2,1]), K.ideal(7), N=7)
            0.48647753726382832627633818586
            sage: print f.green_function(P([w,1]), K.ideal(17), error_bound=0.001)
            -0.70761163353747779889947530309

        .. TODO:: Implement general p-adic extensions so that the flip trick can be used
             for number fields.
        """
        N = kwds.get('N', 10)                     #Get number of iterates (if entered)
        err = kwds.get('error_bound', None)         #Get error bound (if entered)
        prec = kwds.get('prec', 100)                #Get precision (if entered)
        R = RealField(prec)
        localht = R(0)
        BR = FractionField(self.codomain().base_ring())
        GBR = G.change_ring(BR) #so the heights work

        if not BR in NumberFields():
            raise NotImplementedError("Must be over a NumberField or a NumberField Order")

        #For QQ the 'flip-trick' works better over RR or Qp
        if isinstance(v, (NumberFieldFractionalIdeal, RingHomomorphism_im_gens)):
            K = BR
        elif is_prime(v):
            K = Qp(v, prec)
        elif v == 0:
            K = R
            v = BR.places(prec=prec)[0]
        else:
            raise ValueError("Invalid valuation (=%s) entered."%v)

        #Coerce all polynomials in F into polynomials with coefficients in K
        F = G.change_ring(K, False)
        d = F.degree()
        dim = F.codomain().ambient_space().dimension_relative()
        P = self.change_ring(K, False)

        if err is not None:
            err = R(err)
            if not err>0:
                raise ValueError("Error bound (=%s) must be positive."%err)
            if G.is_endomorphism() == False:
                raise NotImplementedError("Error bounds only for endomorphisms")

            #if doing error estimates, compute needed number of iterates
            D = (dim + 1) * (d - 1) + 1
            #compute upper bound
            if isinstance(v, RingHomomorphism_im_gens): #archimedean
                vindex = BR.places(prec=prec).index(v)
                U = GBR.local_height_arch(vindex, prec=prec) + R(binomial(dim + d, d)).log()
            else: #non-archimedean
                U = GBR.local_height(v, prec=prec)

            #compute lower bound - from explicit polynomials of Nullstellensatz
            CR = GBR.codomain().ambient_space().coordinate_ring() #.lift() only works over fields
            I = CR.ideal(GBR.defining_polynomials())
            maxh = 0
            for k in range(dim + 1):
                CoeffPolys = (CR.gen(k) ** D).lift(I)
                Res = 1
                h = 1
                for poly in CoeffPolys:
                    if poly != 0:
                        for c in poly.coefficients():
                            Res = lcm(Res, c.denominator())
                for poly in CoeffPolys:
                    if poly != 0:
                        if isinstance(v, RingHomomorphism_im_gens): #archimedean
                            if BR == QQ:
                                h = max([(Res*c).local_height_arch(prec=prec) for c in poly.coefficients()])
                            else:
                                h = max([(Res*c).local_height_arch(vindex, prec=prec) for c in poly.coefficients()])
                        else: #non-archimedean
                            h = max([c.local_height(v, prec=prec) for c in poly.coefficients()])
                        if h > maxh:
                            maxh=h
            if isinstance(v, RingHomomorphism_im_gens): #archimedean
                L = R(Res / ((dim + 1) * binomial(dim + D - d, D - d) * maxh)).log().abs()
            else: #non-archimedean
                L = R(1 / maxh).log().abs()
            C = max([U, L])
            if C != 0:
                N = R(C/(err)).log(d).abs().ceil()
            else: #we just need log||P||_v
                N=1

        #START GREEN FUNCTION CALCULATION
        if isinstance(v, RingHomomorphism_im_gens):  #embedding for archimedean local height
            for i in range(N+1):
                Pv = [ (v(t).abs()) for t in P ]
                m = -1
                #compute the maximum absolute value of entries of a, and where it occurs
                for n in range(dim + 1):
                    if Pv[n] > m:
                        j = n
                        m = Pv[n]
                # add to sum for the Green's function
                localht += ((1/R(d))**R(i)) * (R(m).log())
                #get the next iterate
                if i < N:
                    P.scale_by(1/P[j])
                    P = F(P, False)
            return (1/BR.absolute_degree()) * localht

        #else - prime or prime ideal for non-archimedean
        for i in range(N + 1):
            if BR == QQ:
                Pv = [ R(K(t).abs()) for t in P ]
            else:
                Pv = [ R(t.abs_non_arch(v)) for t in P ]
            m = -1
            #compute the maximum absolute value of entries of a, and where it occurs
            for n in range(dim + 1):
                if Pv[n] > m:
                    j = n
                    m = Pv[n]
            # add to sum for the Green's function
            localht += ((1/R(d))**R(i)) * (R(m).log())
            #get the next iterate
            if i < N:
                P.scale_by(1/P[j])
                P = F(P, False)
        return (1/BR.absolute_degree()) * localht
    def pthpowers(self, p, Bound):
        """
        Find the indices of proveably all pth powers in the recurrence sequence bounded by Bound.

        Let `u_n` be a binary recurrence sequence.  A ``p`` th power in `u_n` is a solution
        to `u_n = y^p` for some integer `y`.  There are only finitely many ``p`` th powers in
        any recurrence sequence [SS].

        INPUT:

        - ``p`` - a rational prime integer (the fixed p in `u_n = y^p`)

        - ``Bound`` - a natural number (the maximum index `n` in `u_n = y^p` that is checked).

        OUTPUT:

        - A list of the indices of all ``p`` th powers less bounded by ``Bound``.  If the sequence is degenerate and there are many ``p`` th powers, raises ``ValueError``.

        EXAMPLES::

            sage: R = BinaryRecurrenceSequence(1,1)        #the Fibonacci sequence
            sage: R.pthpowers(2, 10**30)        # long time (7 seconds) -- in fact these are all squares, c.f. [BMS06]
            [0, 1, 2, 12]

            sage: S = BinaryRecurrenceSequence(8,1) #a Lucas sequence
            sage: S.pthpowers(3,10**30)    # long time (3 seconds) -- provably finds the indices of all 3rd powers less than 10^30
            [0, 1, 2]

            sage: Q = BinaryRecurrenceSequence(3,3,2,1)
            sage: Q.pthpowers(11,10**30)          # long time (7.5 seconds)
            [1]

        If the sequence is degenerate, and there are are no ``p`` th powers, returns `[]`.  Otherwise, if
        there are many ``p`` th powers, raises ``ValueError``.

        ::

            sage: T = BinaryRecurrenceSequence(2,0,1,2)
            sage: T.is_degenerate()
            True
            sage: T.is_geometric()
            True
            sage: T.pthpowers(7,10**30)
            Traceback (most recent call last):
            ...
            ValueError: The degenerate binary recurrence sequence is geometric or quasigeometric and has many pth powers.

            sage: L = BinaryRecurrenceSequence(4,0,2,2)
            sage: [L(i).factor() for i in xrange(10)]
            [2, 2, 2^3, 2^5, 2^7, 2^9, 2^11, 2^13, 2^15, 2^17]
            sage: L.is_quasigeometric()
            True
            sage: L.pthpowers(2,10**30)
            []

        NOTE: This function is primarily optimized in the range where ``Bound`` is much larger than ``p``.

        """

        #Thanks to Jesse Silliman for helpful conversations!

        #Reset the dictionary of good primes, as this depends on p
        self._PGoodness = {}
        #Starting lower bound on good primes
        self._ell = 1

        #If the sequence is geometric, then the `n`th term is `a*r^n`.  Thus the
        #property of being a ``p`` th power is periodic mod ``p``.  So there are either
        #no ``p`` th powers if there are none in the first ``p`` terms, or many if there
        #is at least one in the first ``p`` terms.

        if self.is_geometric() or self.is_quasigeometric():
            no_powers = True
            for i in xrange(1, 6 * p + 1):
                if _is_p_power(self(i), p):
                    no_powers = False
                    break
            if no_powers:
                if _is_p_power(self.u0, p):
                    return [0]
                return []
            else:
                raise ValueError(
                    "The degenerate binary recurrence sequence is geometric or quasigeometric and has many pth powers."
                )

        #If the sequence is degenerate without being geometric or quasigeometric, there
        #may be many ``p`` th powers or no ``p`` th powers.

        elif (self.b**2 + 4 * self.c) == 0:

            #This is the case if the matrix F is not diagonalizable, ie b^2 +4c = 0, and alpha/beta = 1.

            alpha = self.b / 2

            #In this case, u_n = u_0*alpha^n + (u_1 - u_0*alpha)*n*alpha^(n-1) = alpha^(n-1)*(u_0 +n*(u_1 - u_0*alpha)),
            #that is, it is a geometric term (alpha^(n-1)) times an arithmetic term (u_0 + n*(u_1-u_0*alpha)).

            #Look at classes n = k mod p, for k = 1,...,p.

            for k in xrange(1, p + 1):

                #The linear equation alpha^(k-1)*u_0 + (k+pm)*(alpha^(k-1)*u1 - u0*alpha^k)
                #must thus be a pth power.  This is a linear equation in m, namely, A + B*m, where

                A = (alpha**(k - 1) * self.u0 + k *
                     (alpha**(k - 1) * self.u1 - self.u0 * alpha**k))
                B = p * (alpha**(k - 1) * self.u1 - self.u0 * alpha**k)

                #This linear equation represents a pth power iff A is a pth power mod B.

                if _is_p_power_mod(A, p, B):
                    raise ValueError(
                        "The degenerate binary recurrence sequence has many pth powers."
                    )
            return []

        #We find ``p`` th powers using an elementary sieve.  Term `u_n` is a ``p`` th
        #power if and only if it is a ``p`` th power modulo every prime `\\ell`.  This condition
        #gives nontrivial information if ``p`` divides the order of the multiplicative group of
        #`\\Bold(F)_{\\ell}`, i.e. if `\\ell` is ` 1 \mod{p}`, as then only `1/p` terms are ``p`` th
        #powers modulo `\\ell``.

        #Thus, given such an `\\ell`, we get a set of necessary congruences for the index modulo the
        #the period of the sequence mod `\\ell`.  Then we intersect these congruences for many primes
        #to get a tight list modulo a growing modulus.  In order to keep this step manageable, we
        #only use primes `\\ell` that are have particularly smooth periods.

        #Some congruences in the list will remain as the modulus grows.  If a congruence remains through
        #7 rounds of increasing the modulus, then we check if this corresponds to a perfect power (if
        #it does, we add it to our list of indices corresponding to ``p`` th powers).  The rest of the congruences
        #are transient and grow with the modulus.  Once the smallest of these is greater than the bound,
        #the list of known indices corresponding to ``p`` th powers is complete.

        else:

            if Bound < 3 * p:

                powers = []
                ell = p + 1

                while not is_prime(ell):
                    ell = ell + p

                F = GF(ell)
                a0 = F(self.u0)
                a1 = F(self.u1)  #a0 and a1 are variables for terms in sequence
                bf, cf = F(self.b), F(self.c)

                for n in xrange(Bound):  # n is the index of the a0

                    #Check whether a0 is a perfect power mod ell
                    if _is_p_power_mod(a0, p, ell):
                        #if a0 is a perfect power mod ell, check if nth term is ppower
                        if _is_p_power(self(n), p):
                            powers.append(n)

                    a0, a1 = a1, bf * a1 + cf * a0  #step up the variables

            else:

                powers = [
                ]  #documents the indices of the sequence that provably correspond to pth powers
                cong = [
                    0
                ]  #list of necessary congruences on the index for it to correspond to pth powers
                Possible_count = {
                }  #keeps track of the number of rounds a congruence lasts in cong

                #These parameters are involved in how we choose primes to increase the modulus
                qqold = 1  #we believe that we know complete information coming from primes good by qqold
                M1 = 1  #we have congruences modulo M1, this may not be the tightest list
                M2 = p  #we want to move to have congruences mod M2
                qq = 1  #the largest prime power divisor of M1 is qq

                #This loop ups the modulus.
                while True:

                    #Try to get good data mod M2

                    #patience of how long we should search for a "good prime"
                    patience = 0.01 * _estimated_time(
                        lcm(M2, p * next_prime_power(qq)), M1, len(cong), p)
                    tries = 0

                    #This loop uses primes to get a small set of congruences mod M2.
                    while True:

                        #only proceed if took less than patience time to find the next good prime
                        ell = _next_good_prime(p, self, qq, patience, qqold)
                        if ell:

                            #gather congruence data for the sequence mod ell, which will be mod period(ell) = modu
                            cong1, modu = _find_cong1(p, self, ell)

                            CongNew = [
                            ]  #makes a new list from cong that is now mod M = lcm(M1, modu) instead of M1
                            M = lcm(M1, modu)
                            for k in xrange(M / M1):
                                for i in cong:
                                    CongNew.append(k * M1 + i)
                            cong = set(CongNew)

                            M1 = M

                            killed_something = False  #keeps track of when cong1 can rule out a congruence in cong

                            #CRT by hand to gain speed
                            for i in list(cong):
                                if not (
                                        i % modu in cong1
                                ):  #congruence in cong is inconsistent with any in cong1
                                    cong.remove(i)  #remove that congruence
                                    killed_something = True

                            if M1 == M2:
                                if not killed_something:
                                    tries += 1
                                    if tries == 2:  #try twice to rule out congruences
                                        cong = list(cong)
                                        qqold = qq
                                        qq = next_prime_power(qq)
                                        M2 = lcm(M2, p * qq)
                                        break

                        else:
                            qq = next_prime_power(qq)
                            M2 = lcm(M2, p * qq)
                            cong = list(cong)
                            break

                    #Document how long each element of cong has been there
                    for i in cong:
                        if i in Possible_count:
                            Possible_count[i] = Possible_count[i] + 1
                        else:
                            Possible_count[i] = 1

                    #Check how long each element has persisted, if it is for at least 7 cycles,
                    #then we check to see if it is actually a perfect power
                    for i in Possible_count:
                        if Possible_count[i] == 7:
                            n = Integer(i)
                            if n < Bound:
                                if _is_p_power(self(n), p):
                                    powers.append(n)

                    #check for a contradiction
                    if len(cong) > len(powers):
                        if cong[len(powers)] > Bound:
                            break
                    elif M1 > Bound:
                        break

            return powers
예제 #31
0
def local_genus_symbol(self, p):
    """
    Returns the Conway-Sloane genus symbol of 2 times a quadratic form
    defined over ZZ at a prime number p.  This is defined (in the
    Genus_Symbol_p_adic_ring() class in the quadratic_forms/genera
    subfolder) to be a list of tuples (one for each Jordan component
    p^m*A at p, where A is a unimodular symmetric matrix with
    coefficients the p-adic integers) of the following form:

        1. If p>2 then return triples of the form [`m`, `n`, `d`] where
            `m` = valuation of the component

            `n` = rank of A

            `d` = det(A) in {1,u} for normalized quadratic non-residue u.

        2. If p=2 then return quintuples of the form [`m`,`n`,`s`, `d`, `o`] where
            `m` = valuation of the component

            `n` = rank of A

            `d` = det(A) in {1,3,5,7}

            `s` = 0 (or 1) if A is even (or odd)

            `o` = oddity of A (= 0 if s = 0) in Z/8Z
              = the trace of the diagonalization of A

    NOTE: The Conway-Sloane convention for describing the prime 'p =
    -1' is not supported here, and neither is the convention for
    including the 'prime' Infinity.  See note on p370 of Conway-Sloane
    (3rd ed) for a discussion of this convention.

    INPUT:

        -`p` -- a prime number > 0

    OUTPUT:
        Returns a Conway-Sloane genus symbol at p, which is an
        instance of the Genus_Symbol_p_adic_ring class.

    EXAMPLES::

        sage: Q = DiagonalQuadraticForm(ZZ, [1,2,3,4])
        sage: Q.local_genus_symbol(2)
        Genus symbol at 2 : [[1, 2, 3, 1, 4], [2, 1, 1, 1, 1], [3, 1, 1, 1, 1]]
        sage: Q.local_genus_symbol(3)
        Genus symbol at 3 : [[0, 3, 1], [1, 1, -1]]
        sage: Q.local_genus_symbol(5)
        Genus symbol at 5 : [[0, 4, 1]]

    """
    ## Check that p is prime and that the form is defined over ZZ.
    if not is_prime(p):
        raise TypeError, "Oops!  The number " + str(p) + " isn't prime."
    if not self.base_ring() == IntegerRing():
        raise TypeError, "Oops!  The quadratic form is not defined over the integers."

    ## Return the result
    try:
        M = self.Hessian_matrix()
        return LocalGenusSymbol(M, p)
    except StandardError:
        raise TypeError, "Oops!  There is a problem computing the local genus symbol at the prime " + str(p) + " for this form."
예제 #32
0
    def create_key_and_extra_args(self,
                                  order,
                                  name=None,
                                  modulus=None,
                                  names=None,
                                  impl=None,
                                  proof=None,
                                  **kwds):
        """
        EXAMPLES::

            sage: GF.create_key_and_extra_args(9, 'a')
            ((9, ('a',), x^2 + 2*x + 2, None, '{}', 3, 2, True), {})
            sage: GF.create_key_and_extra_args(9, 'a', foo='value')
            ((9, ('a',), x^2 + 2*x + 2, None, "{'foo': 'value'}", 3, 2, True), {'foo': 'value'})
        """
        from sage.structure.proof.all import WithProof, arithmetic
        if proof is None: proof = arithmetic()
        with WithProof('arithmetic', proof):
            order = int(order)
            if order <= 1:
                raise ValueError("the order of a finite field must be > 1.")

            if arith.is_prime(order):
                name = None
                modulus = None
                p = integer.Integer(order)
                n = integer.Integer(1)
            elif arith.is_prime_power(order):
                if not names is None: name = names
                name = normalize_names(1, name)

                p, n = arith.factor(order)[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 (kwds.has_key('conway') and kwds['conway']):
                        raise ValueError(
                            "parameter 'conway' is required if no name given")
                    if not kwds.has_key('prefix'):
                        raise ValueError(
                            "parameter 'prefix' is required if no name given")
                    name = kwds['prefix'] + str(n)

                if kwds.has_key('conway') and kwds['conway']:
                    from conway_polynomials import conway_polynomial
                    if not kwds.has_key('prefix'):
                        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)

                if modulus is None or isinstance(modulus, str):
                    # A string specifies an algorithm to find a suitable modulus.
                    if modulus == "default":  # for backward compatibility
                        modulus = None
                    modulus = GF(p)['x'].irreducible_element(n,
                                                             algorithm=modulus)
                elif isinstance(modulus, (list, tuple)):
                    modulus = GF(p)['x'](modulus)
                elif sage.rings.polynomial.polynomial_element.is_Polynomial(
                        modulus):
                    modulus = modulus.change_variable_name('x')
                else:
                    raise TypeError("wrong type for modulus parameter")
            else:
                raise ValueError(
                    "the order of a finite field must be a prime power.")

            return (order, name, modulus, impl, str(kwds), p, n, proof), kwds
def has_equivalent_Jordan_decomposition_at_prime(self, other, p):
    """
    Determines if the given quadratic form has a Jordan decomposition
    equivalent to that of self.
    
    INPUT:
        a QuadraticForm

    OUTPUT:
        boolean
    
    EXAMPLES::

        sage: Q1 = QuadraticForm(ZZ, 3, [1, 0, -1, 1, 0, 3])
        sage: Q2 = QuadraticForm(ZZ, 3, [1, 0, 0, 2, -2, 6])
        sage: Q3 = QuadraticForm(ZZ, 3, [1, 0, 0, 1, 0, 11])
        sage: [Q1.level(), Q2.level(), Q3.level()]
        [44, 44, 44]
        sage: Q1.has_equivalent_Jordan_decomposition_at_prime(Q2,2)
        False
        sage: Q1.has_equivalent_Jordan_decomposition_at_prime(Q2,11)
        False
        sage: Q1.has_equivalent_Jordan_decomposition_at_prime(Q3,2)
        False
        sage: Q1.has_equivalent_Jordan_decomposition_at_prime(Q3,11)
        True 
        sage: Q2.has_equivalent_Jordan_decomposition_at_prime(Q3,2)
        True 
        sage: Q2.has_equivalent_Jordan_decomposition_at_prime(Q3,11)
        False
    
    """
    ## Sanity Checks
    #if not isinstance(other, QuadraticForm):
    if type(other) != type(self):
        raise TypeError, "Oops!  The first argument must be of type QuadraticForm."
    if not is_prime(p):
        raise TypeError, "Oops!  The second argument must be a prime number."

    ## Get the relevant local normal forms quickly
    self_jordan = self.jordan_blocks_by_scale_and_unimodular(p, safe_flag= False)
    other_jordan = other.jordan_blocks_by_scale_and_unimodular(p, safe_flag=False)    

    ## DIAGNOSTIC
    #print "self_jordan = ", self_jordan
    #print "other_jordan = ", other_jordan


    ## Check for the same number of Jordan components
    if len(self_jordan) != len(other_jordan):
        return False


    ## Deal with odd primes:  Check that the Jordan component scales, dimensions, and discriminants are the same
    if p != 2:
        for i in range(len(self_jordan)):
            if (self_jordan[i][0] != other_jordan[i][0]) \
               or (self_jordan[i][1].dim() != other_jordan[i][1].dim()) \
               or (legendre_symbol(self_jordan[i][1].det() * other_jordan[i][1].det(), p) != 1):
                return False

        ## All tests passed for an odd prime.
        return True


    ## For p = 2:  Check that all Jordan Invariants are the same.
    elif p == 2:

        ## Useful definition
        t = len(self_jordan)          ## Define t = Number of Jordan components


        ## Check that all Jordan Invariants are the same (scale, dim, and norm)
        for i in range(t):
            if (self_jordan[i][0] != other_jordan[i][0]) \
               or (self_jordan[i][1].dim() != other_jordan[i][1].dim()) \
               or (valuation(GCD(self_jordan[i][1].coefficients()), p) != valuation(GCD(other_jordan[i][1].coefficients()), p)):
                return False

        ## DIAGNOSTIC
        #print "Passed the Jordan invariant test."


        ## Use O'Meara's isometry test 93:29 on p277.
        ## ------------------------------------------

        ## List of norms, scales, and dimensions for each i
        scale_list = [ZZ(2)**self_jordan[i][0]  for i in range(t)]
        norm_list = [ZZ(2)**(self_jordan[i][0] + valuation(GCD(self_jordan[i][1].coefficients()), 2))  for i in range(t)]
        dim_list = [(self_jordan[i][1].dim())  for i in range(t)]

        ## List of Hessian determinants and Hasse invariants for each Jordan (sub)chain
        ## (Note: This is not the same as O'Meara's Gram determinants, but ratios are the same!)  -- NOT SO GOOD...
        ## But it matters in condition (ii), so we multiply all by 2 (instead of dividing by 2 since only square-factors matter, and it's easier.)
        j = 0
        self_chain_det_list = [ self_jordan[j][1].Gram_det() * (scale_list[j]**dim_list[j])]
        other_chain_det_list = [ other_jordan[j][1].Gram_det() * (scale_list[j]**dim_list[j])]
        self_hasse_chain_list = [ self_jordan[j][1].scale_by_factor(ZZ(2)**self_jordan[j][0]).hasse_invariant__OMeara(2) ]
        other_hasse_chain_list = [ other_jordan[j][1].scale_by_factor(ZZ(2)**other_jordan[j][0]).hasse_invariant__OMeara(2) ]
                   
        for j in range(1, t):
            self_chain_det_list.append(self_chain_det_list[j-1] * self_jordan[j][1].Gram_det() * (scale_list[j]**dim_list[j]))
            other_chain_det_list.append(other_chain_det_list[j-1] * other_jordan[j][1].Gram_det() * (scale_list[j]**dim_list[j]))
            self_hasse_chain_list.append(self_hasse_chain_list[j-1] \
                                         * hilbert_symbol(self_chain_det_list[j-1], self_jordan[j][1].Gram_det(), 2) \
                                         * self_jordan[j][1].hasse_invariant__OMeara(2))
            other_hasse_chain_list.append(other_hasse_chain_list[j-1] \
                                          * hilbert_symbol(other_chain_det_list[j-1], other_jordan[j][1].Gram_det(), 2) \
                                          * other_jordan[j][1].hasse_invariant__OMeara(2))


        ## SANITY CHECK -- check that the scale powers are strictly increasing        
        for i in range(1, len(scale_list)):
            if scale_list[i-1] >= scale_list[i]:
                   raise RuntimeError, "Oops!  There is something wrong with the Jordan Decomposition -- the given scales are not strictly increasing!"


        ## DIAGNOSTIC
        #print "scale_list = ", scale_list
        #print "norm_list = ", norm_list
        #print "dim_list = ", dim_list
        #print
        #print "self_chain_det_list = ", self_chain_det_list
        #print "other_chain_det_list = ", other_chain_det_list
        #print "self_hasse_chain_list = ", self_hasse_chain_list
        #print "other_hasse_chain_det_list = ", other_hasse_chain_list

        
        ## Test O'Meara's two conditions
        for i in range(t-1):

            ## Condition (i): Check that their (unit) ratio is a square (but it suffices to check at most mod 8).
            modulus = norm_list[i] * norm_list[i+1] / (scale_list[i] ** 2)
            if modulus > 8:
                   modulus = 8 
            if (modulus > 1) and (((self_chain_det_list[i] / other_chain_det_list[i]) % modulus) != 1):
                #print "Failed when i =", i, " in condition 1."
                return False
            
            ## Check O'Meara's condition (ii) when appropriate
            if norm_list[i+1] % (4 * norm_list[i]) == 0:
                if self_hasse_chain_list[i] * hilbert_symbol(norm_list[i] * other_chain_det_list[i], -self_chain_det_list[i], 2) \
                       != other_hasse_chain_list[i] * hilbert_symbol(norm_list[i], -other_chain_det_list[i], 2):      ## Nipp conditions
                    #print "Failed when i =", i, " in condition 2."
                    return False


        ## All tests passed for the prime 2.
        return True
            
    else:
        raise TypeError, "Oops!  This should not have happened."
예제 #34
0
def local_genus_symbol(self, p):
    """
    Returns the Conway-Sloane genus symbol of 2 times a quadratic form
    defined over ZZ at a prime number p.  This is defined (in the
    Genus_Symbol_p_adic_ring() class in the quadratic_forms/genera
    subfolder) to be a list of tuples (one for each Jordan component
    p^m*A at p, where A is a unimodular symmetric matrix with
    coefficients the p-adic integers) of the following form:

        1. If p>2 then return triples of the form [`m`, `n`, `d`] where
            `m` = valuation of the component

            `n` = rank of A

            `d` = det(A) in {1,u} for normalized quadratic non-residue u.

        2. If p=2 then return quintuples of the form [`m`,`n`,`s`, `d`, `o`] where
            `m` = valuation of the component

            `n` = rank of A

            `d` = det(A) in {1,3,5,7}

            `s` = 0 (or 1) if A is even (or odd)

            `o` = oddity of A (= 0 if s = 0) in Z/8Z
              = the trace of the diagonalization of A

    NOTE: The Conway-Sloane convention for describing the prime 'p =
    -1' is not supported here, and neither is the convention for
    including the 'prime' Infinity.  See note on p370 of Conway-Sloane
    (3rd ed) for a discussion of this convention.

    INPUT:

        -`p` -- a prime number > 0

    OUTPUT:
        Returns a Conway-Sloane genus symbol at p, which is an
        instance of the Genus_Symbol_p_adic_ring class.

    EXAMPLES::

        sage: Q = DiagonalQuadraticForm(ZZ, [1,2,3,4])
        sage: Q.local_genus_symbol(2)
        Genus symbol at 2 : [[1, 2, 3, 1, 4], [2, 1, 1, 1, 1], [3, 1, 1, 1, 1]]
        sage: Q.local_genus_symbol(3)
        Genus symbol at 3 : [[0, 3, 1], [1, 1, -1]]
        sage: Q.local_genus_symbol(5)
        Genus symbol at 5 : [[0, 4, 1]]

    """
    ## Check that p is prime and that the form is defined over ZZ.
    if not is_prime(p):
        raise TypeError, "Oops!  The number " + str(p) + " isn't prime."
    if not self.base_ring() == IntegerRing():
        raise TypeError, "Oops!  The quadratic form is not defined over the integers."

    ## Return the result
    try:
        M = self.Hessian_matrix()
        return LocalGenusSymbol(M, p)
    except Exception:
        raise TypeError, "Oops!  There is a problem computing the local genus symbol at the prime " + str(
            p) + " for this form."
def local_normal_form(self, p):
    """
    Returns the a locally integrally equivalent quadratic form over
    the p-adic integers Z_p which gives the Jordan decomposition.  The
    Jordan components are written as sums of blocks of size <= 2 and
    are arranged by increasing scale, and then by increasing norm.
    (This is equivalent to saying that we put the 1x1 blocks before
    the 2x2 blocks in each Jordan component.)

    INPUT:

        `p` -- a positive prime number.

    OUTPUT:

        a quadratic form over ZZ

    WARNING:  Currently this only works for quadratic forms defined over ZZ.

    EXAMPLES::

        sage: Q = QuadraticForm(ZZ, 2, [10,4,1])
        sage: Q.local_normal_form(5)
        Quadratic form in 2 variables over Integer Ring with coefficients:
        [ 1 0 ]
        [ * 6 ]

    ::

        sage: Q.local_normal_form(3)
        Quadratic form in 2 variables over Integer Ring with coefficients:
        [ 10 0 ]
        [ * 15 ]

        sage: Q.local_normal_form(2)
        Quadratic form in 2 variables over Integer Ring with coefficients:
        [ 1 0 ]
        [ * 6 ]

    """
    ## Sanity Checks
    if (self.base_ring() != IntegerRing()):
        raise NotImplementedError(
            "Oops!  This currently only works for quadratic forms defined over IntegerRing(). =("
        )
    if not ((p >= 2) and is_prime(p)):
        raise TypeError("Oops!  p is not a positive prime number. =(")

    ## Some useful local variables
    Q = copy.deepcopy(self)
    Q.__init__(self.base_ring(), self.dim(), self.coefficients())

    ## Prepare the final form to return
    Q_Jordan = copy.deepcopy(self)
    Q_Jordan.__init__(self.base_ring(), 0)

    while Q.dim() > 0:
        n = Q.dim()

        ## Step 1: Find the minimally p-divisible matrix entry, preferring diagonals
        ## -------------------------------------------------------------------------
        (min_i, min_j) = Q.find_entry_with_minimal_scale_at_prime(p)
        if min_i == min_j:
            min_val = valuation(2 * Q[min_i, min_j], p)
        else:
            min_val = valuation(Q[min_i, min_j], p)

        ## Error if we still haven't seen non-zero coefficients!
        if (min_val == Infinity):
            raise RuntimeError("Oops!  The original matrix is degenerate. =(")

        ## Step 2: Arrange for the upper leftmost entry to have minimal valuation
        ## ----------------------------------------------------------------------
        if (min_i == min_j):
            block_size = 1
            Q.swap_variables(0, min_i, in_place=True)
        else:
            ## Work in the upper-left 2x2 block, and replace it by its 2-adic equivalent form
            Q.swap_variables(0, min_i, in_place=True)
            Q.swap_variables(1, min_j, in_place=True)

            ## 1x1 => make upper left the smallest
            if (p != 2):
                block_size = 1
                Q.add_symmetric(1, 0, 1, in_place=True)
            ## 2x2 => replace it with the appropriate 2x2 matrix
            else:
                block_size = 2

        ## DIAGNOSTIC
        #print "\n Finished Step 2 \n";
        #print "\n Q is: \n" + str(Q)  + "\n";
        #print "  p is: " + str(p)
        #print "  min_val is: " + str( min_val)
        #print "  block_size is: " + str(block_size)
        #print "\n Starting Step 3 \n"

        ## Step 3: Clear out the remaining entries
        ##  ---------------------------------------
        min_scale = p**min_val  ## This is the minimal valuation of the Hessian matrix entries.

        ##DIAGNOSTIC
        #print "Starting Step 3:"
        #print "----------------"
        #print "  min_scale is: " + str(min_scale)

        ## Perform cancellation over Z by ensuring divisibility
        if (block_size == 1):
            a = 2 * Q[0, 0]
            for j in range(block_size, n):
                b = Q[0, j]
                g = GCD(a, b)

                ## DIAGNSOTIC
                #print "Cancelling from a 1x1 block:"
                #print "----------------------------"
                #print "  Cancelling entry with index (" + str(upper_left) + ", " + str(j) + ")"
                #print "  entry = " + str(b)
                #print "  gcd = " + str(g)
                #print "  a = " + str(a)
                #print "  b = " + str(b)
                #print "  a/g = " + str(a/g) + "   (used for stretching)"
                #print "  -b/g = " + str(-b/g) + "   (used for cancelling)"

                ## Sanity Check:  a/g is a p-unit
                if valuation(g, p) != valuation(a, p):
                    raise RuntimeError(
                        "Oops!  We have a problem with our rescaling not preserving p-integrality!"
                    )

                Q.multiply_variable(
                    ZZ(a / g), j, in_place=True
                )  ## Ensures that the new b entry is divisible by a
                Q.add_symmetric(ZZ(-b / g), j, 0,
                                in_place=True)  ## Performs the cancellation

        elif (block_size == 2):
            a1 = 2 * Q[0, 0]
            a2 = Q[0, 1]
            b1 = Q[1, 0]  ## This is the same as a2
            b2 = 2 * Q[1, 1]

            big_det = (a1 * b2 - a2 * b1)
            small_det = big_det / (min_scale * min_scale)

            ## Cancels out the rows/columns of the 2x2 block
            for j in range(block_size, n):
                a = Q[0, j]
                b = Q[1, j]

                ## Ensures an integral result (scale jth row/column by big_det)
                Q.multiply_variable(big_det, j, in_place=True)

                ## Performs the cancellation (by producing -big_det * jth row/column)
                Q.add_symmetric(ZZ(-(a * b2 - b * a2)), j, 0, in_place=True)
                Q.add_symmetric(ZZ(-(-a * b1 + b * a1)), j, 1, in_place=True)

                ## Now remove the extra factor (non p-unit factor) in big_det we introduced above
                Q.divide_variable(ZZ(min_scale * min_scale), j, in_place=True)

            ## DIAGNOSTIC
            #print "Cancelling out a 2x2 block:"
            #print "---------------------------"
            #print "  a1 = " + str(a1)
            #print "  a2 = " + str(a2)
            #print "  b1 = " + str(b1)
            #print "  b2 = " + str(b2)
            #print "  big_det = " + str(big_det)
            #print "  min_scale = " + str(min_scale)
            #print "  small_det = " + str(small_det)
            #print "  Q = \n", Q

            ## Uses Cassels's proof to replace the remaining 2 x 2 block
            if (((1 + small_det) % 8) == 0):
                Q[0, 0] = 0
                Q[1, 1] = 0
                Q[0, 1] = min_scale
            elif (((5 + small_det) % 8) == 0):
                Q[0, 0] = min_scale
                Q[1, 1] = min_scale
                Q[0, 1] = min_scale
            else:
                raise RuntimeError(
                    "Error in LocalNormal: Impossible behavior for a 2x2 block! \n"
                )

        ## Check that the cancellation worked, extract the upper-left block, and trim Q to handle the next block.
        for i in range(block_size):
            for j in range(block_size, n):
                if Q[i, j] != 0:
                    raise RuntimeError(
                        "Oops!  The cancellation didn't work properly at entry ("
                        + str(i) + ", " + str(j) + ").")
        Q_Jordan = Q_Jordan + Q.extract_variables(range(block_size))
        Q = Q.extract_variables(range(block_size, n))

    return Q_Jordan
def local_normal_form(self, p):
    """
    Returns the a locally integrally equivalent quadratic form over
    the p-adic integers Z_p which gives the Jordan decomposition.  The
    Jordan components are written as sums of blocks of size <= 2 and
    are arranged by increasing scale, and then by increasing norm.
    (This is equivalent to saying that we put the 1x1 blocks before
    the 2x2 blocks in each Jordan component.)

    INPUT:
        `p` -- a positive prime number.

    OUTPUT:
        a quadratic form over ZZ
    
    WARNING:  Currently this only works for quadratic forms defined over ZZ.
    
    EXAMPLES::
    
        sage: Q = QuadraticForm(ZZ, 2, [10,4,1])
        sage: Q.local_normal_form(5)
        Quadratic form in 2 variables over Integer Ring with coefficients: 
        [ 1 0 ]
        [ * 6 ]
        
    ::            
    
        sage: Q.local_normal_form(3)
        Quadratic form in 2 variables over Integer Ring with coefficients: 
        [ 10 0 ]
        [ * 15 ]
    
        sage: Q.local_normal_form(2)
        Quadratic form in 2 variables over Integer Ring with coefficients: 
        [ 1 0 ]
        [ * 6 ]
    
    """
    ## Sanity Checks
    if (self.base_ring() != IntegerRing()):
        raise NotImplementedError, "Oops!  This currently only works for quadratic forms defined over IntegerRing(). =("
    if not ((p>=2) and is_prime(p)):
        raise TypeError, "Oops!  p is not a positive prime number. =("

    ## Some useful local variables
    Q = copy.deepcopy(self)
    Q.__init__(self.base_ring(), self.dim(), self.coefficients())

    ## Prepare the final form to return
    Q_Jordan = copy.deepcopy(self)
    Q_Jordan.__init__(self.base_ring(), 0)

    
    while Q.dim() > 0:
        n = Q.dim()

        ## Step 1: Find the minimally p-divisible matrix entry, preferring diagonals
        ## -------------------------------------------------------------------------
        (min_i, min_j) = Q.find_entry_with_minimal_scale_at_prime(p)
        if min_i == min_j:
            min_val = valuation(2 * Q[min_i, min_j], p)
        else:
            min_val = valuation(Q[min_i, min_j], p)

        ## Error if we still haven't seen non-zero coefficients!
        if (min_val == Infinity):
            raise RuntimeError, "Oops!  The original matrix is degenerate. =("

      
        ## Step 2: Arrange for the upper leftmost entry to have minimal valuation
        ## ----------------------------------------------------------------------
        if (min_i == min_j):
            block_size = 1
            Q.swap_variables(0, min_i, in_place = True)
        else:
            ## Work in the upper-left 2x2 block, and replace it by its 2-adic equivalent form  
            Q.swap_variables(0, min_i, in_place = True)
            Q.swap_variables(1, min_j, in_place = True)

            ## 1x1 => make upper left the smallest
            if (p != 2):
                block_size = 1;
                Q.add_symmetric(1, 0, 1, in_place = True)   
            ## 2x2 => replace it with the appropriate 2x2 matrix
            else: 
                block_size = 2

        ## DIAGNOSTIC
        #print "\n Finished Step 2 \n";
        #print "\n Q is: \n" + str(Q)  + "\n";
        #print "  p is: " + str(p) 
        #print "  min_val is: " + str( min_val)
        #print "  block_size is: " + str(block_size)
        #print "\n Starting Step 3 \n"

        ## Step 3: Clear out the remaining entries
        ##  ---------------------------------------
        min_scale = p ** min_val                             ## This is the minimal valuation of the Hessian matrix entries.

        ##DIAGNOSTIC
        #print "Starting Step 3:"
        #print "----------------"
        #print "  min_scale is: " + str(min_scale)


        ## Perform cancellation over Z by ensuring divisibility
        if (block_size == 1):
            a = 2 * Q[0,0]
            for j in range(block_size, n):
                b = Q[0, j]
                g = GCD(a, b)

                ## DIAGNSOTIC
                #print "Cancelling from a 1x1 block:"
                #print "----------------------------"
                #print "  Cancelling entry with index (" + str(upper_left) + ", " + str(j) + ")"
                #print "  entry = " + str(b)
                #print "  gcd = " + str(g)
                #print "  a = " + str(a)
                #print "  b = " + str(b)
                #print "  a/g = " + str(a/g) + "   (used for stretching)"
                #print "  -b/g = " + str(-b/g) + "   (used for cancelling)"
                
                ## Sanity Check:  a/g is a p-unit
                if valuation (g, p) != valuation(a, p):
                    raise RuntimeError, "Oops!  We have a problem with our rescaling not preserving p-integrality!"

                Q.multiply_variable(ZZ(a/g), j, in_place = True)   ## Ensures that the new b entry is divisible by a
                Q.add_symmetric(ZZ(-b/g), j, 0, in_place = True)  ## Performs the cancellation


        elif (block_size == 2):
            a1 = 2 * Q[0,0]
            a2 = Q[0, 1]
            b1 = Q[1, 0]      ## This is the same as a2
            b2 = 2 * Q[1, 1]

            big_det = (a1*b2 - a2*b1) 
            small_det = big_det / (min_scale * min_scale)  

            ## Cancels out the rows/columns of the 2x2 block
            for j in range(block_size, n):
                a = Q[0, j]
                b = Q[1, j]
           
                ## Ensures an integral result (scale jth row/column by big_det)
                Q.multiply_variable(big_det, j, in_place = True)  
           
                ## Performs the cancellation (by producing -big_det * jth row/column)
                Q.add_symmetric(ZZ(-(a*b2 - b*a2)), j, 0, in_place = True)  
                Q.add_symmetric(ZZ(-(-a*b1 + b*a1)), j, 1, in_place = True)  

                ## Now remove the extra factor (non p-unit factor) in big_det we introduced above
                Q.divide_variable(ZZ(min_scale * min_scale), j, in_place = True)  

            ## DIAGNOSTIC
            #print "Cancelling out a 2x2 block:"
            #print "---------------------------"
            #print "  a1 = " + str(a1)
            #print "  a2 = " + str(a2)
            #print "  b1 = " + str(b1)
            #print "  b2 = " + str(b2)
            #print "  big_det = " + str(big_det)
            #print "  min_scale = " + str(min_scale)            
            #print "  small_det = " + str(small_det)            
            #print "  Q = \n", Q            

            ## Uses Cassels's proof to replace the remaining 2 x 2 block
            if (((1 + small_det) % 8) == 0):
                Q[0, 0] = 0
                Q[1, 1] = 0
                Q[0, 1] = min_scale
            elif (((5 + small_det) % 8) == 0):
                Q[0, 0] = min_scale
                Q[1, 1] = min_scale
                Q[0, 1] = min_scale
            else:
                raise RuntimeError, "Error in LocalNormal: Impossible behavior for a 2x2 block! \n"


        ## Check that the cancellation worked, extract the upper-left block, and trim Q to handle the next block.
        for i in range(block_size):
            for j in range(block_size, n):
                if Q[i,j] != 0:
                    raise RuntimeError, "Oops!  The cancellation didn't work properly at entry (" + str(i) + ", " + str(j) + ")."
        Q_Jordan = Q_Jordan + Q.extract_variables(range(block_size))
        Q = Q.extract_variables(range(block_size, n))

    return Q_Jordan
예제 #37
0
def has_equivalent_Jordan_decomposition_at_prime(self, other, p):
    """
    Determines if the given quadratic form has a Jordan decomposition
    equivalent to that of self.

    INPUT:
        a QuadraticForm

    OUTPUT:
        boolean

    EXAMPLES::

        sage: Q1 = QuadraticForm(ZZ, 3, [1, 0, -1, 1, 0, 3])
        sage: Q2 = QuadraticForm(ZZ, 3, [1, 0, 0, 2, -2, 6])
        sage: Q3 = QuadraticForm(ZZ, 3, [1, 0, 0, 1, 0, 11])
        sage: [Q1.level(), Q2.level(), Q3.level()]
        [44, 44, 44]
        sage: Q1.has_equivalent_Jordan_decomposition_at_prime(Q2,2)
        False
        sage: Q1.has_equivalent_Jordan_decomposition_at_prime(Q2,11)
        False
        sage: Q1.has_equivalent_Jordan_decomposition_at_prime(Q3,2)
        False
        sage: Q1.has_equivalent_Jordan_decomposition_at_prime(Q3,11)
        True
        sage: Q2.has_equivalent_Jordan_decomposition_at_prime(Q3,2)
        True
        sage: Q2.has_equivalent_Jordan_decomposition_at_prime(Q3,11)
        False

    """
    ## Sanity Checks
    #if not isinstance(other, QuadraticForm):
    if not isinstance(other, type(self)):
        raise TypeError(
            "Oops!  The first argument must be of type QuadraticForm.")
    if not is_prime(p):
        raise TypeError("Oops!  The second argument must be a prime number.")

    ## Get the relevant local normal forms quickly
    self_jordan = self.jordan_blocks_by_scale_and_unimodular(p,
                                                             safe_flag=False)
    other_jordan = other.jordan_blocks_by_scale_and_unimodular(p,
                                                               safe_flag=False)

    ## DIAGNOSTIC
    #print "self_jordan = ", self_jordan
    #print "other_jordan = ", other_jordan

    ## Check for the same number of Jordan components
    if len(self_jordan) != len(other_jordan):
        return False

    ## Deal with odd primes:  Check that the Jordan component scales, dimensions, and discriminants are the same
    if p != 2:
        for i in range(len(self_jordan)):
            if (self_jordan[i][0] != other_jordan[i][0]) \
               or (self_jordan[i][1].dim() != other_jordan[i][1].dim()) \
               or (legendre_symbol(self_jordan[i][1].det() * other_jordan[i][1].det(), p) != 1):
                return False

        ## All tests passed for an odd prime.
        return True

    ## For p = 2:  Check that all Jordan Invariants are the same.
    elif p == 2:

        ## Useful definition
        t = len(self_jordan)  ## Define t = Number of Jordan components

        ## Check that all Jordan Invariants are the same (scale, dim, and norm)
        for i in range(t):
            if (self_jordan[i][0] != other_jordan[i][0]) \
               or (self_jordan[i][1].dim() != other_jordan[i][1].dim()) \
               or (valuation(GCD(self_jordan[i][1].coefficients()), p) != valuation(GCD(other_jordan[i][1].coefficients()), p)):
                return False

        ## DIAGNOSTIC
        #print "Passed the Jordan invariant test."

        ## Use O'Meara's isometry test 93:29 on p277.
        ## ------------------------------------------

        ## List of norms, scales, and dimensions for each i
        scale_list = [ZZ(2)**self_jordan[i][0] for i in range(t)]
        norm_list = [
            ZZ(2)**(self_jordan[i][0] +
                    valuation(GCD(self_jordan[i][1].coefficients()), 2))
            for i in range(t)
        ]
        dim_list = [(self_jordan[i][1].dim()) for i in range(t)]

        ## List of Hessian determinants and Hasse invariants for each Jordan (sub)chain
        ## (Note: This is not the same as O'Meara's Gram determinants, but ratios are the same!)  -- NOT SO GOOD...
        ## But it matters in condition (ii), so we multiply all by 2 (instead of dividing by 2 since only square-factors matter, and it's easier.)
        j = 0
        self_chain_det_list = [
            self_jordan[j][1].Gram_det() * (scale_list[j]**dim_list[j])
        ]
        other_chain_det_list = [
            other_jordan[j][1].Gram_det() * (scale_list[j]**dim_list[j])
        ]
        self_hasse_chain_list = [
            self_jordan[j][1].scale_by_factor(
                ZZ(2)**self_jordan[j][0]).hasse_invariant__OMeara(2)
        ]
        other_hasse_chain_list = [
            other_jordan[j][1].scale_by_factor(
                ZZ(2)**other_jordan[j][0]).hasse_invariant__OMeara(2)
        ]

        for j in range(1, t):
            self_chain_det_list.append(self_chain_det_list[j - 1] *
                                       self_jordan[j][1].Gram_det() *
                                       (scale_list[j]**dim_list[j]))
            other_chain_det_list.append(other_chain_det_list[j - 1] *
                                        other_jordan[j][1].Gram_det() *
                                        (scale_list[j]**dim_list[j]))
            self_hasse_chain_list.append(self_hasse_chain_list[j-1] \
                                         * hilbert_symbol(self_chain_det_list[j-1], self_jordan[j][1].Gram_det(), 2) \
                                         * self_jordan[j][1].hasse_invariant__OMeara(2))
            other_hasse_chain_list.append(other_hasse_chain_list[j-1] \
                                          * hilbert_symbol(other_chain_det_list[j-1], other_jordan[j][1].Gram_det(), 2) \
                                          * other_jordan[j][1].hasse_invariant__OMeara(2))

        ## SANITY CHECK -- check that the scale powers are strictly increasing
        for i in range(1, len(scale_list)):
            if scale_list[i - 1] >= scale_list[i]:
                raise RuntimeError(
                    "Oops!  There is something wrong with the Jordan Decomposition -- the given scales are not strictly increasing!"
                )

        ## DIAGNOSTIC
        #print "scale_list = ", scale_list
        #print "norm_list = ", norm_list
        #print "dim_list = ", dim_list
        #print
        #print "self_chain_det_list = ", self_chain_det_list
        #print "other_chain_det_list = ", other_chain_det_list
        #print "self_hasse_chain_list = ", self_hasse_chain_list
        #print "other_hasse_chain_det_list = ", other_hasse_chain_list

        ## Test O'Meara's two conditions
        for i in range(t - 1):

            ## Condition (i): Check that their (unit) ratio is a square (but it suffices to check at most mod 8).
            modulus = norm_list[i] * norm_list[i + 1] / (scale_list[i]**2)
            if modulus > 8:
                modulus = 8
            if (modulus > 1) and ((
                (self_chain_det_list[i] / other_chain_det_list[i]) % modulus)
                                  != 1):
                #print "Failed when i =", i, " in condition 1."
                return False

            ## Check O'Meara's condition (ii) when appropriate
            if norm_list[i + 1] % (4 * norm_list[i]) == 0:
                if self_hasse_chain_list[i] * hilbert_symbol(norm_list[i] * other_chain_det_list[i], -self_chain_det_list[i], 2) \
                       != other_hasse_chain_list[i] * hilbert_symbol(norm_list[i], -other_chain_det_list[i], 2):      ## Nipp conditions
                    #print "Failed when i =", i, " in condition 2."
                    return False

        ## All tests passed for the prime 2.
        return True

    else:
        raise TypeError("Oops!  This should not have happened.")
예제 #38
0
    def green_function(self, G,v, **kwds):
        r"""
        Evaluates the local Green's function at the place ``v`` for ``self`` with ``N`` terms of the series
        or, in dimension 1, to within the specified error bound. Defaults to ``N=10`` if no kwds provided

        Use ``v=0`` for the archimedean place. Must be over `\ZZ` or `\QQ`.

        ALGORITHM:

        See Exercise 5.29 and Figure 5.6 of ``The Arithmetic of Dynamics Systems``, Joseph H. Silverman, Springer, GTM 241, 2007.

        INPUT:

        - ``G`` - an endomorphism of self.codomain()

        - ``v`` - non-negative integer. a place, use v=0 for the archimedean place

        kwds:

        - ``N`` - positive integer. number of terms of the series to use

        - ``prec`` - positive integer, float point or p-adic precision, default: 100

        - ``error_bound`` - a positive real number

        OUTPUT:

        - a real number

        Examples::

            sage: P.<x,y>=ProjectiveSpace(QQ,1)
            sage: H=Hom(P,P)
            sage: f=H([x^2+y^2,x*y]);
            sage: Q=P(5,1)
            sage: f.green_function(Q,0,N=30)
            1.6460930159932946233759277576

        ::

            sage: P.<x,y>=ProjectiveSpace(QQ,1)
            sage: H=Hom(P,P)
            sage: f=H([x^2+y^2,x*y]);
            sage: Q=P(5,1)
            sage: Q.green_function(f,0,N=200,prec=200)
            1.6460930160038721802875250367738355497198064992657997569827

        .. TODO::

            error bounds for dimension > 1
        """
        N = kwds.get('N', None)                     #Get number of iterates (if entered)
        err = kwds.get('error_bound', None)         #Get error bound (if entered)
        prec = kwds.get('prec', 100)                #Get precision (if entered)
        R=RealField(prec)

        if not (v == 0 or is_prime(v)):
            raise ValueError("Invalid valuation (=%s) entered."%v)
        if v == 0:
            K = R
        else:
            K = Qp(v, prec)

        #Coerce all polynomials in F into polynomials with coefficients in K
        F=G.change_ring(K,False)
        d = F.degree()
        D=F.codomain().ambient_space().dimension_relative()

        if err is not None:
            if D!=1:
                raise NotImplementedError("error bounds only for dimension 1")
            err = R(err)
            if not err>0:
                raise ValueError, "Error bound (=%s) must be positive."%err

            #if doing error estimates, compute needed number of iterates
            res = F.resultant()

            #compute maximum coefficient of polynomials of F
            C = R(G.global_height(prec))

            if v == 0:
                log_fact = R(0)
                for i in range(2*d+1):
                    log_fact += R(i+1).log()
                B = max((R(res.abs()) - R(2*d).log() - (2*d-1)*C - log_fact).log().abs(), (C + R(d+1).log()).abs())
            else:
                B = max(R(res.abs()).log() - ((2*d-1)*C).abs(), C.abs())
            N = R(B/(err*(d-1))).log(d).abs().ceil()

        elif N is None:
            N=10 #default is to do 10 iterations

        #Coerce the coordinates into Q_v
        self.normalize_coordinates()
        if self.codomain().base_ring()==QQ:
            self.clear_denominators()
        P=self.change_ring(K,False)

        #START GREEN FUNCTION CALCULATION

        g = R(0)

        for i in range(N+1):
            m = -1

            #compute the maximum absolute value of entries of a, and where it occurs
            for n in range(D+1):
                a_v = R(P[n].abs())
                if a_v > m:
                    j = n
                    m = a_v

            #add to Greens function
            g += (1/R(d))**(i)*R(m).log()

            #normalize coordinates and evaluate
            P.scale_by(1/P[j])
            P = F(P,False)

        return g
    def pthpowers(self, p, Bound):
        """
        Find the indices of proveably all pth powers in the recurrence sequence bounded by Bound.

        Let `u_n` be a binary recurrence sequence.  A ``p`` th power in `u_n` is a solution
        to `u_n = y^p` for some integer `y`.  There are only finitely many ``p`` th powers in
        any recurrence sequence [SS].

        INPUT:

        - ``p`` - a rational prime integer (the fixed p in `u_n = y^p`)

        - ``Bound`` - a natural number (the maximum index `n` in `u_n = y^p` that is checked).

        OUTPUT:

        - A list of the indices of all ``p`` th powers less bounded by ``Bound``.  If the sequence is degenerate and there are many ``p`` th powers, raises ``ValueError``.

        EXAMPLES::

            sage: R = BinaryRecurrenceSequence(1,1)        #the Fibonacci sequence
            sage: R.pthpowers(2, 10**30)        # long time (7 seconds) -- in fact these are all squares, c.f. [BMS06]
            [0, 1, 2, 12]

            sage: S = BinaryRecurrenceSequence(8,1) #a Lucas sequence
            sage: S.pthpowers(3,10**30)    # long time (3 seconds) -- provably finds the indices of all 3rd powers less than 10^30
            [0, 1, 2]

            sage: Q = BinaryRecurrenceSequence(3,3,2,1)
            sage: Q.pthpowers(11,10**30)          # long time (7.5 seconds)
            [1]

        If the sequence is degenerate, and there are are no ``p`` th powers, returns `[]`.  Otherwise, if
        there are many ``p`` th powers, raises ``ValueError``.

        ::

            sage: T = BinaryRecurrenceSequence(2,0,1,2)
            sage: T.is_degenerate()
            True
            sage: T.is_geometric()
            True
            sage: T.pthpowers(7,10**30)
            Traceback (most recent call last):
            ...
            ValueError: The degenerate binary recurrence sequence is geometric or quasigeometric and has many pth powers.

            sage: L = BinaryRecurrenceSequence(4,0,2,2)
            sage: [L(i).factor() for i in xrange(10)]
            [2, 2, 2^3, 2^5, 2^7, 2^9, 2^11, 2^13, 2^15, 2^17]
            sage: L.is_quasigeometric()
            True
            sage: L.pthpowers(2,10**30)
            []

        NOTE: This function is primarily optimized in the range where ``Bound`` is much larger than ``p``.

        """

        #Thanks to Jesse Silliman for helpful conversations!

        #Reset the dictionary of good primes, as this depends on p
        self._PGoodness = {}
        #Starting lower bound on good primes
        self._ell = 1

        #If the sequence is geometric, then the `n`th term is `a*r^n`.  Thus the
        #property of being a ``p`` th power is periodic mod ``p``.  So there are either
        #no ``p`` th powers if there are none in the first ``p`` terms, or many if there
        #is at least one in the first ``p`` terms.

        if self.is_geometric() or self.is_quasigeometric():
            no_powers = True
            for i in xrange(1,6*p+1):
                if _is_p_power(self(i), p) :
                    no_powers = False
                    break
            if no_powers:
                if _is_p_power(self.u0,p):
                    return [0]
                return []
            else :
                raise ValueError, "The degenerate binary recurrence sequence is geometric or quasigeometric and has many pth powers."

        #If the sequence is degenerate without being geometric or quasigeometric, there
        #may be many ``p`` th powers or no ``p`` th powers.

        elif (self.b**2+4*self.c) == 0 :

            #This is the case if the matrix F is not diagonalizable, ie b^2 +4c = 0, and alpha/beta = 1.

            alpha = self.b/2

            #In this case, u_n = u_0*alpha^n + (u_1 - u_0*alpha)*n*alpha^(n-1) = alpha^(n-1)*(u_0 +n*(u_1 - u_0*alpha)),
            #that is, it is a geometric term (alpha^(n-1)) times an arithmetic term (u_0 + n*(u_1-u_0*alpha)).

            #Look at classes n = k mod p, for k = 1,...,p.

            for k in xrange(1,p+1):

                #The linear equation alpha^(k-1)*u_0 + (k+pm)*(alpha^(k-1)*u1 - u0*alpha^k)
                #must thus be a pth power.  This is a linear equation in m, namely, A + B*m, where

                A = (alpha**(k-1)*self.u0 + k*(alpha**(k-1)*self.u1 - self.u0*alpha**k))
                B = p*(alpha**(k-1)*self.u1 - self.u0*alpha**k)

                #This linear equation represents a pth power iff A is a pth power mod B.

                if _is_p_power_mod(A, p, B):
                    raise ValueError, "The degenerate binary recurrence sequence has many pth powers."
            return []

        #We find ``p`` th powers using an elementary sieve.  Term `u_n` is a ``p`` th
        #power if and only if it is a ``p`` th power modulo every prime `\\ell`.  This condition
        #gives nontrivial information if ``p`` divides the order of the multiplicative group of
        #`\\Bold(F)_{\\ell}`, i.e. if `\\ell` is ` 1 \mod{p}`, as then only `1/p` terms are ``p`` th
        #powers modulo `\\ell``.

        #Thus, given such an `\\ell`, we get a set of necessary congruences for the index modulo the
        #the period of the sequence mod `\\ell`.  Then we intersect these congruences for many primes
        #to get a tight list modulo a growing modulus.  In order to keep this step manageable, we
        #only use primes `\\ell` that are have particularly smooth periods.

        #Some congruences in the list will remain as the modulus grows.  If a congruence remains through
        #7 rounds of increasing the modulus, then we check if this corresponds to a perfect power (if
        #it does, we add it to our list of indices corresponding to ``p`` th powers).  The rest of the congruences
        #are transient and grow with the modulus.  Once the smallest of these is greater than the bound,
        #the list of known indices corresponding to ``p`` th powers is complete.

        else:

            if Bound < 3 * p :

                powers = []
                ell = p + 1

                while not is_prime(ell):
                    ell = ell + p

                F = GF(ell)
                a0 = F(self.u0); a1 = F(self.u1) #a0 and a1 are variables for terms in sequence
                bf, cf = F(self.b), F(self.c)

                for n in xrange(Bound): # n is the index of the a0

                    #Check whether a0 is a perfect power mod ell
                    if _is_p_power_mod(a0, p, ell) :
                        #if a0 is a perfect power mod ell, check if nth term is ppower
                        if _is_p_power(self(n), p):
                            powers.append(n)

                    a0, a1 = a1, bf*a1 + cf*a0        #step up the variables

            else :

                powers = []        #documents the indices of the sequence that provably correspond to pth powers
                cong = [0]        #list of necessary congruences on the index for it to correspond to pth powers
                Possible_count = {}    #keeps track of the number of rounds a congruence lasts in cong

                #These parameters are involved in how we choose primes to increase the modulus
                qqold = 1        #we believe that we know complete information coming from primes good by qqold
                M1 = 1            #we have congruences modulo M1, this may not be the tightest list
                M2 = p            #we want to move to have congruences mod M2
                qq = 1            #the largest prime power divisor of M1 is qq

                #This loop ups the modulus.
                while True:

                    #Try to get good data mod M2

                    #patience of how long we should search for a "good prime"
                    patience = 0.01 * _estimated_time(lcm(M2,p*next_prime_power(qq)), M1, len(cong), p)
                    tries = 0

                    #This loop uses primes to get a small set of congruences mod M2.
                    while True:

                        #only proceed if took less than patience time to find the next good prime
                        ell = _next_good_prime(p, self, qq, patience, qqold)
                        if ell:

                            #gather congruence data for the sequence mod ell, which will be mod period(ell) = modu
                            cong1, modu = _find_cong1(p, self, ell)

                            CongNew = []        #makes a new list from cong that is now mod M = lcm(M1, modu) instead of M1
                            M = lcm(M1, modu)
                            for k in xrange(M/M1):
                                for i in cong:
                                    CongNew.append(k*M1+i)
                            cong = set(CongNew)

                            M1 = M

                            killed_something = False        #keeps track of when cong1 can rule out a congruence in cong

                            #CRT by hand to gain speed
                            for i in list(cong):
                                if not (i % modu in cong1):        #congruence in cong is inconsistent with any in cong1
                                    cong.remove(i)            #remove that congruence
                                    killed_something = True

                            if M1 == M2:
                                if not killed_something:
                                    tries += 1
                                    if tries == 2:            #try twice to rule out congruences
                                        cong = list(cong)
                                        qqold = qq
                                        qq = next_prime_power(qq)
                                        M2 = lcm(M2,p*qq)
                                        break

                        else :
                            qq = next_prime_power(qq)
                            M2 = lcm(M2,p*qq)
                            cong = list(cong)
                            break

                    #Document how long each element of cong has been there
                    for i in cong:
                        if i in Possible_count:
                            Possible_count[i] = Possible_count[i] + 1
                        else :
                            Possible_count[i] = 1

                    #Check how long each element has persisted, if it is for at least 7 cycles,
                    #then we check to see if it is actually a perfect power
                    for i in Possible_count:
                        if Possible_count[i] == 7:
                            n = Integer(i)
                            if n < Bound:
                                if _is_p_power(self(n),p):
                                    powers.append(n)

                    #check for a contradiction
                    if len(cong) > len(powers):
                        if cong[len(powers)] > Bound:
                            break
                    elif M1 > Bound:
                        break

            return powers
예제 #40
0
    def create_key_and_extra_args(self, order, name=None, modulus=None, names=None,
                                  impl=None, proof=None, **kwds):
        """
        EXAMPLES::

            sage: GF.create_key_and_extra_args(9, 'a')
            ((9, ('a',), x^2 + 2*x + 2, None, '{}', 3, 2, True), {})
            sage: GF.create_key_and_extra_args(9, 'a', foo='value')
            ((9, ('a',), x^2 + 2*x + 2, None, "{'foo': 'value'}", 3, 2, True), {'foo': 'value'})
        """
        from sage.structure.proof.all import WithProof, arithmetic
        if proof is None: proof = arithmetic()
        with WithProof('arithmetic', proof):
            order = int(order)
            if order <= 1:
                raise ValueError("the order of a finite field must be > 1.")

            if arith.is_prime(order):
                name = None
                modulus = None
                p = integer.Integer(order)
                n = integer.Integer(1)
            elif arith.is_prime_power(order):
                if not names is None: name = names
                name = normalize_names(1,name)

                p, n = arith.factor(order)[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 (kwds.has_key('conway') and kwds['conway']):
                        raise ValueError("parameter 'conway' is required if no name given")
                    if not kwds.has_key('prefix'):
                        raise ValueError("parameter 'prefix' is required if no name given")
                    name = kwds['prefix'] + str(n)

                if kwds.has_key('conway') and kwds['conway']:
                    from conway_polynomials import conway_polynomial
                    if not kwds.has_key('prefix'):
                        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)

                if modulus is None or isinstance(modulus, str):
                    # A string specifies an algorithm to find a suitable modulus.
                    if modulus == "default":    # for backward compatibility
                        modulus = None
                    modulus = GF(p)['x'].irreducible_element(n, algorithm=modulus)
                elif isinstance(modulus, (list, tuple)):
                    modulus = GF(p)['x'](modulus)
                elif sage.rings.polynomial.polynomial_element.is_Polynomial(modulus):
                    modulus = modulus.change_variable_name('x')
                else:
                    raise TypeError("wrong type for modulus parameter")
            else:
                raise ValueError("the order of a finite field must be a prime power.")

            return (order, name, modulus, impl, str(kwds), p, n, proof), kwds