示例#1
0
    def incr(self, f_out, verbose=False, haltk=0):
        r"""
        This function 'increments' the totally real data to the next
        value which satisfies the bounds essentially given by Rolle's
        theorem, and returns the next polynomial in the sequence
        f_out.

        The default or usual case just increments the constant
        coefficient; then inductively, if this is outside of the
        bounds we increment the next higher coefficient, and so on.

        If there are no more coefficients to be had, returns the zero
        polynomial.

        INPUT:

        - ``f_out`` -- an integer sequence, to be written with the
          coefficients of the next polynomial
        - ``verbose`` -- boolean to print verbosely computational details
        - ``haltk`` -- integer, the level at which to halt the inductive
          coefficient bounds

        OUTPUT:

        the successor polynomial as a coefficient list.

        EXAMPLES:

        As this function is heavily used internally by the various enumeration
        routines, there is no separate test::

            sage: pass # not tested
        """

        import numpy

        m = self.m
        n = self.n
        k = self.k
        d = self.d

        # If k == -1, we have a full polynomial, so we add 1 to the constant coefficient.
        if k == -1:
            if len(self.amaxvals[0]) > 0 and self.amaxvals[0]:
                self.a[0] = self.amaxvals[0].pop()
                for i in range(0,m):
                    f_out[i] = self.a[i]
                return
            else:
                if verbose:
                    print "  finished"

                # Already reached maximum, so "carry the 1" to find the next value of k.
                k += 1
                while k < m and len(self.amaxvals[k]) == 0:
                    k += 1
                if k < m:
                    self.a[k] = self.amaxvals[k].pop()
                    k -= 1

        # If we are working through an initialization routine, treat that.
        elif haltk and k == haltk-1:
            if len(self.maxvals[k]) == 0:
                k += 1
                while k <= m-1 and len(self.amaxvals[k]) == 0:
                    k += 1
                if k < m:
                    self.a[k] = self.amaxvals[k].pop()
                    k -= 1

        # If in the previous step we finished all possible values of
        # the lastmost coefficient, so we must compute bounds on the next coefficient.
        # Recall k == n-1 implies iteration is complete.
        while k < m-1:
            # maxoutflag flags a required abort along the way
            maxoutflag = False

            # Recall k == -1 means all coefficients are good to go.
            while k >= 0 and (not haltk or k >= haltk):
                if verbose:
                    print k, ":",
                    for i in range(0,self.m+1):
                        print self.a[i],
                    print ""

                if k == m-2:
                    # We only know the value of a[n-1], the trace.
                    bl = max(math.ceil(1.7719*self.n), ((self.a[m-1]**2).trace()*1./m))
                    br = 1./m*(self.a[m-1]**2).trace() + \
                           self.gamma*(1./(m**d)*self.B/self.dF)**(1./(self.n-d))
                    br = math.floor(br)

                    # Check for trivially empty.
                    if bl > br:
                        if verbose:
                            print " ", br, ">", bl
                        maxoutflag = 1
                        break

                    if verbose >= 2:
                        print "  bl, br:", bl, br

                    # Enumerate all elements of Z_F with T_2 <= br
                    T2s = []
                    trace_elts_found = False
                    for i in range(len(self.trace_elts)):
                        tre = self.trace_elts[i]
                        if tre[0] <= bl and tre[1] >= br:
                            trace_elts_found = True
                            if verbose >= 2:
                                print "  found copy!"
                            for theta in tre[2]:
                                if theta.trace() >= bl and theta.trace() <= br:
                                    T2s.append(theta)
                            break
                    if not trace_elts_found:
                        T2s = self.F._positive_integral_elements_with_trace([bl,br])
                        self.trace_elts.append([bl,br,T2s])

                    # Now ensure that T2 satisfies the correct parity condition
                    am2s = []
                    for t2 in T2s:
                        am2 = (self.a[m-1]**2-t2)/2
                        if am2.is_integral():
                            ispositive = True
                            for v in self.Foo:
                                ispositive = ispositive and v((m-1)*self.a[m-1]**2-2*m*am2) > 0
                            if ispositive:
                                am2s.append(am2)

                    if verbose >= 2:
                        print "  am2s:", am2s

                    # If none survive, break!
                    if len(am2s) == 0:
                        if verbose:
                            print "  finished"
                        maxoutflag = 1
                        break

                    self.amaxvals[m-2] = am2s
                    self.a[m-2] = self.amaxvals[m-2].pop()

                    # Initialize the second derivative.
                    self.b_lower = [-1./m*(v(self.a[m-1]) +
                                      (m-1.)*math.sqrt(v(self.a[m-1])**2 - 2.*(1+1./(m-1))*v(self.a[m-2]))) for v in self.Foo]
                    self.b_upper = [-1./m*(v(self.a[m-1]) -
                                      (m-1.)*math.sqrt(v(self.a[m-1])**2 - 2.*(1+1./(m-1))*v(self.a[m-2]))) for v in self.Foo]
                    self.beta[k] = [[self.b_lower[i], -self.Foo[i](self.a[m-1])/m, self.b_upper[i]] for i in range(d)]
                    self.gnk[k] = [0, (m-1)*self.a[m-1], m*(m-1)/2]

                    if verbose >= 2:
                        print "  betak:", self.beta[k]
                else:
                    # Compute the roots of the derivative.
                    self.gnk[k+1][0] = self.a[k+1]
                    gnk = self.gnk[k+1]
                    self.beta[k] = [numpy.roots([v(gnk[len(gnk)-1-i]) for i in range(len(gnk))]).tolist() for v in self.Foo]

                    try:
                        for i in range(d):
                            self.beta[k][i].sort()
                    except TypeError:
                        if verbose:
                            print "  betak:", self.beta[k]
                        maxoutflag = True
                        break

                    # Check for double roots
                    for i in range(len(self.beta[k][0])-1):
                        if abs(self.beta[k][0][i] - self.beta[k][0][i+1]) < 2*eps_global:
                            # This happens reasonably infrequently, so calling
                            # the Python routine should be sufficiently fast...
                            f = self.Fx(self.gnk[k+1])
                            df = self.Fx(self.gnk[k+2])
                            if gcd(f,df) != 1:
                                if verbose:
                                    print "  gnk has multiple factor!"
                                maxoutflag = True
                                break
                    if maxoutflag:
                        break

                    if k == m-3:
                        self.b_lower = [-1./m*(v(self.a[m-1]) +
                                          (m-1.)*math.sqrt(v(self.a[m-1])**2 - 2.*(1+1./(m-1))*v(self.a[m-2]))) for v in self.Foo]
                        self.b_upper = [-1./m*(v(self.a[m-1]) -
                                          (m-1.)*math.sqrt(v(self.a[m-1])**2 - 2.*(1+1./(m-1))*v(self.a[m-2]))) for v in self.Foo]
                    elif k == m-4:
                        # New bounds from Lagrange multiplier in degree 3.
                        bminmax = [lagrange_degree_3(m,v(self.a[m-1]),v(self.a[m-2]),v(self.a[m-3])) for v in self.Foo]
                        self.b_lower = [bminmax[i][0] for i in range(len(bminmax))]
                        self.b_upper = [bminmax[i][1] for i in range(len(bminmax))]

                    self.beta[k] = [[self.b_lower[i]] + self.beta[k][i] + [self.b_upper[i]] for i in range(len(self.beta[k]))]

                    if verbose >= 2:
                        print "  betak:", self.beta[k]

                    # Compute next g_(m-(k+1)), k times the formal integral of g_(m-k).
                    self.gnk[k] = [self.F.primitive_element()*0] + [self.gnk[k+1][i-1]*(k+1)/i for i in range(1,m-k+1)]
                    gnk = self.gnk[k]
                    gnks = [ [v(gnk[len(gnk)-1-i]) for i in range(len(gnk))] for v in self.Foo ]
                    gnkm1 = self.gnk[k+1]
                    gnkm1s = [ [v(gnkm1[len(gnkm1)-1-i]) for i in range(len(gnkm1))] for v in self.Foo ]
                    mk = m-(k+1)

                    if verbose >= 2:
                        print "  gnk:", self.gnk[k]
                        print "  gnks:", gnks

                    # Compute upper and lower bounds which guarantee one retains
                    # a polynomial with all real roots.
                    betak = self.beta[k]
                    akmin = [-numpy.polyval(gnks[j], betak[j][mk+1]) - \
                               abs(numpy.polyval(gnkm1s[j], betak[j][mk+1]))*eps_global for j in range(self.d)]
                    for i in range(1,(mk+1)/2+1):
                        # Use the fact that f(z) <= f(x)+|f'(x)|eps if |x-z| < eps
                        # for sufficiently small eps, f(z) = 0, and f''(z) < 0.
                        akmin = [max(akmin[j],
                                    -numpy.polyval(gnks[j], betak[j][mk+1-2*i]) - \
                                       abs(numpy.polyval(gnkm1s[j], betak[j][mk+1-2*i])*eps_global)) for j in range(self.d)]

                    akmax = [-numpy.polyval(gnks[j], betak[j][mk]) + \
                               abs(numpy.polyval(gnkm1s[j], betak[j][mk]))*eps_global for j in range(self.d)]
                    for i in range(1,mk/2+1):
                        akmax = [min(akmax[j],
                                    -numpy.polyval(gnks[j], betak[j][mk-2*i]) + \
                                       abs(numpy.polyval(gnkm1s[j], betak[j][mk-2*i])*eps_global)) for j in range(self.d)]

                    if verbose >= 2:
                        print "  akmin:", akmin
                        print "  akmax:", akmax

                    for i in range(self.d):
                        if akmin[i] > akmax[i]:
                            if verbose:
                                print " ", akmin[i], ">", akmax[i]
                            maxoutflag = 1
                            break
                    if maxoutflag:
                        break

                    self.amaxvals[k] = integral_elements_in_box(self.F, [[akmin[i],akmax[i]] for i in range(d)])
                    if k == 0:
                        a0s = [0, -sum([self.a[i] for i in range(1,m+1)]),
                                  -sum([self.a[i]*(-1)**i for i in range(1,m+1)]),
                                  -sum([self.a[i]*2**i for i in range(1,m+1)]),
                                  -sum([self.a[i]*(-2)**i for i in range(1,m+1)])]
                        for a0 in a0s:
                            try:
                                self.amaxvals[0].remove(a0)
                            except Exception:
                                pass

                    if verbose:
                        print "  amaxvals[k]:", self.amaxvals[k]
                    if len(self.amaxvals[k]) == 0:
                        if verbose:
                            print "  finished"
                        maxoutflag = True
                        break
                    self.a[k] = self.amaxvals[k].pop()

                self.k -= 1
                k -= 1

            if not maxoutflag:
                self.k = k
                for i in range(m):
                    f_out[i] = self.a[i]
                return
            else:
                k += 1
                while k < m and len(self.amaxvals[k]) == 0:
                    k += 1
                if k < m:
                    self.a[k] = self.amaxvals[k].pop()
                    k -= 1

        # k == n-1, so iteration is complete; return the zero polynomial (of degree n+1).
        self.k = k
        f_out[m] = 0
        return
