Пример #1
0
def enumerate_totallyreal_fields_rel(F, m, B, a = [], verbose=0, return_seqs=False):
    r"""
    This function enumerates (primitive) totally real field extensions of
    degree `m>1` of the totally real field F with discriminant `d \leq B`;
    optionally one can specify the first few coefficients, where the sequence ``a``
    corresponds to a polynomial by

    ::

        a[d]*x^n + ... + a[0]*x^(n-d)

    if ``length(a) = d+1``, so in particular always ``a[d] = 1``.
    If verbose == 1 (or 2), then print to the screen (really) verbosely; if
    verbose is a string, then print verbosely to the file specified by verbose.
    If return_seqs, then return the polynomials as sequences (for easier
    exporting to a file).

    NOTE:
    This is guaranteed to give all primitive such fields, and
    seems in practice to give many imprimitive ones.

    INPUT:

    - ``F`` -- number field, the base field
    - ``m`` -- integer, the degree
    - ``B`` -- integer, the discriminant bound
    - ``a`` -- list (default: []), the coefficient list to begin with
    - ``verbose`` -- boolean or string (default: 0)
    - ``return_seqs`` -- boolean (default: False)

    OUTPUT:

    the list of fields with entries [d,fabs,f], where
    d is the discriminant, fabs is an absolute defining polynomial,
    and f is a defining polynomial relative to F,
    sorted by discriminant.

    EXAMPLES::

        sage: ZZx = ZZ['x']
        sage: F.<t> = NumberField(x^2-2)
        sage: enumerate_totallyreal_fields_rel(F, 2, 2000)
        [[1600, x^4 - 6*x^2 + 4, xF^2 + xF - 1]]

    AUTHORS:

    - John Voight (2007-11-01)
    """

    if not isinstance(m, Integer):
        try:
            m = Integer(m)
        except TypeError:
            raise TypeError, "cannot coerce m (= %s) to an integer" % m
    if (m < 1):
        raise ValueError, "m must be at least 1."

    n = F.degree()*m

    # Initialize
    T = tr_data_rel(F,m,B,a)
    S = []
    Srel = []
    dB_odlyzko = odlyzko_bound_totallyreal(n)
    dB = math.ceil(40000*dB_odlyzko**n)
    counts = [0,0,0,0]

    # Trivial case
    if m == 1:
        g = pari(F.defining_polynomial()).reverse().Vec()
        if return_seqs:
            return [[0,0,0,0],[1,g,[-1,1]]]
        else:
            return [[1,pari('x-1'),g]]

    if verbose:
        saveout = sys.stdout
        if type(verbose) == str:
            fsock = open(verbose, 'w')
            sys.stdout = fsock
        # Else, print to screen
    f_out = [0]*m + [1]
    if verbose == 2:
        T.incr(f_out,verbose)
    else:
        T.incr(f_out)

    Fx = PolynomialRing(F, 'xF')

    nfF = pari(str(F.defining_polynomial()).replace('x', str(F.primitive_element()) ) )
    parit = pari(str(F.primitive_element()))

    while f_out[m] != 0:
        counts[0] += 1
        if verbose:
            print "==>", f_out,

        f_str = ''
        for i in range(len(f_out)):
            f_str += '(' + str(f_out[i]) + ')*x^' + str(i)
            if i < len(f_out)-1:
                f_str += '+'
        nf = pari(f_str)
        if nf.poldegree('t') == 0:
            nf = nf.subst('x', 'x-t')
        nf = nf.polresultant(nfF, parit)
        d = nf.poldisc()
        counts[0] += 1
        if d > 0 and nf.polsturm_full() == n:
            da = int_has_small_square_divisor(Integer(d))
            if d > dB or d <= B*da:
                counts[1] += 1
                if nf.polisirreducible():
                    counts[2] += 1
                    [zk,d] = nf.nfbasis_d()

                    if d <= B:
                        if verbose:
                            print "has discriminant", d,

                        # Find a minimal lattice element
                        counts[3] += 1
                        ng = pari([nf,zk]).polredabs()

                        # Check if K is contained in the list.
                        found = False
                        ind = bisect.bisect_left(S, [d,ng])
                        while ind < len(S) and S[ind][0] == d:
                            if S[ind][1] == ng:
                                if verbose:
                                    print "but is not new"
                                found = True
                                break
                            ind += 1
                        if not found:
                            if verbose:
                                print "and is new!"
                            S.insert(ind, [d,ng])
                            Srel.insert(ind, Fx(f_out))
                    else:
                        if verbose:
                            print "has discriminant", abs(d), "> B"
                else:
                    if verbose:
                        print "is not absolutely irreducible"
            else:
                if verbose:
                    print "has discriminant", abs(d), "with no large enough square divisor"
        else:
            if verbose:
                if d == 0:
                    print "is not squarefree"
                else:
                    print "is not totally real"
        if verbose == 2:
            T.incr(f_out,verbose=verbose)
        else:
            T.incr(f_out)

    # In the application of Smyth's theorem above, we exclude finitely
    # many possibilities which we must now throw back in.
    if m == 2:
        if Fx([-1,1,1]).is_irreducible():
            K = F.extension(Fx([-1,1,1]), 'tK')
            Kabs = K.absolute_field('tKabs')
            Kabs_pari = pari(Kabs.defining_polynomial())
            d = K.absolute_discriminant()
            if abs(d) <= B:
                ng = Kabs_pari.polredabs()
                ind = bisect.bisect_left(S, [d,ng])
                S.insert(ind, [d,ng])
                Srel.insert(ind, Fx([-1,1,1]))
        elif F.degree() == 2:
            for ff in [[1,-7,13,-7,1],[1,-8,14,-7,1]]:
                f = Fx(ff).factor()[0][0]
                K = F.extension(f, 'tK')
                Kabs = K.absolute_field('tKabs')
                Kabs_pari = pari(Kabs.defining_polynomial())
                d = K.absolute_discriminant()
                if abs(d) <= B:
                    ng = Kabs_pari.polredabs()
                    ind = bisect.bisect_left(S, [d,ng])
                    S.insert(ind, [d,ng])
                    Srel.insert(ind, f)
    elif m == 3:
        if Fx([-1,6,-5,1]).is_irreducible():
            K = F.extension(Fx([-1,6,-5,1]), 'tK')
            Kabs = K.absolute_field('tKabs')
            Kabs_pari = pari(Kabs.defining_polynomial())
            d = K.absolute_discriminant()
            if abs(d) <= B:
                ng = Kabs_pari.polredabs()
                ind = bisect.bisect_left(S, [d,ng])
                S.insert(ind, [d,ng])
                Srel.insert(ind, Fx([-1,6,-5,1]))

    # Now check for isomorphic fields
    S = [[S[i][0],S[i][1],Srel[i]] for i in range(len(S))]
    weed_fields(S)

    # Output.
    if verbose:
        print "="*80
        print "Polynomials tested:", counts[0]
        print "Irreducible polynomials:", counts[1]
        print "Polynomials with nfdisc <= B:", counts[2]
        for i in range(len(S)):
            print S[i]
        if type(verbose) == str:
            fsock.close()
        sys.stdout = saveout

    if return_seqs:
        return [counts,[[s[0],s[1].reverse().Vec(),s[2].coeffs()] for s in S]]
    else:
        return S
