def _evalf_(self, x, parent): """ EXAMPLES:: sage: erf(2).n() 0.995322265018953 sage: erf(2).n(200) 0.99532226501895273416206925636725292861089179704006007673835 sage: erf(pi - 1/2*I).n(100) 1.0000111669099367825726058952 + 1.6332655417638522934072124548e-6*I TESTS: Check that PARI/GP through the GP interface gives the same answer:: sage: gp.set_real_precision(59) # random 38 sage: print gp.eval("1 - erfc(1)"); print erf(1).n(200); 0.84270079294971486934122063508260925929606699796630290845994 0.84270079294971486934122063508260925929606699796630290845994 """ try: prec = parent.prec() except AttributeError: # not a Sage parent prec = 0 return parent(1) - parent(pari(x).erfc(prec))
def __init__(self, field, num_integer_primes=10000, max_iterations=100): r""" Construct a new iterator of small degree one primes. EXAMPLES:: sage: x = QQ['x'].gen() sage: K.<a> = NumberField(x^2 - 3) sage: K.primes_of_degree_one_list(3) # random [Fractional ideal (2*a + 1), Fractional ideal (-a + 4), Fractional ideal (3*a + 2)] """ self._field = field self._poly = self._field.absolute_field('b').defining_polynomial() self._poly = ZZ['x'](self._poly.denominator() * self._poly()) # make integer polynomial # this uses that [ O_K : Z[a] ]^2 = | disc(f(x)) / disc(O_K) | self._prod_of_small_primes = ZZ( pari( 'TEMPn = %s; TEMPps = primes(TEMPn); prod(X = 1, TEMPn, TEMPps[X])' % num_integer_primes)) self._prod_of_small_primes //= self._prod_of_small_primes.gcd( self._poly.discriminant()) self._integer_iter = iter(ZZ) self._queue = [] self._max_iterations = max_iterations
def _shortest_vectors(self, max_count=None, max_length=0): """ Compute shortest vectors and their number and length (potentially). INPUT: - ``max_count`` -- maximum number of vectors to store in the result (default: all); - ``max_length`` -- maximal length of vectors to consider (default: 0, i.e., consider shortest vectors). OUTPUT: A triple consisting of the number of corresponding (shortest) vectors, their length, and a list of at most ``max_count`` such vectors. TESTS:: sage: L = Lattice([[1, 0], [0, 1]]) sage: L.shortest_vectors_count() 4 """ default = max_length == 0 and max_count == 0 if default and self.__shortest_vectors is not None: return self.__shortest_vectors qf = self.reduced_inner_product_matrix() if max_count is None: # determine the number of shortest vectors max_count = self._shortest_vectors(max_length=max_length, max_count=0)[0] #self.degree() count, length, vectors = pari(qf).qfminim(0, max_count) result = count, length, vectors.python().columns() if default: self.__shortest_vectors = result return result
def qfparam(G, sol): r""" Parametrizes the conic defined by the matrix ``G``. INPUT: - ``G`` -- a `3 \times 3`-matrix over `\QQ`. - ``sol`` -- a triple of rational numbers providing a solution to sol*G*sol^t = 0. OUTPUT: A triple of polynomials that parametrizes all solutions of x*G*x^t = 0 up to scaling. ALGORITHM: Uses Denis Simon's pari script Qfparam. EXAMPLES:: sage: from sage.quadratic_forms.qfsolve import qfsolve, qfparam sage: M = Matrix(QQ, [[0, 0, -12], [0, -12, 0], [-12, 0, -1]]); M [ 0 0 -12] [ 0 -12 0] [-12 0 -1] sage: sol = qfsolve(M); sage: ret = qfparam(M, sol); ret (-t^2 - 12, 24*t, 24*t^2) sage: ret[0].parent() is QQ['t'] True """ gp = _gp_for_simon() R = QQ['t'] t = R.gen() s = 'Qfparam(%s, (%s)~)*[t^2,t,1]~' % (G._pari_(), pari(gp(sol))._pari_()) ret = pari(gp(s)) return tuple([R(r) for r in ret])
def as_hom(self): r""" Return the homomorphism L -> L corresponding to self, where L is the Galois closure of the ambient number field. EXAMPLE:: sage: G = QuadraticField(-7,'w').galois_group() sage: G[1].as_hom() Ring endomorphism of Number Field in w with defining polynomial x^2 + 7 Defn: w |--> -w """ L = self.parent().splitting_field() a = L(self.parent()._pari_data.galoispermtopol(pari(self.list()).Vecsmall())) return L.hom(a, L)
def as_hom(self): r""" Return the homomorphism L -> L corresponding to self, where L is the Galois closure of the ambient number field. EXAMPLE:: sage: G = QuadraticField(-7,'w').galois_group() sage: G[1].as_hom() Ring endomorphism of Number Field in w with defining polynomial x^2 + 7 Defn: w |--> -w """ L = self.parent().splitting_field() a = L(self.parent()._pari_data.galoispermtopol( pari(self.list()).Vecsmall())) return L.hom(a, L)
def resultant(self, normalize=False): r""" Computes the resultant of the defining polynomials of ``self`` if ``self`` is a map on the projective line. If ``normalize`` is ``True``, then first normalize the coordinate functions with :meth:`normalize_coordinates`. INPUT: - ``normalize`` -- Boolean (optional - default: ``False``) OUTPUT: - an element of ``self.codomain().base_ring()`` EXAMPLES:: sage: P.<x,y> = ProjectiveSpace(QQ,1) sage: H = Hom(P,P) sage: f = H([x^2+y^2,6*y^2]) sage: f.resultant() 36 :: sage: R.<t> = PolynomialRing(GF(17)) sage: P.<x,y> = ProjectiveSpace(R,1) sage: H = Hom(P,P) sage: f = H([t*x^2+t*y^2,6*y^2]) sage: f.resultant() 2*t^2 """ if self.domain().dimension_relative() > 1: raise TypeError("Only for dimension 1, use self.primes_of_bad_reduction() to get bad primes") if normalize is True: F=copy(self) F.normalize_coordinates() else: F=self x=self.domain().gen(0) y=self.domain().gen(1) d=self.degree() f=F[0].substitute({y:1}) g=F[1].substitute({y:1}) res=(f.lc()**(d-g.degree())*g.lc()**(d-f.degree())*pari(f).polresultant(g,x)) return(self.codomain().base_ring()(res))
def resultant(self,normalize=False): r""" Computes the resultant of the defining polynomials of ``self`` if ``self`` is a map on the projective line. If ``normalize==True``, then first normalize the coordinate functions with ``normalize_coordinates()``. INPUT: - ``normalize`` -- Boolean (optional - default: ``False``) OUTPUT: - an element of ``self.codomain().base_ring()`` EXAMPLES:: sage: P.<x,y>=ProjectiveSpace(QQ,1) sage: H=Hom(P,P) sage: f=H([x^2+y^2,6*y^2]) sage: f.resultant() 36 :: sage: R.<t>=PolynomialRing(GF(17)) sage: P.<x,y>=ProjectiveSpace(R,1) sage: H=Hom(P,P) sage: f=H([t*x^2+t*y^2,6*y^2]) sage: f.resultant() 2*t^2 """ if self.domain().dimension_relative() > 1: raise TypeError("Only for dimension 1, use self.primes_of_bad_reduction() to get bad primes") if normalize==True: F=copy(self) F.normalize_coordinates() else: F=self x=self.domain().gen(0) y=self.domain().gen(1) d=self.degree() f=F[0].substitute({y:1}) g=F[1].substitute({y:1}) res=(f.lc()**(d-g.degree())*g.lc()**(d-f.degree())*pari(f).polresultant(g,x)) return(self.codomain().base_ring()(res))
def qfsolve(G, factD=None): r""" Find a solution `x = (x_0,...,x_n)` to `x G x^t = 0` for an `n \times n`-matrix ``G`` over `\QQ`. If a solution exists, returns a tuple of rational numbers `x`. Otherwise, returns `-1` if no solutions exists over the reals or a prime `p` if no solution exists over the `p`-adic field `\QQ_p`. EXAMPLES:: sage: from sage.quadratic_forms.qfsolve import qfsolve sage: M = Matrix(QQ, [[0, 0, -12], [0, -12, 0], [-12, 0, -1]]); M [ 0 0 -12] [ 0 -12 0] [-12 0 -1] sage: sol = qfsolve(M); sol (1, 0, 0) sage: sol[0].parent() is QQ True sage: M = Matrix(QQ, [[1, 0, 0], [0, 1, 0], [0, 0, 1]]) sage: ret = qfsolve(M); ret -1 sage: ret.parent() is ZZ True sage: M = Matrix(QQ, [[1, 0, 0], [0, 1, 0], [0, 0, -7]]) sage: qfsolve(M) 7 sage: M = Matrix(QQ, [[3, 0, 0, 0], [0, 5, 0, 0], [0, 0, -7, 0], [0, 0, 0, -11]]) sage: qfsolve(M) (-3, 4, 3, 2) """ gp = _gp_for_simon() if factD is not None: raise NotImplementedError, "qfsolve not implemented with parameter factD" ret = pari(gp('Qfsolve(%s)' % G._pari_())) if ret.type() == 't_COL': return tuple([QQ(r) for r in ret]) return ZZ(ret)
def __init__(self, field, num_integer_primes=10000, max_iterations=100): r""" Construct a new iterator of small degree one primes. EXAMPLES:: sage: x = QQ['x'].gen() sage: K.<a> = NumberField(x^2 - 3) sage: K.primes_of_degree_one_list(3) # random [Fractional ideal (2*a + 1), Fractional ideal (-a + 4), Fractional ideal (3*a + 2)] """ self._field = field self._poly = self._field.absolute_field('b').defining_polynomial() self._poly = ZZ['x'](self._poly.denominator() * self._poly()) # make integer polynomial # this uses that [ O_K : Z[a] ]^2 = | disc(f(x)) / disc(O_K) | self._prod_of_small_primes = ZZ(pari('TEMPn = %s; TEMPps = primes(TEMPn); prod(X = 1, TEMPn, TEMPps[X])' % num_integer_primes)) self._prod_of_small_primes //= self._prod_of_small_primes.gcd(self._poly.discriminant()) self._integer_iter = iter(ZZ) self._queue = [] self._max_iterations = max_iterations
def fixed_field(self): r""" Return the fixed field of this subgroup (as a subfield of the Galois closure of the number field associated to the ambient Galois group). EXAMPLE:: sage: L.<a> = NumberField(x^4 + 1) sage: G = L.galois_group() sage: H = G.decomposition_group(L.primes_above(3)[0]) sage: H.fixed_field() (Number Field in a0 with defining polynomial x^2 + 2, Ring morphism: From: Number Field in a0 with defining polynomial x^2 + 2 To: Number Field in a with defining polynomial x^4 + 1 Defn: a0 |--> a^3 + a) """ if self.order() == 1: return self._galois_closure # work around a silly error vecs = [pari(g.list()).Vecsmall() for g in self._elts] v = self._ambient._pari_data.galoisfixedfield(vecs) x = self._galois_closure(v[1]) return self._galois_closure.subfield(x)
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. * 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_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: 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 __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)
def pari(x): """ Return the pari object constructed from a Sage object. The work is done by the __call__ method of the class PariInstance, which in turn passes the work to any class which has its own method _pari_(). EXAMPLES:: sage: pari([2,3,5]) [2, 3, 5] sage: pari(Matrix(2,2,range(4))) [0, 1; 2, 3] sage: pari(x^2-3) x^2 - 3 :: sage: a = pari(1); a, a.type() (1, 't_INT') sage: a = pari(1/2); a, a.type() (1/2, 't_FRAC') sage: a = pari(1/2); a, a.type() (1/2, 't_FRAC') Conversion from reals uses the real's own precision, here 53 bits (the default):: sage: a = pari(1.2); a, a.type(), a.precision() (1.20000000000000, 't_REAL', 4) # 32-bit (1.20000000000000, 't_REAL', 3) # 64-bit Conversion from strings uses the current pari real precision. By default this is 4 words, 38 digits, 128 bits on 64-bit machines and 5 words, 19 digits, 64 bits on 32-bit machines. :: sage: a = pari('1.2'); a, a.type(), a.precision() (1.20000000000000, 't_REAL', 5) # 32-bit (1.20000000000000, 't_REAL', 4) # 64-bit Conversion from matrices is supported, but not from vectors; use lists instead:: sage: a = pari(matrix(2,3,[1,2,3,4,5,6])); a, a.type() ([1, 2, 3; 4, 5, 6], 't_MAT') sage: v = vector([1.2,3.4,5.6]) sage: v.pari() Traceback (most recent call last): ... AttributeError: 'sage.modules.free_module_element.FreeModuleElement_generic_dense' object has no attribute 'pari' sage: b = pari(list(v)); b,b.type() ([1.20000000000000, 3.40000000000000, 5.60000000000000], 't_VEC') Some more exotic examples:: sage: K.<a> = NumberField(x^3 - 2) sage: pari(K) [y^3 - 2, [1, 1], -108, 1, [[1, 1.25992104989487, 1.58740105196820; 1, -0.629960524947437 - 1.09112363597172*I, -0.793700525984100 + 1.37472963699860*I], [1, 1.25992104989487, 1.58740105196820; 1, -1.72108416091916, 0.581029111014503; 1, 0.461163111024285, -2.16843016298270], [1, 1, 2; 1, -2, 1; 1, 0, -2], [3, 0, 0; 0, 0, 6; 0, 6, 0], [6, 0, 0; 0, 6, 0; 0, 0, 3], [2, 0, 0; 0, 0, 1; 0, 1, 0], [2, [0, 0, 2; 1, 0, 0; 0, 1, 0]]], [1.25992104989487, -0.629960524947437 - 1.09112363597172*I], [1, y, y^2], [1, 0, 0; 0, 1, 0; 0, 0, 1], [1, 0, 0, 0, 0, 2, 0, 2, 0; 0, 1, 0, 1, 0, 0, 0, 0, 2; 0, 0, 1, 0, 1, 0, 1, 0, 0]] sage: E = EllipticCurve('37a1') sage: pari(E) [0, 0, 1, -1, 0, 0, -2, 1, -1, 48, -216, 37, 110592/37, [0.837565435283323, 0.269594436405445, -1.10715987168877]~, 2.99345864623196, -2.45138938198679*I, 0.942638555913623, 1.32703057887968*I, 7.33813274078958] Conversion from basic Python types:: sage: pari(int(-5)) -5 sage: pari(long(2**150)) 1427247692705959881058285969449495136382746624 sage: pari(float(pi)) 3.14159265358979 sage: pari(complex(exp(pi*I/4))) 0.707106781186548 + 0.707106781186547*I sage: pari(False) 0 sage: pari(True) 1 Some commands are just executed without returning a value:: sage: pari("dummy = 0; kill(dummy)") sage: type(pari("dummy = 0; kill(dummy)")) <type 'NoneType'> """ return gen.pari(x)
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
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.0 / m * (am1 ** 2).trace() + self.gamma * (1.0 / (m ** d) * self.B / self.dF) ** (1.0 / (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.0 / m * ( v(self.a[m - 1]) + (m - 1.0) * math.sqrt(v(self.a[m - 1]) ** 2 - 2.0 * (1 + 1.0 / (m - 1)) * v(self.a[m - 2])) ) for v in self.Foo ] self.b_upper = [ -1.0 / m * ( v(self.a[m - 1]) - (m - 1.0) * math.sqrt(v(self.a[m - 1]) ** 2 - 2.0 * (1 + 1.0 / (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)
def classno(d): """Return the class number of the order of discriminant d.""" # There is currently no qfbclassno method in gen.pyx, hence the string. return Integer(pari('qfbclassno(%s,%s)' % (d, 1 if proof else 0)))
def classno(d): """Return the class number of the order of discriminant d.""" # There is currently no qfbclassno method in gen.pyx, hence the string. return Integer(pari('qfbclassno(%s,%s)'%(d, 1 if proof else 0)))