示例#2
0
    def incr(self, f_out, verbose=False, haltk=0):
        r"""
        This function 'increments' the totally real data to the next
        value which satisfies the bounds essentially given by Rolle's
        theorem, and returns the next polynomial in the sequence
        f_out.

        The default or usual case just increments the constant
        coefficient; then inductively, if this is outside of the
        bounds we increment the next higher coefficient, and so on.

        If there are no more coefficients to be had, returns the zero
        polynomial.

        INPUT:

        - ``f_out`` -- an integer sequence, to be written with the
          coefficients of the next polynomial
        - ``verbose`` -- boolean or nonnegative integer (default: False)
          print verbosely computational details. It prints extra
          information if ``verbose`` is set to ``2`` or more
        - ``haltk`` -- integer, the level at which to halt the inductive
          coefficient bounds

        OUTPUT:

        the successor polynomial as a coefficient list.
        """

        import numpy

        m = self.m
        n = self.n
        k = self.k
        d = self.d

        # If k == -1, we have a full polynomial, so we add 1 to the constant coefficient.
        if k == -1:
            if len(self.amaxvals[0]) > 0 and self.amaxvals[0]:
                self.a[0] = self.amaxvals[0].pop()
                for i in range(0,m):
                    f_out[i] = self.a[i]
                return
            else:
                if verbose:
                    print "  finished"

                # Already reached maximum, so "carry the 1" to find the next value of k.
                k += 1
                while k < m and len(self.amaxvals[k]) == 0:
                    k += 1
                if k < m:
                    self.a[k] = self.amaxvals[k].pop()
                    k -= 1

        # If we are working through an initialization routine, treat that.
        elif haltk and k == haltk-1:
            if len(self.maxvals[k]) == 0:
                k += 1
                while k <= m-1 and len(self.amaxvals[k]) == 0:
                    k += 1
                if k < m:
                    self.a[k] = self.amaxvals[k].pop()
                    k -= 1

        # If in the previous step we finished all possible values of
        # the lastmost coefficient, so we must compute bounds on the next coefficient.
        # Recall k == n-1 implies iteration is complete.
        while k < m-1:
            # maxoutflag flags a required abort along the way
            maxoutflag = False

            # Recall k == -1 means all coefficients are good to go.
            while k >= 0 and (not haltk or k >= haltk):
                if verbose:
                    print k, ":",
                    for i in range(0,self.m+1):
                        print self.a[i],
                    print ""

                if k == m-2:
                    # We only know the value of a[n-1], the trace.
                    bl = max(math.ceil(1.7719*self.n), ((self.a[m-1]**2).trace()*1./m))
                    br = 1./m*(self.a[m-1]**2).trace() + \
                           self.gamma*(1./(m**d)*self.B/self.dF)**(1./(self.n-d))
                    br = math.floor(br)

                    # Check for trivially empty.
                    if bl > br:
                        if verbose:
                            print " ", br, ">", bl
                        maxoutflag = 1
                        break

                    if verbose >= 2:
                        print "  bl, br:", bl, br

                    # Enumerate all elements of Z_F with T_2 <= br
                    T2s = []
                    trace_elts_found = False
                    for i in range(len(self.trace_elts)):
                        tre = self.trace_elts[i]
                        if tre[0] <= bl and tre[1] >= br:
                            trace_elts_found = True
                            if verbose >= 2:
                                print "  found copy!"
                            for theta in tre[2]:
                                if theta.trace() >= bl and theta.trace() <= br:
                                    T2s.append(theta)
                            break
                    if not trace_elts_found:
                        T2s = self.F._positive_integral_elements_with_trace([bl,br])
                        self.trace_elts.append([bl,br,T2s])

                    # Now ensure that T2 satisfies the correct parity condition
                    am2s = []
                    for t2 in T2s:
                        am2 = (self.a[m-1]**2-t2)/2
                        if am2.is_integral():
                            ispositive = True
                            for v in self.Foo:
                                ispositive = ispositive and v((m-1)*self.a[m-1]**2-2*m*am2) > 0
                            if ispositive:
                                am2s.append(am2)

                    if verbose >= 2:
                        print "  am2s:", am2s

                    # If none survive, break!
                    if len(am2s) == 0:
                        if verbose:
                            print "  finished"
                        maxoutflag = 1
                        break

                    self.amaxvals[m-2] = am2s
                    self.a[m-2] = self.amaxvals[m-2].pop()

                    # Initialize the second derivative.
                    self.b_lower = [-1./m*(v(self.a[m-1]) +
                                      (m-1.)*math.sqrt(v(self.a[m-1])**2 - 2.*(1+1./(m-1))*v(self.a[m-2]))) for v in self.Foo]
                    self.b_upper = [-1./m*(v(self.a[m-1]) -
                                      (m-1.)*math.sqrt(v(self.a[m-1])**2 - 2.*(1+1./(m-1))*v(self.a[m-2]))) for v in self.Foo]
                    self.beta[k] = [[self.b_lower[i], -self.Foo[i](self.a[m-1])/m, self.b_upper[i]] for i in range(d)]
                    self.gnk[k] = [0, (m-1)*self.a[m-1], m*(m-1)/2]

                    if verbose >= 2:
                        print "  betak:", self.beta[k]
                else:
                    # Compute the roots of the derivative.
                    self.gnk[k+1][0] = self.a[k+1]
                    gnk = self.gnk[k+1]
                    self.beta[k] = [numpy.roots([v(gnk[len(gnk)-1-i]) for i in range(len(gnk))]).tolist() for v in self.Foo]

                    try:
                        for i in range(d):
                            self.beta[k][i].sort()
                    except TypeError:
                        if verbose:
                            print "  betak:", self.beta[k]
                        maxoutflag = True
                        break

                    # Check for double roots
                    for i in range(len(self.beta[k][0])-1):
                        if abs(self.beta[k][0][i] - self.beta[k][0][i+1]) < 2*eps_global:
                            # This happens reasonably infrequently, so calling
                            # the Python routine should be sufficiently fast...
                            f = self.Fx(self.gnk[k+1])
                            df = self.Fx(self.gnk[k+2])
                            if gcd(f,df) != 1:
                                if verbose:
                                    print "  gnk has multiple factor!"
                                maxoutflag = True
                                break
                    if maxoutflag:
                        break

                    if k == m-3:
                        self.b_lower = [-1./m*(v(self.a[m-1]) +
                                          (m-1.)*math.sqrt(v(self.a[m-1])**2 - 2.*(1+1./(m-1))*v(self.a[m-2]))) for v in self.Foo]
                        self.b_upper = [-1./m*(v(self.a[m-1]) -
                                          (m-1.)*math.sqrt(v(self.a[m-1])**2 - 2.*(1+1./(m-1))*v(self.a[m-2]))) for v in self.Foo]
                    elif k == m-4:
                        # New bounds from Lagrange multiplier in degree 3.
                        bminmax = [lagrange_degree_3(m,v(self.a[m-1]),v(self.a[m-2]),v(self.a[m-3])) for v in self.Foo]
                        self.b_lower = [bminmax[i][0] for i in range(len(bminmax))]
                        self.b_upper = [bminmax[i][1] for i in range(len(bminmax))]

                    self.beta[k] = [[self.b_lower[i]] + self.beta[k][i] + [self.b_upper[i]] for i in range(len(self.beta[k]))]

                    if verbose >= 2:
                        print "  betak:", self.beta[k]

                    # Compute next g_(m-(k+1)), k times the formal integral of g_(m-k).
                    self.gnk[k] = [self.F.primitive_element()*0] + [self.gnk[k+1][i-1]*(k+1)/i for i in range(1,m-k+1)]
                    gnk = self.gnk[k]
                    gnks = [ [v(gnk[len(gnk)-1-i]) for i in range(len(gnk))] for v in self.Foo ]
                    gnkm1 = self.gnk[k+1]
                    gnkm1s = [ [v(gnkm1[len(gnkm1)-1-i]) for i in range(len(gnkm1))] for v in self.Foo ]
                    mk = m-(k+1)

                    if verbose >= 2:
                        print "  gnk:", self.gnk[k]
                        print "  gnks:", gnks

                    # Compute upper and lower bounds which guarantee one retains
                    # a polynomial with all real roots.
                    betak = self.beta[k]
                    akmin = [-numpy.polyval(gnks[j], betak[j][mk+1]) - \
                               abs(numpy.polyval(gnkm1s[j], betak[j][mk+1]))*eps_global for j in range(self.d)]
                    for i in range(1,(mk+1)//2+1):
                        # Use the fact that f(z) <= f(x)+|f'(x)|eps if |x-z| < eps
                        # for sufficiently small eps, f(z) = 0, and f''(z) < 0.
                        akmin = [max(akmin[j],
                                    -numpy.polyval(gnks[j], betak[j][mk+1-2*i]) - \
                                       abs(numpy.polyval(gnkm1s[j], betak[j][mk+1-2*i])*eps_global)) for j in range(self.d)]

                    akmax = [-numpy.polyval(gnks[j], betak[j][mk]) + \
                               abs(numpy.polyval(gnkm1s[j], betak[j][mk]))*eps_global for j in range(self.d)]
                    for i in range(1,mk//2+1):
                        akmax = [min(akmax[j],
                                    -numpy.polyval(gnks[j], betak[j][mk-2*i]) + \
                                       abs(numpy.polyval(gnkm1s[j], betak[j][mk-2*i])*eps_global)) for j in range(self.d)]

                    if verbose >= 2:
                        print "  akmin:", akmin
                        print "  akmax:", akmax

                    for i in range(self.d):
                        if akmin[i] > akmax[i]:
                            if verbose:
                                print " ", akmin[i], ">", akmax[i]
                            maxoutflag = 1
                            break
                    if maxoutflag:
                        break

                    self.amaxvals[k] = integral_elements_in_box(self.F, [[akmin[i],akmax[i]] for i in range(d)])
                    if k == 0:
                        a0s = [0, -sum([self.a[i] for i in range(1,m+1)]),
                                  -sum([self.a[i]*(-1)**i for i in range(1,m+1)]),
                                  -sum([self.a[i]*2**i for i in range(1,m+1)]),
                                  -sum([self.a[i]*(-2)**i for i in range(1,m+1)])]
                        for a0 in a0s:
                            try:
                                self.amaxvals[0].remove(a0)
                            except Exception:
                                pass

                    if verbose:
                        print "  amaxvals[k]:", self.amaxvals[k]
                    if len(self.amaxvals[k]) == 0:
                        if verbose:
                            print "  finished"
                        maxoutflag = True
                        break
                    self.a[k] = self.amaxvals[k].pop()

                self.k -= 1
                k -= 1

            if not maxoutflag:
                self.k = k
                for i in range(m):
                    f_out[i] = self.a[i]
                return
            else:
                k += 1
                while k < m and len(self.amaxvals[k]) == 0:
                    k += 1
                if k < m:
                    self.a[k] = self.amaxvals[k].pop()
                    k -= 1

        # k == n-1, so iteration is complete; return the zero polynomial (of degree n+1).
        self.k = k
        f_out[m] = 0
        return
示例#3
0
    def __init__(self, F, m, B, a=None):
        r"""
        Initialization routine (constructor).

        INPUT:

        - ``F`` -- number field, the base field
        - ``m`` -- integer, the relative degree
        - ``B`` -- integer, the discriminant bound
        - ``a`` -- list (default: []), the coefficient list to begin with,
          corresponding to ``a[len(a)]*x^n + ... + a[0]x^(n-len(a))``.

        OUTPUT:

        the data initialized to begin enumeration of totally real fields
        with base field F, degree n, discriminant bounded by B, and starting
        with coefficients a.

        EXAMPLES::

            sage: F.<t> = NumberField(x^2-2)
            sage: T = sage.rings.number_field.totallyreal_rel.tr_data_rel(F, 2, 2000)
        """
        if a is None:  # don't make the stupid noob mistake of putting a=[]
            a = []     # in the function signature above.

        # Initialize constants.
        self.m = m
        d = F.degree()
        self.d = d
        self.n = m*d
        self.B = B
        self.gamma = hermite_constant(self.n-self.d)

        self.F = F
        self.Z_F = F.maximal_order()
        self.Foo = F.real_embeddings()
        self.dF = abs(F.disc())
        self.Fx = PolynomialRing(F, 'xF')

        self.beta = [[]]*m
        self.gnk = [[]]*m

        self.trace_elts = []

        Z_Fbasis = self.Z_F.basis()

        # Initialize variables.
        if a == []:
            # No starting input, all polynomials will be found; initialize to zero.
            self.a = [0]*m + [1]
            self.amaxvals = [[]]*m
            anm1s = [[i] for i in range(0,m//2+1)]
            for i in range(1,self.d):
                for j in range(len(anm1s)):
                    anm1s[j] = [ anm1s[j] + [i] for i in range(m)]
                anm1s = sum(anm1s, [])
            anm1s = [sum([Z_Fbasis[i]*a[i] for i in range(self.d)]) for a in anm1s]
            # Minimize trace in class.
            import numpy
            for i in range(len(anm1s)):
                Q = [ [ v(m*x) for v in self.Foo] + [0] for x in Z_Fbasis] + [[v(anm1s[i]) for v in self.Foo] + [10**6]]
                pari_string = '['+';'.join([','.join(["%s"%ii for ii in row]) for row in zip(*Q)])+']'
                adj = pari(pari_string).qflll()[self.d]
                anm1s[i] += sum([m*Z_Fbasis[ii]*int(adj[ii])//int(adj[self.d]) for ii in range(self.d)])

            self.amaxvals[m-1] = anm1s
            self.a[m-1] = self.amaxvals[m-1].pop()
            self.k = m-2

            bl = math.ceil(1.7719*self.n)
            br = max([1./m*(am1**2).trace() + \
                            self.gamma*(1./(m**d)*self.B/self.dF)**(1./(self.n-d)) for am1 in anm1s])
            br = math.floor(br)
            T2s = self.F._positive_integral_elements_with_trace([bl,br])
            self.trace_elts.append([bl,br,T2s])

        elif len(a) <= m+1:
            # First few coefficients have been specified.
            # The value of k is the largest index of the coefficients of a which is
            # currently unknown; e.g., if k == -1, then we can iterate
            # over polynomials, and if k == n-1, then we have finished iterating.
            if a[len(a)-1] != 1:
                raise ValueError, "a[len(a)-1](=%s) must be 1 so polynomial is monic"%a[len(a)-1]

            raise NotImplementedError, "These have not been checked."

            k = m-len(a)
            self.k = k
            a = [0]*(k+1) + a
            self.amaxvals = [[]]*m
            for i in range(0,n+1):
                self.a[i] = a[i]

            # Bounds come from an application of Lagrange multipliers in degrees 2,3.
            self.b_lower = [-1./m*(v(self.a[m-1]) +
                              (m-1.)*math.sqrt(v(self.a[m-1])**2 - 2.*(1+1./(m-1))*v(self.a[m-2]))) for v in self.Foo]
            self.b_upper = [-1./m*(v(self.a[m-1]) -
                              (m-1.)*math.sqrt(v(self.a[m-1])**2 - 2.*(1+1./(m-1))*v(self.a[m-2]))) for v in self.Foo]
            if k < m-2:
                bminmax = [lagrange_degree_3(n,v(self.a[m-1]),v(self.a[m-2]),v(self.a[m-3])) for v in self.Foo]
                self.b_lower = bminmax[0]
                self.b_upper = bminmax[1]

            # Annoying, but must reverse coefficients for numpy.
            gnk = [binomial(j,k+2)*a[j] for j in range(k+2,n+1)]
            self.beta[k+1] = [[self.b_lower] + numpy.roots([v(gnk[i]) for i in range(len(gnk))].reverse()).tolist().sort() + [self.b_upper] for v in self.Foo]

            # Now to really initialize gnk.
            self.gnk[k+1] = [[0] + [binomial(j,k+1)*v(a[j]) for j in range (k+2,m+1)] for v in self.Foo]
        else:
            # Bad input!
            raise ValueError, "a has length %s > m+1"%len(a)
示例#4
0
    def __init__(self, F, m, B, a=None):
        r"""
        Initialization routine (constructor).

        INPUT:

        - ``F`` -- number field, the base field
        - ``m`` -- integer, the relative degree
        - ``B`` -- integer, the discriminant bound
        - ``a`` -- list (default: []), the coefficient list to begin with,
          corresponding to ``a[len(a)]*x^n + ... + a[0]x^(n-len(a))``.

        OUTPUT:

        the data initialized to begin enumeration of totally real fields
        with base field F, degree n, discriminant bounded by B, and starting
        with coefficients a.

        EXAMPLES::

            sage: F.<t> = NumberField(x^2-2)
            sage: T = sage.rings.number_field.totallyreal_rel.tr_data_rel(F, 2, 2000)
        """
        if a is None:  # don't make the stupid noob mistake of putting a=[]
            a = []     # in the function signature above.

        # Initialize constants.
        self.m = m
        d = F.degree()
        self.d = d
        self.n = m*d
        self.B = B
        self.gamma = hermite_constant(self.n-self.d)

        self.F = F
        self.Z_F = F.maximal_order()
        self.Foo = F.real_embeddings()
        self.dF = abs(F.disc())
        self.Fx = PolynomialRing(F, 'xF')

        self.beta = [[]]*m
        self.gnk = [[]]*m

        self.trace_elts = []

        Z_Fbasis = self.Z_F.basis()

        # Initialize variables.
        if a == []:
            # No starting input, all polynomials will be found; initialize to zero.
            self.a = [0]*m + [1]
            self.amaxvals = [[]]*m
            anm1s = [[i] for i in range(0,m//2+1)]
            for i in range(1,self.d):
                for j in range(len(anm1s)):
                    anm1s[j] = [ anm1s[j] + [i] for i in range(m)]
                anm1s = sum(anm1s, [])
            anm1s = [sum([Z_Fbasis[i]*a[i] for i in range(self.d)]) for a in anm1s]
            # Minimize trace in class.
            import numpy
            for i in range(len(anm1s)):
                Q = [ [ v(m*x) for v in self.Foo] + [0] for x in Z_Fbasis] + [[v(anm1s[i]) for v in self.Foo] + [10**6]]
                pari_string = '['+';'.join([','.join(["%s"%ii for ii in row]) for row in zip(*Q)])+']'
                adj = pari(pari_string).qflll()[self.d]
                anm1s[i] += sum([m*Z_Fbasis[ii]*int(adj[ii])//int(adj[self.d]) for ii in range(self.d)])

            self.amaxvals[m-1] = anm1s
            self.a[m-1] = self.amaxvals[m-1].pop()
            self.k = m-2

            bl = math.ceil(1.7719*self.n)
            br = max([1./m*(am1**2).trace() + \
                            self.gamma*(1./(m**d)*self.B/self.dF)**(1./(self.n-d)) for am1 in anm1s])
            br = math.floor(br)
            T2s = self.F._positive_integral_elements_with_trace([bl,br])
            self.trace_elts.append([bl,br,T2s])

        elif len(a) <= m+1:
            # First few coefficients have been specified.
            # The value of k is the largest index of the coefficients of a which is
            # currently unknown; e.g., if k == -1, then we can iterate
            # over polynomials, and if k == n-1, then we have finished iterating.
            if a[len(a)-1] != 1:
                raise ValueError("a[len(a)-1](=%s) must be 1 so polynomial is monic"%a[len(a)-1])

            raise NotImplementedError("These have not been checked.")

            k = m-len(a)
            self.k = k
            a = [0]*(k+1) + a
            self.amaxvals = [[]]*m
            for i in range(0,n+1):
                self.a[i] = a[i]

            # Bounds come from an application of Lagrange multipliers in degrees 2,3.
            self.b_lower = [-1./m*(v(self.a[m-1]) +
                              (m-1.)*math.sqrt(v(self.a[m-1])**2 - 2.*(1+1./(m-1))*v(self.a[m-2]))) for v in self.Foo]
            self.b_upper = [-1./m*(v(self.a[m-1]) -
                              (m-1.)*math.sqrt(v(self.a[m-1])**2 - 2.*(1+1./(m-1))*v(self.a[m-2]))) for v in self.Foo]
            if k < m-2:
                bminmax = [lagrange_degree_3(n,v(self.a[m-1]),v(self.a[m-2]),v(self.a[m-3])) for v in self.Foo]
                self.b_lower = bminmax[0]
                self.b_upper = bminmax[1]

            # Annoying, but must reverse coefficients for numpy.
            gnk = [binomial(j,k+2)*a[j] for j in range(k+2,n+1)]
            self.beta[k+1] = [[self.b_lower] + numpy.roots([v(gnk[i]) for i in range(len(gnk))].reverse()).tolist().sort() + [self.b_upper] for v in self.Foo]

            # Now to really initialize gnk.
            self.gnk[k+1] = [[0] + [binomial(j,k+1)*v(a[j]) for j in range (k+2,m+1)] for v in self.Foo]
        else:
            # Bad input!
            raise ValueError("a has length %s > m+1"%len(a))