Пример #2
0
def enumerate_totallyreal_fields_rel(F,
                                     m,
                                     B,
                                     a=[],
                                     verbose=0,
                                     return_seqs=False,
                                     return_pari_objects=True):
    r"""
    This function enumerates (primitive) totally real field extensions of
    degree `m>1` of the totally real field F with discriminant `d \leq B`;
    optionally one can specify the first few coefficients, where the sequence ``a``
    corresponds to a polynomial by

    ::

        a[d]*x^n + ... + a[0]*x^(n-d)

    if ``length(a) = d+1``, so in particular always ``a[d] = 1``.

    .. note::

        This is guaranteed to give all primitive such fields, and
        seems in practice to give many imprimitive ones.

    INPUT:

    - ``F`` -- number field, the base field
    - ``m`` -- integer, the degree
    - ``B`` -- integer, the discriminant bound
    - ``a`` -- list (default: []), the coefficient list to begin with
    - ``verbose`` -- boolean or nonnegative integer or string (default: 0)
      give a verbose description of the computations being performed. If
      ``verbose`` is set to ``2`` or more then it outputs some extra
      information. If ``verbose`` is a string then it outputs to a file
      specified by ``verbose``
    - ``return_seqs`` -- (boolean, default False) If ``True``, then return
      the polynomials as sequences (for easier exporting to a file). This
      also returns a list of four numbers, as explained in the OUTPUT
      section below.
    - ``return_pari_objects`` -- (boolean, default: True) if
      both ``return_seqs`` and ``return_pari_objects`` are ``False`` then
      it returns the elements as Sage objects; otherwise it returns pari
      objects.

    OUTPUT:

    - the list of fields with entries ``[d,fabs,f]``, where ``d`` is the
      discriminant, ``fabs`` is an absolute defining polynomial, and ``f``
      is a defining polynomial relative to ``F``, sorted by discriminant.

    - if ``return_seqs`` is ``True``, then the first field of the list is
      a list containing the count of four items as explained below

      - the first entry gives the number of polynomials tested
      - the second entry gives the number of polynomials with its
        discriminant having a large enough square divisor
      - the third entry is the number of irreducible polynomials
      - the fourth entry is the number of irreducible polynomials with
        discriminant at most ``B``

    EXAMPLES::

        sage: ZZx = ZZ['x']
        sage: F.<t> = NumberField(x^2-2)
        sage: enumerate_totallyreal_fields_rel(F, 1, 2000)
        [[1, [-2, 0, 1], xF - 1]]
        sage: enumerate_totallyreal_fields_rel(F, 2, 2000)
        [[1600, x^4 - 6*x^2 + 4, xF^2 + xF - 1]]
        sage: enumerate_totallyreal_fields_rel(F, 2, 2000, return_seqs=True)
        [[9, 6, 5, 0], [[1600, [4, 0, -6, 0, 1], [-1, 1, 1]]]]

    TESTS:

    Each of the outputs must be elements of Sage if ``return_pari_objects``
    is set to ``False``::

        sage: type(enumerate_totallyreal_fields_rel(F, 2, 2000)[0][1])
        <type 'cypari2.gen.Gen'>
        sage: enumerate_totallyreal_fields_rel(F, 2, 2000, return_pari_objects=False)[0][0].parent()
        Integer Ring
        sage: enumerate_totallyreal_fields_rel(F, 2, 2000, return_pari_objects=False)[0][1].parent()
        Univariate Polynomial Ring in x over Rational Field
        sage: enumerate_totallyreal_fields_rel(F, 2, 2000, return_pari_objects=False)[0][2].parent()
        Univariate Polynomial Ring in xF over Number Field in t with defining polynomial x^2 - 2
        sage: enumerate_totallyreal_fields_rel(F, 2, 2000, return_seqs=True)[1][0][1][0].parent()
        Rational Field

    AUTHORS:

    - John Voight (2007-11-01)
    """

    if not isinstance(m, Integer):
        try:
            m = Integer(m)
        except TypeError:
            raise TypeError("cannot coerce m (= %s) to an integer" % m)
    if (m < 1):
        raise ValueError("m must be at least 1.")

    n = F.degree() * m

    # Initialize
    S = {}  # dictionary of the form {(d, fabs): f, ...}
    dB_odlyzko = odlyzko_bound_totallyreal(n)
    dB = math.ceil(40000 * dB_odlyzko**n)
    counts = [0, 0, 0, 0]

    # Trivial case
    if m == 1:
        g = pari(F.defining_polynomial()).polrecip().Vec()
        if return_seqs:
            return [[0, 0, 0, 0], [1, [-1, 1], g]]
        elif return_pari_objects:
            return [[1, g, pari('xF-1')]]
        else:
            Px = PolynomialRing(QQ, 'xF')
            return [[ZZ(1), [QQ(_) for _ in g], Px.gen() - 1]]

    if verbose:
        saveout = sys.stdout
        if isinstance(verbose, str):
            fsock = open(verbose, 'w')
            sys.stdout = fsock
        # Else, print to screen
    f_out = [0] * m + [1]
    T = tr_data_rel(F, m, B, a)
    if verbose == 2:
        T.incr(f_out, verbose)
    else:
        T.incr(f_out)

    Fx = PolynomialRing(F, 'xF')

    nfF = pari(
        str(F.defining_polynomial()).replace('x', str(F.primitive_element())))
    parit = pari(str(F.primitive_element()))

    while f_out[m] != 0:
        counts[0] += 1
        if verbose:
            print("==>", f_out, end="")

        f_str = ''
        for i in range(len(f_out)):
            f_str += '(' + str(f_out[i]) + ')*x^' + str(i)
            if i < len(f_out) - 1:
                f_str += '+'
        nf = pari(f_str)
        if nf.poldegree('t') == 0:
            nf = nf.subst('x', 'x-t')
        nf = nf.polresultant(nfF, parit)
        d = nf.poldisc()
        #counts[0] += 1
        if d > 0 and nf.polsturm() == n:
            da = int_has_small_square_divisor(Integer(d))
            if d > dB or d <= B * da:
                counts[1] += 1
                if nf.polisirreducible():
                    counts[2] += 1
                    [zk, d] = nf.nfbasis_d()

                    if d <= B:
                        if verbose:
                            print("has discriminant", d, end="")

                        # Find a minimal lattice element
                        counts[3] += 1
                        ng = pari([nf, zk]).polredabs()

                        # Check if K is contained in the list.
                        if (d, ng) in S:
                            if verbose:
                                print("but is not new")
                        else:
                            if verbose:
                                print("and is new!")
                            S[(d, ng)] = Fx(f_out)
                    else:
                        if verbose:
                            print("has discriminant", abs(d), "> B")
                else:
                    if verbose:
                        print("is not absolutely irreducible")
            else:
                if verbose:
                    print("has discriminant", abs(d),
                          "with no large enough square divisor")
        else:
            if verbose:
                if d == 0:
                    print("is not squarefree")
                else:
                    print("is not totally real")
        if verbose == 2:
            T.incr(f_out, verbose=verbose)
        else:
            T.incr(f_out)

    # In the application of Smyth's theorem above, we exclude finitely
    # many possibilities which we must now throw back in.
    if m == 2:
        if Fx([-1, 1, 1]).is_irreducible():
            K = F.extension(Fx([-1, 1, 1]), 'tK')
            Kabs = K.absolute_field('tKabs')
            Kabs_pari = pari(Kabs.defining_polynomial())
            d = K.absolute_discriminant()
            if abs(d) <= B:
                ng = Kabs_pari.polredabs()
                S[(d, ng)] = Fx([-1, 1, 1])
        elif F.degree() == 2:
            for ff in [[1, -7, 13, -7, 1], [1, -8, 14, -7, 1]]:
                f = Fx(ff).factor()[0][0]
                K = F.extension(f, 'tK')
                Kabs = K.absolute_field('tKabs')
                Kabs_pari = pari(Kabs.defining_polynomial())
                d = K.absolute_discriminant()
                if abs(d) <= B:
                    ng = Kabs_pari.polredabs()
                    S[(d, ng)] = f
    elif m == 3:
        if Fx([-1, 6, -5, 1]).is_irreducible():
            K = F.extension(Fx([-1, 6, -5, 1]), 'tK')
            Kabs = K.absolute_field('tKabs')
            Kabs_pari = pari(Kabs.defining_polynomial())
            d = K.absolute_discriminant()
            if abs(d) <= B:
                ng = Kabs_pari.polredabs()
                S[(d, ng)] = Fx([-1, 6, -5, 1])

    # Convert S to a sorted list of triples [d, fabs, f], taking care
    # not to use the comparison operators on PARI polynomials.
    S = [[s[0], s[1], t] for s, t in S.items()]
    S.sort(key=lambda x: (x[0], [QQ(cf) for cf in x[1].polrecip().Vec()]))

    # Now check for isomorphic fields
    weed_fields(S)

    # Output.
    if verbose:
        print("=" * 80)
        print("Polynomials tested: {}".format(counts[0]))
        print("Polynomials with discriminant with large enough square"
              " divisor: {}".format(counts[1]))
        print("Irreducible polynomials: {}".format(counts[2]))
        print("Polynomials with nfdisc <= B: {}".format(counts[3]))
        for i in range(len(S)):
            print(S[i])
        if isinstance(verbose, str):
            fsock.close()
        sys.stdout = saveout

    # Make sure to return elements that belong to Sage
    if return_seqs:
        return [[ZZ(x) for x in counts],
                [[
                    s[0], [QQ(x) for x in s[1].polrecip().Vec()],
                    s[2].coefficients(sparse=False)
                ] for s in S]]
    elif return_pari_objects:
        return S
    else:
        Px = PolynomialRing(QQ, 'x')
        return [[s[0], Px([QQ(_) for _ in s[1].list()]), s[2]] for s in S]
