def enumerate_totallyreal_fields_all(n, B, verbose=0, return_seqs=False): r""" Enumerates *all* totally real fields of degree `n` with discriminant `\le B`, primitive or otherwise. EXAMPLES:: sage: enumerate_totallyreal_fields_all(4, 2000) [[725, x^4 - x^3 - 3*x^2 + x + 1], [1125, x^4 - x^3 - 4*x^2 + 4*x + 1], [1600, x^4 - 6*x^2 + 4], [1957, x^4 - 4*x^2 - x + 1], [2000, x^4 - 5*x^2 + 5]] In practice most of these will be found by :func:`~sage.rings.number_field.totallyreal.enumerate_totallyreal_fields_prim`, which is guaranteed to return all primitive fields but often returns many non-primitive ones as well. For instance, only one of the five fields in the example above is primitive, but :func:`~sage.rings.number_field.totallyreal.enumerate_totallyreal_fields_prim` finds four out of the five (the exception being `x^4 - 6x^2 + 4`). TESTS: The following was fixed in :trac:`13101`:: sage: enumerate_totallyreal_fields_all(8, 10^6) # long time (about 2 s) [] """ S = [] counts = [0,0,0] if len(divisors(n)) > 4: raise ValueError, "Only implemented for n = p*q with p,q prime" for d in divisors(n): if d > 1 and d < n: Sds = enumerate_totallyreal_fields_prim(d, int(math.floor((1.*B)**(1.*d/n))), verbose=verbose) for i in range(len(Sds)): if verbose: print "="*80 print "Taking F =", Sds[i][1] F = NumberField(ZZx(Sds[i][1]), 't') T = enumerate_totallyreal_fields_rel(F, n/d, B, verbose=verbose, return_seqs=return_seqs) if return_seqs: for i in range(3): counts[i] += T[0][i] S += [[t[0],pari(t[1]).Polrev()] for t in T[1]] else: S += [[t[0],t[1]] for t in T] j = i+1 for E in enumerate_totallyreal_fields_prim(n/d, int(math.floor((1.*B)**(1./d)/(1.*Sds[i][0])**(n*1./d**2)))): for EF in F.composite_fields(NumberField(ZZx(E[1]), 'u')): if EF.degree() == n and EF.disc() <= B: S.append([EF.disc(), pari(EF.absolute_polynomial())]) S += enumerate_totallyreal_fields_prim(n, B, verbose=verbose) S.sort() weed_fields(S) # Output. if verbose: saveout = sys.stdout if type(verbose) == str: fsock = open(verbose, 'w') sys.stdout = fsock # Else, print to screen 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()] for s in S]] else: return S
def enumerate_totallyreal_fields_all(n, B, verbose=0, return_seqs=False, return_pari_objects=True): r""" Enumerates *all* totally real fields of degree ``n`` with discriminant at most ``B``, primitive or otherwise. INPUT: - ``n`` -- integer, the degree - ``B`` -- integer, the discriminant bound - ``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. EXAMPLES:: sage: enumerate_totallyreal_fields_all(4, 2000) [[725, x^4 - x^3 - 3*x^2 + x + 1], [1125, x^4 - x^3 - 4*x^2 + 4*x + 1], [1600, x^4 - 6*x^2 + 4], [1957, x^4 - 4*x^2 - x + 1], [2000, x^4 - 5*x^2 + 5]] sage: enumerate_totallyreal_fields_all(1, 10) [[1, x - 1]] TESTS: Each of the outputs must be elements of Sage if ``return_pari_objects`` is set to ``False``:: sage: enumerate_totallyreal_fields_all(2, 10) [[5, x^2 - x - 1], [8, x^2 - 2]] sage: enumerate_totallyreal_fields_all(2, 10)[0][1].parent() Interface to the PARI C library sage: enumerate_totallyreal_fields_all(2, 10, return_pari_objects=False)[0][1].parent() Univariate Polynomial Ring in x over Rational Field In practice most of these will be found by :func:`~sage.rings.number_field.totallyreal.enumerate_totallyreal_fields_prim`, which is guaranteed to return all primitive fields but often returns many non-primitive ones as well. For instance, only one of the five fields in the example above is primitive, but :func:`~sage.rings.number_field.totallyreal.enumerate_totallyreal_fields_prim` finds four out of the five (the exception being `x^4 - 6x^2 + 4`). The following was fixed in :trac:`13101`:: sage: enumerate_totallyreal_fields_all(8, 10^6) # long time (about 2 s) [] """ S = [] counts = [0,0,0,0] if len(divisors(n)) > 4: raise ValueError("Only implemented for n = p*q with p,q prime") for d in divisors(n): if d > 1 and d < n: Sds = enumerate_totallyreal_fields_prim(d, int(math.floor((1.*B)**(1.*d/n))), verbose=verbose) for i in range(len(Sds)): if verbose: print "="*80 print "Taking F =", Sds[i][1] F = NumberField(ZZx(Sds[i][1]), 't') T = enumerate_totallyreal_fields_rel(F, n/d, B, verbose=verbose, return_seqs=return_seqs) if return_seqs: for i in range(4): counts[i] += T[0][i] S += [[t[0],pari(t[1]).Polrev()] for t in T[1]] else: S += [[t[0],t[1]] for t in T] j = i+1 for E in enumerate_totallyreal_fields_prim(n/d, int(math.floor((1.*B)**(1./d)/(1.*Sds[i][0])**(n*1./d**2)))): for EF in F.composite_fields(NumberField(ZZx(E[1]), 'u')): if EF.degree() == n and EF.disc() <= B: S.append([EF.disc(), pari(EF.absolute_polynomial())]) S += enumerate_totallyreal_fields_prim(n, B, verbose=verbose) S.sort(cmp=lambda x, y: cmp(x[0], y[0]) or cmp(x[1], y[1])) weed_fields(S) # Output. if verbose: saveout = sys.stdout if isinstance(verbose, str): fsock = open(verbose, 'w') sys.stdout = fsock # Else, print to screen 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(_) for _ in counts], [[ZZ(s[0]), [QQ(_) for _ in s[1].polrecip().Vec()]] for s in S]] elif return_pari_objects: return S else: Px = PolynomialRing(QQ, 'x') return [[ZZ(s[0]), Px([QQ(_) for _ in s[1].list()])] for s in S]
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
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]
def enumerate_totallyreal_fields_all(n, B, verbose=0, return_seqs=False, return_pari_objects=True): r""" Enumerates *all* totally real fields of degree ``n`` with discriminant at most ``B``, primitive or otherwise. INPUT: - ``n`` -- integer, the degree - ``B`` -- integer, the discriminant bound - ``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. EXAMPLES:: sage: enumerate_totallyreal_fields_all(4, 2000) [[725, x^4 - x^3 - 3*x^2 + x + 1], [1125, x^4 - x^3 - 4*x^2 + 4*x + 1], [1600, x^4 - 6*x^2 + 4], [1957, x^4 - 4*x^2 - x + 1], [2000, x^4 - 5*x^2 + 5]] sage: enumerate_totallyreal_fields_all(1, 10) [[1, x - 1]] TESTS: Each of the outputs must be elements of Sage if ``return_pari_objects`` is set to ``False``:: sage: enumerate_totallyreal_fields_all(2, 10) [[5, x^2 - x - 1], [8, x^2 - 2]] sage: type(enumerate_totallyreal_fields_all(2, 10)[0][1]) <type 'cypari2.gen.Gen'> sage: enumerate_totallyreal_fields_all(2, 10, return_pari_objects=False)[0][1].parent() Univariate Polynomial Ring in x over Rational Field In practice most of these will be found by :func:`~sage.rings.number_field.totallyreal.enumerate_totallyreal_fields_prim`, which is guaranteed to return all primitive fields but often returns many non-primitive ones as well. For instance, only one of the five fields in the example above is primitive, but :func:`~sage.rings.number_field.totallyreal.enumerate_totallyreal_fields_prim` finds four out of the five (the exception being `x^4 - 6x^2 + 4`). The following was fixed in :trac:`13101`:: sage: enumerate_totallyreal_fields_all(8, 10^6) # long time (about 2 s) [] """ S = [] counts = [0, 0, 0, 0] if len(divisors(n)) > 4: raise ValueError("Only implemented for n = p*q with p,q prime") for d in divisors(n): if d > 1 and d < n: Sds = enumerate_totallyreal_fields_prim( d, int(math.floor((1. * B)**(1. * d / n))), verbose=verbose) for i in range(len(Sds)): if verbose: print("=" * 80) print("Taking F =", Sds[i][1]) F = NumberField(ZZx(Sds[i][1]), 't') T = enumerate_totallyreal_fields_rel(F, n / d, B, verbose=verbose, return_seqs=return_seqs) if return_seqs: for i in range(4): counts[i] += T[0][i] S += [[t[0], pari(t[1]).Polrev()] for t in T[1]] else: S += [[t[0], t[1]] for t in T] for E in enumerate_totallyreal_fields_prim( n / d, int( math.floor((1. * B)**(1. / d) / (1. * Sds[i][0])**(n * 1. / d**2)))): for EF in F.composite_fields(NumberField(ZZx(E[1]), 'u')): if EF.degree() == n and EF.disc() <= B: S.append( [EF.disc(), pari(EF.absolute_polynomial())]) S += enumerate_totallyreal_fields_prim(n, B, verbose=verbose) S.sort(key=lambda x: (x[0], [QQ(cf) for cf in x[1].polrecip().Vec()])) weed_fields(S) # Output. if verbose: saveout = sys.stdout if isinstance(verbose, str): fsock = open(verbose, 'w') sys.stdout = fsock # Else, print to screen 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(_) for _ in counts], [[ZZ(s[0]), [QQ(_) for _ in s[1].polrecip().Vec()]] for s in S]] elif return_pari_objects: return S else: Px = PolynomialRing(QQ, 'x') return [[ZZ(s[0]), Px([QQ(_) for _ in s[1].list()])] for s in S]
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]
def enumerate_totallyreal_fields_all(n, B, verbose=0, return_seqs=False): r""" Enumerates *all* totally real fields of degree `n` with discriminant `\le B`, primitive or otherwise. EXAMPLES:: sage: enumerate_totallyreal_fields_all(4, 2000) [[725, x^4 - x^3 - 3*x^2 + x + 1], [1125, x^4 - x^3 - 4*x^2 + 4*x + 1], [1600, x^4 - 6*x^2 + 4], [1957, x^4 - 4*x^2 - x + 1], [2000, x^4 - 5*x^2 + 5]] In practice most of these will be found by :func:`~sage.rings.number_field.totallyreal.enumerate_totallyreal_fields_prim`, which is guaranteed to return all primitive fields but often returns many non-primitive ones as well. For instance, only one of the five fields in the example above is primitive, but :func:`~sage.rings.number_field.totallyreal.enumerate_totallyreal_fields_prim` finds four out of the five (the exception being `x^4 - 6x^2 + 4`). """ S = [] counts = [0, 0, 0] if len(divisors(n)) > 4: raise ValueError, "Only implemented for n = p*q with p,q prime" for d in divisors(n): if d > 1 and d < n: Sds = enumerate_totallyreal_fields_prim(d, int(math.floor((1.0 * B) ** (1.0 * d / n))), verbose=verbose) for i in range(len(Sds)): if verbose: print "=" * 80 print "Taking F =", Sds[i][1] F = NumberField(ZZx(Sds[i][1]), "t") T = enumerate_totallyreal_fields_rel(F, n / d, B, verbose=verbose, return_seqs=return_seqs) if return_seqs: for i in range(3): counts[i] += T[0][i] S += [[t[0], pari(t[1]).Polrev()] for t in T[1]] else: S += [[t[0], t[1]] for t in T] j = i + 1 for E in enumerate_totallyreal_fields_prim( n / d, int(math.floor((1.0 * B) ** (1.0 / d) / (1.0 * Sds[i][0]) ** (n * 1.0 / d ** 2))) ): for EF in F.composite_fields(NumberField(ZZx(E[1]), "u")): if EF.degree() == n and EF.disc() <= B: S.append([EF.disc(), pari(EF.absolute_polynomial())]) S += enumerate_totallyreal_fields_prim(n, B, verbose=verbose) S.sort() weed_fields(S) # Output. if verbose: saveout = sys.stdout if type(verbose) == str: fsock = open(verbose, "w") sys.stdout = fsock # Else, print to screen 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()] for s in S]] else: return S
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