Пример #3
0
def enumerate_totallyreal_fields_rel(F, m, B, a = [], verbose=0,
                                     return_seqs=False,
                                     return_pari_objects=True):
    r"""
    This function enumerates (primitive) totally real field extensions of
    degree `m>1` of the totally real field F with discriminant `d \leq B`;
    optionally one can specify the first few coefficients, where the sequence ``a``
    corresponds to a polynomial by

    ::

        a[d]*x^n + ... + a[0]*x^(n-d)

    if ``length(a) = d+1``, so in particular always ``a[d] = 1``.

    .. note::

        This is guaranteed to give all primitive such fields, and
        seems in practice to give many imprimitive ones.

    INPUT:

    - ``F`` -- number field, the base field
    - ``m`` -- integer, the degree
    - ``B`` -- integer, the discriminant bound
    - ``a`` -- list (default: []), the coefficient list to begin with
    - ``verbose`` -- boolean or nonnegative integer or string (default: 0)
      give a verbose description of the computations being performed. If
      ``verbose`` is set to ``2`` or more then it outputs some extra
      information. If ``verbose`` is a string then it outputs to a file
      specified by ``verbose``
    - ``return_seqs`` -- (boolean, default False) If ``True``, then return
      the polynomials as sequences (for easier exporting to a file). This
      also returns a list of four numbers, as explained in the OUTPUT
      section below.
    - ``return_pari_objects`` -- (boolean, default: True) if
      both ``return_seqs`` and ``return_pari_objects`` are ``False`` then
      it returns the elements as Sage objects; otherwise it returns pari
      objects.

    OUTPUT:

    - the list of fields with entries ``[d,fabs,f]``, where ``d`` is the
      discriminant, ``fabs`` is an absolute defining polynomial, and ``f``
      is a defining polynomial relative to ``F``, sorted by discriminant.

    - if ``return_seqs`` is ``True``, then the first field of the list is
      a list containing the count of four items as explained below

      - the first entry gives the number of polynomials tested
      - the second entry gives the number of polynomials with its
        discriminant having a large enough square divisor
      - the third entry is the number of irreducible polynomials
      - the fourth entry is the number of irreducible polynomials with
        discriminant at most ``B``

    EXAMPLES::

        sage: ZZx = ZZ['x']
        sage: F.<t> = NumberField(x^2-2)
        sage: enumerate_totallyreal_fields_rel(F, 1, 2000)
        [[1, [-2, 0, 1], xF - 1]]
        sage: enumerate_totallyreal_fields_rel(F, 2, 2000)
        [[1600, x^4 - 6*x^2 + 4, xF^2 + xF - 1]]
        sage: enumerate_totallyreal_fields_rel(F, 2, 2000, return_seqs=True)
        [[9, 6, 5, 0], [[1600, [4, 0, -6, 0, 1], [-1, 1, 1]]]]

    TESTS:

    Each of the outputs must be elements of Sage if ``return_pari_objects``
    is set to ``False``::

        sage: enumerate_totallyreal_fields_rel(F, 2, 2000)[0][1].parent()
        Interface to the PARI C library
        sage: enumerate_totallyreal_fields_rel(F, 2, 2000, return_pari_objects=False)[0][0].parent()
        Integer Ring
        sage: enumerate_totallyreal_fields_rel(F, 2, 2000, return_pari_objects=False)[0][1].parent()
        Univariate Polynomial Ring in x over Rational Field
        sage: enumerate_totallyreal_fields_rel(F, 2, 2000, return_pari_objects=False)[0][2].parent()
        Univariate Polynomial Ring in xF over Number Field in t with defining polynomial x^2 - 2
        sage: enumerate_totallyreal_fields_rel(F, 2, 2000, return_seqs=True)[1][0][1][0].parent()
        Rational Field

    AUTHORS:

    - John Voight (2007-11-01)
    """

    if not isinstance(m, Integer):
        try:
            m = Integer(m)
        except TypeError:
            raise TypeError("cannot coerce m (= %s) to an integer" % m)
    if (m < 1):
        raise ValueError("m must be at least 1.")

    n = F.degree()*m

    # Initialize
    S = {}        # dictionary of the form {(d, fabs): f, ...}
    dB_odlyzko = odlyzko_bound_totallyreal(n)
    dB = math.ceil(40000*dB_odlyzko**n)
    counts = [0,0,0,0]

    # Trivial case
    if m == 1:
        g = pari(F.defining_polynomial()).polrecip().Vec()
        if return_seqs:
            return [[0,0,0,0], [1, [-1, 1], g]]
        elif return_pari_objects:
            return [[1, g, pari('xF-1')]]
        else:
            Px = PolynomialRing(QQ, 'xF')
            return [[ZZ(1), [QQ(_) for _ in g], Px.gen()-1]]

    if verbose:
        saveout = sys.stdout
        if isinstance(verbose, str):
            fsock = open(verbose, 'w')
            sys.stdout = fsock
        # Else, print to screen
    f_out = [0]*m + [1]
    T = tr_data_rel(F,m,B,a)
    if verbose == 2:
        T.incr(f_out,verbose)
    else:
        T.incr(f_out)

    Fx = PolynomialRing(F, 'xF')

    nfF = pari(str(F.defining_polynomial()).replace('x', str(F.primitive_element()) ) )
    parit = pari(str(F.primitive_element()))

    while f_out[m] != 0:
        counts[0] += 1
        if verbose:
            print "==>", f_out,

        f_str = ''
        for i in range(len(f_out)):
            f_str += '(' + str(f_out[i]) + ')*x^' + str(i)
            if i < len(f_out)-1:
                f_str += '+'
        nf = pari(f_str)
        if nf.poldegree('t') == 0:
            nf = nf.subst('x', 'x-t')
        nf = nf.polresultant(nfF, parit)
        d = nf.poldisc()
        #counts[0] += 1
        if d > 0 and nf.polsturm() == n:
            da = int_has_small_square_divisor(Integer(d))
            if d > dB or d <= B*da:
                counts[1] += 1
                if nf.polisirreducible():
                    counts[2] += 1
                    [zk,d] = nf.nfbasis_d()

                    if d <= B:
                        if verbose:
                            print "has discriminant", d,

                        # Find a minimal lattice element
                        counts[3] += 1
                        ng = pari([nf,zk]).polredabs()

                        # Check if K is contained in the list.
                        if (d, ng) in S:
                            if verbose:
                                print "but is not new"
                        else:
                            if verbose:
                                print "and is new!"
                            S[(d, ng)] = Fx(f_out)
                    else:
                        if verbose:
                            print "has discriminant", abs(d), "> B"
                else:
                    if verbose:
                        print "is not absolutely irreducible"
            else:
                if verbose:
                    print "has discriminant", abs(d), "with no large enough square divisor"
        else:
            if verbose:
                if d == 0:
                    print "is not squarefree"
                else:
                    print "is not totally real"
        if verbose == 2:
            T.incr(f_out,verbose=verbose)
        else:
            T.incr(f_out)

    # In the application of Smyth's theorem above, we exclude finitely
    # many possibilities which we must now throw back in.
    if m == 2:
        if Fx([-1,1,1]).is_irreducible():
            K = F.extension(Fx([-1,1,1]), 'tK')
            Kabs = K.absolute_field('tKabs')
            Kabs_pari = pari(Kabs.defining_polynomial())
            d = K.absolute_discriminant()
            if abs(d) <= B:
                ng = Kabs_pari.polredabs()
                S[(d, ng)] = Fx([-1,1,1])
        elif F.degree() == 2:
            for ff in [[1,-7,13,-7,1],[1,-8,14,-7,1]]:
                f = Fx(ff).factor()[0][0]
                K = F.extension(f, 'tK')
                Kabs = K.absolute_field('tKabs')
                Kabs_pari = pari(Kabs.defining_polynomial())
                d = K.absolute_discriminant()
                if abs(d) <= B:
                    ng = Kabs_pari.polredabs()
                    S[(d, ng)] = f
    elif m == 3:
        if Fx([-1,6,-5,1]).is_irreducible():
            K = F.extension(Fx([-1,6,-5,1]), 'tK')
            Kabs = K.absolute_field('tKabs')
            Kabs_pari = pari(Kabs.defining_polynomial())
            d = K.absolute_discriminant()
            if abs(d) <= B:
                ng = Kabs_pari.polredabs()
                S[(d, ng)] = Fx([-1,6,-5,1])

    # Convert S to a sorted list of triples [d, fabs, f], taking care
    # to use cmp() and not the comparison operators on PARI polynomials.
    S = [[s[0], s[1], t] for s, t in S.items()]
    S.sort(cmp=lambda x, y: cmp(x[0], y[0]) or cmp(x[1], y[1]))

    # Now check for isomorphic fields
    weed_fields(S)

    # Output.
    if verbose:
        print "="*80
        print "Polynomials tested: {}".format(counts[0])
        print ( "Polynomials with discriminant with large enough square"
                " divisor: {}".format(counts[1]))
        print "Irreducible polynomials: {}".format(counts[2])
        print "Polynomials with nfdisc <= B: {}".format(counts[3])
        for i in range(len(S)):
            print S[i]
        if isinstance(verbose, str):
            fsock.close()
        sys.stdout = saveout

    # Make sure to return elements that belong to Sage
    if return_seqs:
        return [[ZZ(x) for x in counts],
                [[s[0], [QQ(x) for x in s[1].polrecip().Vec()], s[2].coefficients(sparse=False)]
                 for s in S]
               ]
    elif return_pari_objects:
        return S
    else:
        Px = PolynomialRing(QQ, 'x')
        return [[s[0], Px([QQ(_) for _ in s[1].list()]), s[2]] for s in S]
Пример #4
0
def enumerate_totallyreal_fields_rel(F, m, B, a=[], verbose=0, return_seqs=False):
    r"""
    This function enumerates (primitive) totally real field extensions of
    degree `m>1` of the totally real field F with discriminant `d \leq B`; 
    optionally one can specify the first few coefficients, where the sequence ``a``
    corresponds to a polynomial by
    
    ::
    
        a[d]*x^n + ... + a[0]*x^(n-d)
        
    if ``length(a) = d+1``, so in particular always ``a[d] = 1``.
    If verbose == 1 (or 2), then print to the screen (really) verbosely; if
    verbose is a string, then print verbosely to the file specified by verbose.
    If return_seqs, then return the polynomials as sequences (for easier
    exporting to a file).

    NOTE:
    This is guaranteed to give all primitive such fields, and 
    seems in practice to give many imprimitive ones.

    INPUT:
    
    - ``F`` -- number field, the base field
    - ``m`` -- integer, the degree
    - ``B`` -- integer, the discriminant bound
    - ``a`` -- list (default: []), the coefficient list to begin with
    - ``verbose`` -- boolean or string (default: 0)
    - ``return_seqs`` -- boolean (default: False)

    OUTPUT:
    
    the list of fields with entries [d,fabs,f], where
    d is the discriminant, fabs is an absolute defining polynomial,
    and f is a defining polynomial relative to F,
    sorted by discriminant.

    EXAMPLES::
    
        sage: ZZx = ZZ['x']
        sage: F.<t> = NumberField(x^2-2)
        sage: enumerate_totallyreal_fields_rel(F, 2, 2000)
        [[1600, x^4 - 6*x^2 + 4, xF^2 + xF - 1]]

    AUTHORS:
    
    - John Voight (2007-11-01)
    """

    if not isinstance(m, Integer):
        try:
            m = Integer(m)
        except TypeError:
            raise TypeError, "cannot coerce m (= %s) to an integer" % m
    if m < 1:
        raise ValueError, "m must be at least 1."

    n = F.degree() * m

    # Initialize
    T = tr_data_rel(F, m, B, a)
    S = []
    Srel = []
    dB_odlyzko = odlyzko_bound_totallyreal(n)
    dB = math.ceil(40000 * dB_odlyzko ** n)
    counts = [0, 0, 0, 0]

    # Trivial case
    if m == 1:
        g = pari(F.defining_polynomial()).reverse().Vec()
        if return_seqs:
            return [[0, 0, 0, 0], [1, g, [-1, 1]]]
        else:
            return [[1, pari("x-1"), g]]

    if verbose:
        saveout = sys.stdout
        if type(verbose) == str:
            fsock = open(verbose, "w")
            sys.stdout = fsock
        # Else, print to screen
    f_out = [0] * m + [1]
    if verbose == 2:
        T.incr(f_out, verbose)
    else:
        T.incr(f_out)

    Fx = PolynomialRing(F, "xF")

    nfF = pari(str(F.defining_polynomial()).replace("x", str(F.primitive_element())))
    parit = pari(str(F.primitive_element()))

    while f_out[m] <> 0:
        counts[0] += 1
        if verbose:
            print "==>", f_out,

        f_str = ""
        for i in range(len(f_out)):
            f_str += "(" + str(f_out[i]) + ")*x^" + str(i)
            if i < len(f_out) - 1:
                f_str += "+"
        nf = pari(f_str)
        if nf.poldegree("t") == 0:
            nf = nf.subst("x", "x-t")
        nf = nf.polresultant(nfF, parit)
        d = nf.poldisc()
        counts[0] += 1
        if d > 0 and nf.polsturm_full() == n:
            da = int_has_small_square_divisor(Integer(d))
            if d > dB or d <= B * da:
                counts[1] += 1
                if nf.polisirreducible():
                    counts[2] += 1
                    [zk, d] = nf.nfbasis_d()

                    if d <= B:
                        if verbose:
                            print "has discriminant", d,

                        # Find a minimal lattice element
                        counts[3] += 1
                        ng = pari([nf, zk]).polredabs()

                        # Check if K is contained in the list.
                        found = False
                        ind = bisect.bisect_left(S, [d, ng])
                        while ind < len(S) and S[ind][0] == d:
                            if S[ind][1] == ng:
                                if verbose:
                                    print "but is not new"
                                found = True
                                break
                            ind += 1
                        if not found:
                            if verbose:
                                print "and is new!"
                            S.insert(ind, [d, ng])
                            Srel.insert(ind, Fx(f_out))
                    else:
                        if verbose:
                            print "has discriminant", abs(d), "> B"
                else:
                    if verbose:
                        print "is not absolutely irreducible"
            else:
                if verbose:
                    print "has discriminant", abs(d), "with no large enough square divisor"
        else:
            if verbose:
                if d == 0:
                    print "is not squarefree"
                else:
                    print "is not totally real"
        if verbose == 2:
            T.incr(f_out, verbose=verbose)
        else:
            T.incr(f_out)

    # In the application of Smyth's theorem above, we exclude finitely
    # many possibilities which we must now throw back in.
    if m == 2:
        if Fx([-1, 1, 1]).is_irreducible():
            K = F.extension(Fx([-1, 1, 1]), "tK")
            Kabs = K.absolute_field("tKabs")
            Kabs_pari = pari(Kabs.defining_polynomial())
            d = K.absolute_discriminant()
            if abs(d) <= B:
                ng = Kabs_pari.polredabs()
                ind = bisect.bisect_left(S, [d, ng])
                S.insert(ind, [d, ng])
                Srel.insert(ind, Fx([-1, 1, 1]))
        elif F.degree() == 2:
            for ff in [[1, -7, 13, -7, 1], [1, -8, 14, -7, 1]]:
                f = Fx(ff).factor()[0][0]
                K = F.extension(f, "tK")
                Kabs = K.absolute_field("tKabs")
                Kabs_pari = pari(Kabs.defining_polynomial())
                d = K.absolute_discriminant()
                if abs(d) <= B:
                    ng = Kabs_pari.polredabs()
                    ind = bisect.bisect_left(S, [d, ng])
                    S.insert(ind, [d, ng])
                    Srel.insert(ind, f)
    elif m == 3:
        if Fx([-1, 6, -5, 1]).is_irreducible():
            K = F.extension(Fx([-1, 6, -5, 1]), "tK")
            Kabs = K.absolute_field("tKabs")
            Kabs_pari = pari(Kabs.defining_polynomial())
            d = K.absolute_discriminant()
            if abs(d) <= B:
                ng = Kabs_pari.polredabs()
                ind = bisect.bisect_left(S, [d, ng])
                S.insert(ind, [d, ng])
                Srel.insert(ind, Fx([-1, 6, -5, 1]))

    # Now check for isomorphic fields
    S = [[S[i][0], S[i][1], Srel[i]] for i in range(len(S))]
    weed_fields(S)

    # Output.
    if verbose:
        print "=" * 80
        print "Polynomials tested:", counts[0]
        print "Irreducible polynomials:", counts[1]
        print "Polynomials with nfdisc <= B:", counts[2]
        for i in range(len(S)):
            print S[i]
        if type(verbose) == str:
            fsock.close()
        sys.stdout = saveout

    if return_seqs:
        return [counts, [[s[0], s[1].reverse().Vec(), s[2].coeffs()] for s in S]]
    else:
        return S