def solve(self, verify = False): percent = RealField(prec=20)(0) holes = self._holes self._minholes = len(holes) while len(holes) > 0: h = holes.popleft() result = self.evaluate_hole(h) if result == -2: self._Nboundmax = max([self._Nboundmax,self._Nbound]) self._holes.append(h) if result == -1: xh = (h.xmax+h.xmin)/2 yh = (h.ymax+h.ymin)/2 depth = h.depth()+1 self._maxdepth = max([self._maxdepth,depth]) h1 = Hole(self,[h.xmin,h.ymin,xh,yh],depth=depth) h2 = Hole(self,[h.xmin,yh,xh,h.ymax],depth=depth) h3 = Hole(self,[xh,h.ymin,h.xmax,yh],depth=depth) h4 = Hole(self,[xh,yh,h.xmax,h.ymax],depth=depth) holes.extendleft([h1,h2,h3,h4]) else: percent += 100*(4**(-h.depth())) if len(holes) < self._minholes: self._minholes = len(holes) percent = RealField(prec=20)(0) if verify and not self.verify(): raise RuntimeError("The result seems not to be correct. Verification failed.") self._solved = True return [self._disc, self._maxdepth, 1 + max([abs(self._F(reg[1][1]).norm()) for reg in self._used_regions]),len(self._used_regions),self._used_regions]
def verify(self): maxdepth = self._maxdepth self.initialize_fundom() percent = RealField(prec=20)(0) holes = self._holes self._minholes = len(holes) while len(holes) > 0: h = holes.popleft() result = self.evaluate_hole(h,verifying=True,maxdepth=maxdepth) if result == -2: print "The solution is incorrect." print "The ",h," is not covered by any region." return False if result == -1: xh = (h.xmax+h.xmin)/2 yh = (h.ymax+h.ymin)/2 depth = h.depth()+1 self._maxdepth = max([self._maxdepth,depth]) h1 = Hole(self,[h.xmin,h.ymin,xh,yh],depth=depth) h2 = Hole(self,[h.xmin,yh,xh,h.ymax],depth=depth) h3 = Hole(self,[xh,h.ymin,h.xmax,yh],depth=depth) h4 = Hole(self,[xh,yh,h.xmax,h.ymax],depth=depth) holes.extendleft([h1,h2,h3,h4]) else: percent += 100*(4**(-h.depth())) if len(holes) < self._minholes: self._minholes=len(holes) percent=RealField(prec=20)(0) return True
def coincidence_index(self, prec=0): """ Returns the probability of two randomly chosen characters being equal. """ if prec == 0: RR = RealField() else: RR = RealField(prec) char_dict = {} for i in self._element_list: # if char_dict.has_key(i): # The method .has_key() has been deprecated since Python 2.2. Use # "k in Dict" instead of "Dict.has_key(k)". if i in char_dict: char_dict[i] += 1 else: char_dict[i] = 1 nn = 0 ci_num = 0 for i in char_dict.keys(): ni = char_dict[i] nn += ni ci_num += ni * (ni - 1) ci_den = nn * (nn - 1) return RR(ci_num) / ci_den
def solve(self,verify=False): percent=RealField(prec=_sage_const_20 )(_sage_const_0 ) holes=self._holes self._minholes=len(holes) while(len(holes)>_sage_const_0 ): if(len(holes)-self._minholes>_sage_const_1000 ): assert(_sage_const_0 ) h=holes.popleft() result=self.evaluate_hole(h) if(result==-_sage_const_2 ): self._Nboundmax=max([self._Nboundmax,self._Nbound]) self._holes.append(h) if(result==-_sage_const_1 ): xh=(h.xmax+h.xmin)/_sage_const_2 yh=(h.ymax+h.ymin)/_sage_const_2 depth=h.depth()+_sage_const_1 self._maxdepth=max([self._maxdepth,depth]) h1=Hole(self,[h.xmin,h.ymin,xh,yh],depth=depth) h2=Hole(self,[h.xmin,yh,xh,h.ymax],depth=depth) h3=Hole(self,[xh,h.ymin,h.xmax,yh],depth=depth) h4=Hole(self,[xh,yh,h.xmax,h.ymax],depth=depth) holes.extendleft([h1,h2,h3,h4]) else: percent+=_sage_const_100 *(_sage_const_4 **(-h.depth())) #print 'Finished hole ',self._minholes,' up to ',percent,'%' if(len(holes)<self._minholes): self._minholes=len(holes) percent=RealField(prec=_sage_const_20 )(_sage_const_0 ) #print "Remaining ",self._minholes,' holes.' if(verify==True): assert(self.verify()) self._solved=True return [self._disc,self._maxdepth,_sage_const_1 +max([abs(self._F(reg[_sage_const_1 ][_sage_const_1 ]).norm()) for reg in self._used_regions]),len(self._used_regions),self._used_regions]
def verify(self): maxdepth=self._maxdepth self.initialize_fundom() percent=RealField(prec=_sage_const_20 )(_sage_const_0 ) holes=self._holes self._minholes=len(holes) while(len(holes)>_sage_const_0 ): if(len(holes)-self._minholes>_sage_const_1000 ): assert(_sage_const_0 ) h=holes.popleft() result=self.evaluate_hole(h,verifying=True,maxdepth=maxdepth) if(result==-_sage_const_2 ): print "The solution is incorrect." print "The ",h," is not covered by any region." return False if(result==-_sage_const_1 ): xh=(h.xmax+h.xmin)/_sage_const_2 yh=(h.ymax+h.ymin)/_sage_const_2 depth=h.depth()+_sage_const_1 self._maxdepth=max([self._maxdepth,depth]) h1=Hole(self,[h.xmin,h.ymin,xh,yh],depth=depth) h2=Hole(self,[h.xmin,yh,xh,h.ymax],depth=depth) h3=Hole(self,[xh,h.ymin,h.xmax,yh],depth=depth) h4=Hole(self,[xh,yh,h.xmax,h.ymax],depth=depth) holes.extendleft([h1,h2,h3,h4]) else: percent+=_sage_const_100 *(_sage_const_4 **(-h.depth())) #print 'Finished hole ',self._minholes,' up to ',percent,'%' if(len(holes)<self._minholes): self._minholes=len(holes) percent=RealField(prec=_sage_const_20 )(_sage_const_0 ) #print "Remaining ",self._minholes,' holes.' return True
def riemann_sum(G, phi, hc, depth=1, mult=False, progress_bar=False, K=None): prec = max([20, 2 * depth]) res = 1 if mult else 0 if K is None: K = phi.parent().base_ring() cover = G.get_covering(depth) n_ints = 0 for e in cover: if n_ints % 500 == 499: verbose('Done %s percent' % (100 * RealField(10)(n_ints) / len(cover))) if progress_bar: update_progress(float(RealField(10)(n_ints + 1) / len(cover)), 'Riemann sum') n_ints += 1 val = hc(e) vmom = val[0] #.moment(0) if vmom.parent().is_exact(): hce = ZZ(vmom) else: hce = ZZ(vmom.rational_reconstruction()) if hce == 0: continue #verbose('hc = %s'%hce) te = sample_point(G, e, prec) if te == Infinity: continue if mult: res *= phi(K(te))**hce else: res += phi(K(te)) * hce return res
def _compute_power_series(self, n, abs_prec, cache_ring=None): """ Compute the power series giving Dickman's function on [n, n+1], by recursion in n. For internal use; self.power_series() is a wrapper around this intended for the user. INPUT: - ``n`` - the lower endpoint of the interval for which this power series holds - ``abs_prec`` - the absolute precision of the resulting power series - ``cache_ring`` - for internal use, caches the power series at this precision. EXAMPLES:: sage: f = dickman_rho.power_series(2, 20); f -9.9376e-8*x^11 + 3.7722e-7*x^10 - 1.4684e-6*x^9 + 5.8783e-6*x^8 - 0.000024259*x^7 + 0.00010341*x^6 - 0.00045583*x^5 + 0.0020773*x^4 - 0.0097336*x^3 + 0.045224*x^2 - 0.11891*x + 0.13032 """ if n <= 1: if n <= -1: return PolynomialRealDense(RealField(abs_prec)['x']) if n == 0: return PolynomialRealDense(RealField(abs_prec)['x'], [1]) elif n == 1: nterms = (RDF(abs_prec) * RDF(2).log() / RDF(3).log()).ceil() R = RealField(abs_prec) neg_three = ZZ(-3) coeffs = [1 - R(1.5).log() ] + [neg_three**-k / k for k in range(1, nterms)] f = PolynomialRealDense(R['x'], coeffs) if cache_ring is not None: self._f[n] = f.truncate_abs(f[0] >> ( cache_ring.prec() + 1)).change_ring(cache_ring) return f else: f = self._compute_power_series(n - 1, abs_prec, cache_ring) # integrand = f / (2n+1 + x) # We calculate this way because the most significant term is the constant term, # and so we want to push the error accumulation and remainder out to the least # significant terms. integrand = f.reverse().quo_rem( PolynomialRealDense(f.parent(), [1, 2 * n + 1]))[0].reverse() integrand = integrand.truncate_abs(RR(2)**-abs_prec) iintegrand = integrand.integral() ff = PolynomialRealDense(f.parent(), [f(1) + iintegrand(-1)]) - iintegrand i = 0 while abs(f[i]) < abs(f[i + 1]): i += 1 rel_prec = int(abs_prec + abs(RR(f[i])).log2()) if cache_ring is not None: self._f[n] = ff.truncate_abs( ff[0] >> (cache_ring.prec() + 1)).change_ring(cache_ring) return ff.change_ring(RealField(rel_prec))
def coincidence_index(S, n=1): """ The coincidence index of the string S. EXAMPLES:: sage: S = strip_encoding("The cat in the hat.") sage: coincidence_index(S) 0.120879120879121 """ if not isinstance(S, str): try: S.coincidence_index(n) except AttributeError: raise TypeError("Argument S (= %s) must be a string.") S = strip_encoding(S) N = len(S) - n + 1 X = {} for i in range(N): c = S[i:i + n] if c in X: X[c] += 1 else: X[c] = 1 RR = RealField() return RR(sum([m * (m - 1) for m in X.values()])) / RR(N * (N - 1))
def __init__(self,F,Nbound=_sage_const_50 ,Tbound=_sage_const_5 ): self._F=F self._solved=False self._disc=self._F.discriminant() self._w=self._F.maximal_order().ring_generators()[_sage_const_0 ] self._eps=self._F.units()[_sage_const_0 ] self._Phi=self._F.real_embeddings(prec=_sage_const_500 ) a=F.gen() self.Pointxy=namedtuple('Pointxy','x y') if(self._disc%_sage_const_2 ==_sage_const_0 ): self._changebasismatrix=_sage_const_1 else: self._changebasismatrix=Matrix(IntegerRing(),_sage_const_2 ,_sage_const_2 ,[_sage_const_1 ,-_sage_const_1 ,_sage_const_0 ,_sage_const_2 ]) # We assume here that Phi orders the embeddings to that # Phi[1] is the largest self._Rw=self._Phi[_sage_const_1 ](self._w) self._Rwconj=self._Phi[_sage_const_0 ](self._w) self._used_regions=[] self._Nboundmin=_sage_const_2 self._Nboundmax=Nbound self._Nboundinc=_sage_const_1 self._Nbound=Nbound self._epsto=[self._F(_sage_const_1 )] self._Dmax=self.embed(self._w) self._Tbound=Tbound self._ranget=sorted(range(-self._Tbound,self._Tbound+_sage_const_2 ),key=abs) self._M=Matrix(RealField(),_sage_const_2 ,_sage_const_2 ,[_sage_const_1 ,self._Rw,_sage_const_1 ,self._Rwconj]).inverse() self.initialize_fundom() self._master_regs=Regions(self) self._maxdepth=_sage_const_0
def __init__(self, F, Nbound = 50,Tbound = 5, prec = 500): self._F = F self._solved = False self._disc = self._F.discriminant() self._w = self._F.maximal_order().ring_generators()[0] self._eps = self._F.units()[0] self._Phi = self._F.real_embeddings(prec=prec) a = F.gen() self.Pointxy = namedtuple('Pointxy', 'x y') if self._disc % 2 ==0 : self._changebasismatrix = 1 else: self._changebasismatrix = Matrix(IntegerRing(),2,2,[1,-1,0,2]) # We assume here that Phi orders the embeddings to that # Phi[1] is the largest self._Rw = self._Phi[1](self._w) self._Rwconj = self._Phi[0](self._w) self._used_regions = [] self._Nboundmin = 2 self._Nboundmax = Nbound self._Nboundinc = 1 self._Nbound = Nbound self._epsto = [self._F(1)] self._Dmax = self.embed(self._w) self._Tbound = Tbound self._ranget = sorted(range(-self._Tbound,self._Tbound+2),key=abs) self._M = ~Matrix(RealField(), 2, 2, [1,self._Rw,1,self._Rwconj]) self.initialize_fundom() self._master_regs = Regions(self) self._maxdepth = 0
def _do_sqrt(x, prec=None, extend=True, all=False): r""" Used internally to compute the square root of x. INPUT: - ``x`` - a number - ``prec`` - None (default) or a positive integer (bits of precision) If not None, then compute the square root numerically to prec bits of precision. - ``extend`` - bool (default: True); this is a place holder, and is always ignored since in the symbolic ring everything has a square root. - ``extend`` - bool (default: True); whether to extend the base ring to find roots. The extend parameter is ignored if prec is a positive integer. - ``all`` - bool (default: False); whether to return a list of all the square roots of x. EXAMPLES:: sage: from sage.functions.other import _do_sqrt sage: _do_sqrt(3) sqrt(3) sage: _do_sqrt(3,prec=10) 1.7 sage: _do_sqrt(3,prec=100) 1.7320508075688772935274463415 sage: _do_sqrt(3,all=True) [sqrt(3), -sqrt(3)] Note that the extend parameter is ignored in the symbolic ring:: sage: _do_sqrt(3,extend=False) sqrt(3) """ from sage.rings.all import RealField, ComplexField if prec: if x >= 0: return RealField(prec)(x).sqrt(all=all) else: return ComplexField(prec)(x).sqrt(all=all) if x == -1: from sage.symbolic.pynac import I z = I else: z = SR(x)**one_half if all: if z: return [z, -z] else: return [z] return z
def __call__(self, x, prec=None, coerce=True, hold=False): """ Note that the ``prec`` argument is deprecated. The precision for the result is deduced from the precision of the input. Convert the input to a higher precision explicitly if a result with higher precision is desired.:: sage: t = gamma(RealField(100)(2.5)); t 1.3293403881791370204736256125 sage: t.prec() 100 sage: gamma(6, prec=53) doctest:...: DeprecationWarning: The prec keyword argument is deprecated. Explicitly set the precision of the input, for example gamma(RealField(300)(1)), or use the prec argument to .n() for exact inputs, e.g., gamma(1).n(300), instead. 120.000000000000 TESTS:: sage: gamma(pi,prec=100) 2.2880377953400324179595889091 sage: gamma(3/4,prec=100) 1.2254167024651776451290983034 """ if prec is not None: from sage.misc.misc import deprecation deprecation( "The prec keyword argument is deprecated. Explicitly set the precision of the input, for example gamma(RealField(300)(1)), or use the prec argument to .n() for exact inputs, e.g., gamma(1).n(300), instead." ) import mpmath return mpmath_utils.call(mpmath.gamma, x, prec=prec) # this is a kludge to keep # sage: Q.<i> = NumberField(x^2+1) # sage: gamma(i) # working, since number field elements cannot be coerced into SR # without specifying an explicit embedding into CC any more try: res = GinacFunction.__call__(self, x, coerce=coerce, hold=hold) except TypeError, err: # the __call__() method returns a TypeError for fast float arguments # as well, we only proceed if the error message says that # the arguments cannot be coerced to SR if not str(err).startswith("cannot coerce"): raise from sage.misc.misc import deprecation deprecation( "Calling symbolic functions with arguments that cannot be coerced into symbolic expressions is deprecated." ) parent = RR if prec is None else RealField(prec) try: x = parent(x) except (ValueError, TypeError): x = parent.complex_field()(x) res = GinacFunction.__call__(self, x, coerce=coerce, hold=hold)
def get_regions(self, B): regions = self._regions if B <= self._N: return [reg for nn,lst in regions.iteritems() if nn < B for reg in lst] F = self._F eps = self._eps newelts = dict([(IntegerRing()(n),[I.gens_reduced()[0] for I in v if I.is_principal()]) for n,v in self._F.ideals_of_bdd_norm(B-1).iteritems() if n >= self._N]) self._N = B for nn in range(len(self._epsto), B): self._epsto.append(self._epsto[nn-1]*eps) for nn, v in newelts.iteritems(): assert not regions.has_key(nn) regions[nn] = [] for q in v: invden = 1/q invden_red = self.fundom_rep(invden) q0 = invden_red-invden m_invden_red = self.fundom_rep(-invden) m_q0 = m_invden_red+invden a, b = self._parent._change_basis(invden_red) am, bm = self._parent._change_basis(m_invden_red) regions[nn].extend([[invden_red,[q0,q],Region(self.embed(invden_red),RealField()(1/nn)),[a,b],nn],[m_invden_red,[m_q0,-q],Region(self.embed(m_invden_red),RealField()(1/nn)),[am,bm],nn]]) for jj in range(1,nn): x = self._epsto[jj] * invden x_red = self.fundom_rep(x) x_red_minus = self.fundom_rep(-x_red) regs = regions[nn] if x_red == regs[0][0] or x_red_minus == regs[0][0]: continue q0_minus = x_red_minus+x q0 = x_red-x q1 = 1/x a, b = self._parent._change_basis(x_red) am, bm = self._parent._change_basis(x_red_minus) regions[nn].extend([[x_red,[q0,q1],Region(self.embed(x_red),RealField()(1/nn)),[a,b],nn],[x_red_minus,[q0_minus,-q1],Region(self.embed(x_red_minus),RealField()(1/nn)),[am,bm],nn]]) return [reg for nn, lst in regions.iteritems() if nn < B for reg in lst]
def coincidence_index(self, prec=0): """ Returns the probability of two randomly chosen characters being equal. """ if prec == 0: RR = RealField() else: RR = RealField(prec) char_dict = {} for i in self._element_list: if i in char_dict: char_dict[i] += 1 else: char_dict[i] = 1 nn = 0 ci_num = 0 for i in char_dict.keys(): ni = char_dict[i] nn += ni ci_num += ni*(ni-1) ci_den = nn*(nn-1) return RR(ci_num)/ci_den
def __init__(self): r""" Create free alphabetic string monoid on generators A-Z. EXAMPLES:: sage: S = AlphabeticStrings(); S Free alphabetic string monoid on A-Z sage: S.gen(0) A sage: S.gen(25) Z sage: S([ i for i in range(26) ]) ABCDEFGHIJKLMNOPQRSTUVWXYZ """ from sage.rings.all import RealField RR = RealField() # The characteristic frequency probability distribution of # Robert Edward Lewand. self._characteristic_frequency_lewand = { "A": RR(0.08167), "B": RR(0.01492), "C": RR(0.02782), "D": RR(0.04253), "E": RR(0.12702), "F": RR(0.02228), "G": RR(0.02015), "H": RR(0.06094), "I": RR(0.06966), "J": RR(0.00153), "K": RR(0.00772), "L": RR(0.04025), "M": RR(0.02406), "N": RR(0.06749), "O": RR(0.07507), "P": RR(0.01929), "Q": RR(0.00095), "R": RR(0.05987), "S": RR(0.06327), "T": RR(0.09056), "U": RR(0.02758), "V": RR(0.00978), "W": RR(0.02360), "X": RR(0.00150), "Y": RR(0.01974), "Z": RR(0.00074)} # The characteristic frequency probability distribution of # H. Beker and F. Piper. self._characteristic_frequency_beker_piper = { "A": RR(0.082), "B": RR(0.015), "C": RR(0.028), "D": RR(0.043), "E": RR(0.127), "F": RR(0.022), "G": RR(0.020), "H": RR(0.061), "I": RR(0.070), "J": RR(0.002), "K": RR(0.008), "L": RR(0.040), "M": RR(0.024), "N": RR(0.067), "O": RR(0.075), "P": RR(0.019), "Q": RR(0.001), "R": RR(0.060), "S": RR(0.063), "T": RR(0.091), "U": RR(0.028), "V": RR(0.010), "W": RR(0.023), "X": RR(0.001), "Y": RR(0.020), "Z": RR(0.001)} alph = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' StringMonoid_class.__init__(self, 26, [ alph[i] for i in range(26) ])
def __init__(self, X, P, codomain=None, check=False): r""" Create the discrete probability space with probabilities on the space X given by the dictionary P with values in the field real_field. EXAMPLES:: sage: S = [ i for i in range(16) ] sage: P = {} sage: for i in range(15): P[i] = 2^(-i-1) sage: P[15] = 2^-16 sage: X = DiscreteProbabilitySpace(S,P) sage: X.domain() (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15) sage: X.set() {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15} sage: X.entropy() 1.9997253418 A probability space can be defined on any list of elements. EXAMPLES:: sage: AZ = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' sage: S = [ AZ[i] for i in range(26) ] sage: P = { 'A':1/2, 'B':1/4, 'C':1/4 } sage: X = DiscreteProbabilitySpace(S,P) sage: X Discrete probability space defined by {'A': 1/2, 'C': 1/4, 'B': 1/4} sage: X.entropy() 1.5 """ if codomain is None: codomain = RealField() if not is_RealField(codomain) and not is_RationalField(codomain): raise TypeError, "Argument codomain (= %s) must be the reals or rationals" % codomain if check: one = sum([P[x] for x in P.keys()]) if is_RationalField(codomain): if not one == 1: raise TypeError, "Argument P (= %s) does not define a probability function" else: if not Abs(one - 1) < 2 ^ (-codomain.precision() + 1): raise TypeError, "Argument P (= %s) does not define a probability function" ProbabilitySpace_generic.__init__(self, X, codomain) DiscreteRandomVariable.__init__(self, self, P, codomain, check)
def quadratic_L_function__numerical(n, d, num_terms=1000): """ Evaluate the Dirichlet L-function (for quadratic character) numerically (in a very naive way). EXAMPLES: First, let us test several values for a given character:: sage: RR = RealField(100) sage: for i in range(5): ....: print("L({}, (-4/.)): {}".format(1+2*i, RR(quadratic_L_function__exact(1+2*i, -4)) - quadratic_L_function__numerical(RR(1+2*i),-4, 10000))) L(1, (-4/.)): 0.000049999999500000024999996962707 L(3, (-4/.)): 4.99999970000003...e-13 L(5, (-4/.)): 4.99999922759382...e-21 L(7, (-4/.)): ...e-29 L(9, (-4/.)): ...e-29 This procedure fails for negative special values, as the Dirichlet series does not converge here:: sage: quadratic_L_function__numerical(-3,-4, 10000) Traceback (most recent call last): ... ValueError: the Dirichlet series does not converge here Test for several characters that the result agrees with the exact value, to a given accuracy :: sage: for d in range(-20,0): # long time (2s on sage.math 2014) ....: if abs(RR(quadratic_L_function__numerical(1, d, 10000) - quadratic_L_function__exact(1, d))) > 0.001: ....: print("Oops! We have a problem at d = {}: exact = {}, numerical = {}".format(d, RR(quadratic_L_function__exact(1, d)), RR(quadratic_L_function__numerical(1, d)))) """ # Set the correct precision if it is given (for n). if is_RealField(n.parent()): R = n.parent() else: R = RealField() if n < 0: raise ValueError('the Dirichlet series does not converge here') d1 = fundamental_discriminant(d) ans = R.zero() for i in range(1, num_terms): ans += R(kronecker_symbol(d1, i) / R(i)**n) return ans
def __init__(self, X, f, codomain=None, check=False): r""" Create free binary string monoid on `n` generators. INPUT: x: A probability space f: A dictionary such that X[x] = value for x in X is the discrete function on X """ if not is_DiscreteProbabilitySpace(X): raise TypeError, "Argument X (= %s) must be a discrete probability space" % X if check: raise NotImplementedError, "Not implemented" if codomain is None: RR = RealField() else: RR = codomain RandomVariable_generic.__init__(self, X, RR) self._function = f
def __init__(self, lfun, prec=None): """ Initialization of the L-function from a PARI L-function. INPUT: - lfun -- a PARI :pari:`lfun` object or an instance of :class:`lfun_generic` - prec -- integer (default: 53) number of *bits* of precision EXAMPLES:: sage: from sage.lfunctions.pari import lfun_generic, LFunction sage: lf = lfun_generic(conductor=1, gammaV=[0], weight=1, eps=1, poles=[1], residues=[-1], v=pari('k->vector(k,n,1)')) sage: L = LFunction(lf) sage: L.num_coeffs() 4 """ if isinstance(lfun, lfun_generic): # preparation using motivic data self._L = lfun.__pari__() if prec is None: prec = lfun.prec elif isinstance(lfun, Gen): # already some PARI lfun self._L = lfun else: # create a PARI lfunction from other input data self._L = pari.lfuncreate(lfun) self._conductor = ZZ(self._L[4]) # needs check self._weight = ZZ(self._L[3]) # needs check if prec is None: self.prec = 53 else: self.prec = PyNumber_Index(prec) self._RR = RealField(self.prec) self._CC = ComplexField(self.prec) # Complex field used for inputs, which ensures exact 1-to-1 # conversion to/from PARI. Since PARI objects have a precision # in machine words (not bits), this is typically higher. For # example, the default of 53 bits of precision would become 64. self._CCin = ComplexField(pari.bitprecision(self._RR(1)))
def scale_by_units(E): r""" Return a model of E reduced with respect to scaling by units, then w.r.t. q1,q2,q3 mod 2,3,2. The latter is Sage's E._reduce_model(). The former is new (but the function here is similar to both one which Nook write for Magma and the ReducedModel() function in Magma); it is only implemented for real quadratic fields so far. INPUT: - ``E`` -- an elliptic curve over a number field K, assumed integral OUTPUT: A model for E, optimally scaled with repect to units when K is real quadratic; unchanged otherwise. """ K = E.base_field() if not K.signature() == (2, 0): return E embs = K.embeddings(RealField(1000)) # lower precision works badly! u = K.units()[0] uv = [e(u).abs().log() for e in embs] c4, c6 = E.c_invariants() c4s = [e(c4) for e in embs] c6s = [e(c6) for e in embs] v = [(x4.abs()**(1 / 4) + x6.abs()**(1 / 6)).log() for x4, x6 in zip(c4s, c6s)] kr = -(v[0] * uv[0] + v[1] * uv[1]) / (uv[0]**2 + uv[1]**2) k1 = kr.floor() k2 = kr.ceil() nv1 = (v[0] + k1 * uv[0])**2 + (v[1] + k1 * uv[1])**2 nv2 = (v[0] + k2 * uv[0])**2 + (v[1] + k2 * uv[1])**2 if nv1 < nv2: k = k1 else: k = k2 return E.scale_curve(u**k)
def frequency_distribution(S, n=1, field=None): """ The probability space of frequencies of n-character substrings of S. """ if isinstance(S, tuple): S = list(S) elif isinstance(S, (str, StringMonoidElement)): S = [S[i:i + n] for i in range(len(S) - n + 1)] if field is None: field = RealField() if isinstance(S, list): P = {} N = len(S) eps = field(1) / N for i in range(N): c = S[i] if P.has_key(c): P[c] += eps else: P[c] = eps return DiscreteProbabilitySpace(S, P, field) raise TypeError, "Argument S (= %s) must be a string, list, or tuple."
def initialize_fundom(self): F = self._F Pts = [self.embed_coords(a,b) for a in [0,1] for b in [0,1]] xmin = min([P.x for P in Pts]) xmax = max([P.x for P in Pts]) ymin = min([P.y for P in Pts]) ymax = max([P.y for P in Pts]) self._aplusbomega = dict([]) rangea = self.rangea_gen(xmin-1,ymin-1,xmax+1,ymax+1) for b in self._ranget: bw = b * self._w for a in rangea(b): self._aplusbomega[(a,b)] = a + bw dx = RealField()(0.49) dy = dx Nx = ceil((xmax-xmin) / dx) Ny = ceil((ymax-ymin) / dy) self._holes = deque([]) for ii, jj in product(range(Nx), range(Ny)): self._holes.append(Hole(self,[xmin+ii*dx,ymin+jj*dy,xmin+(ii+1)*dx,ymin+(jj+1)*dy]))
def __getattr__(self, name): """ EXAMPLE:: sage: DiscreteGaussianSamplerRejection(3.0).foo Traceback (most recent call last): ... AttributeError: 'DiscreteGaussianSamplerRejection' object has no attribute 'foo' """ if name == "rho": # we delay the creation of rho until we actually need it R = RealField(self.precision) self.rho = [ round(self.max_precs * exp( (-(R(x) / R(self.stddev))**2) / R(2))) for x in range(0, self.upper_bound) ] self.rho[0] = self.rho[0] / 2 return self.rho else: raise AttributeError("'%s' object has no attribute '%s'" % (self.__class__.__name__, name))
def quadratic_L_function__numerical(n, d, num_terms=1000): """ Evaluate the Dirichlet L-function (for quadratic character) numerically (in a very naive way). EXAMPLES:: sage: ## Test several values for a given character sage: RR = RealField(100) sage: for i in range(5): ... print "L(" + str(1+2*i) + ", (-4/.)): ", RR(quadratic_L_function__exact(1+2*i, -4)) - quadratic_L_function__numerical(RR(1+2*i),-4, 10000) L(1, (-4/.)): 0.000049999999500000024999996962707 L(3, (-4/.)): 4.99999970000003...e-13 L(5, (-4/.)): 4.99999922759382...e-21 L(7, (-4/.)): ...e-29 L(9, (-4/.)): ...e-29 sage: ## Testing the accuracy of the negative special values sage: ## ---- THIS FAILS SINCE THE DIRICHLET SERIES DOESN'T CONVERGE HERE! ---- sage: ## Test several characters agree with the exact value, to a given accuracy. sage: for d in range(-20,0): ... if abs(RR(quadratic_L_function__numerical(1, d, 10000) - quadratic_L_function__exact(1, d))) > 0.001: ... print "Oops! We have a problem at d = ", d, " exact = ", RR(quadratic_L_function__exact(1, d)), " numerical = ", RR(quadratic_L_function__numerical(1, d)) ... """ ## Set the correct precision if it's given (for n). if is_RealField(n.parent()): R = n.parent() else: R = RealField() d1 = fundamental_discriminant(d) ans = R(0) for i in range(1, num_terms): ans += R(kronecker_symbol(d1, i) / R(i)**n) return ans
def frequency_distribution(self, length=1, prec=0): """ Returns the probability space of character frequencies. The output of this method is different from that of the method :func:`characteristic_frequency() <sage.monoids.string_monoid.AlphabeticStringMonoid.characteristic_frequency>`. One can think of the characteristic frequency probability of an element in an alphabet `A` as the expected probability of that element occurring. Let `S` be a string encoded using elements of `A`. The frequency probability distribution corresponding to `S` provides us with the frequency probability of each element of `A` as observed occurring in `S`. Thus one distribution provides expected probabilities, while the other provides observed probabilities. INPUT: - ``length`` -- (default ``1``) if ``length=1`` then consider the probability space of monogram frequency, i.e. probability distribution of single characters. If ``length=2`` then consider the probability space of digram frequency, i.e. probability distribution of pairs of characters. This method currently supports the generation of probability spaces for monogram frequency (``length=1``) and digram frequency (``length=2``). - ``prec`` -- (default ``0``) a non-negative integer representing the precision (in number of bits) of a floating-point number. The default value ``prec=0`` means that we use 53 bits to represent the mantissa of a floating-point number. For more information on the precision of floating-point numbers, see the function :func:`RealField() <sage.rings.real_mpfr.RealField>` or refer to the module :mod:`real_mpfr <sage.rings.real_mpfr>`. EXAMPLES: Capital letters of the English alphabet:: sage: M = AlphabeticStrings().encoding("abcd") sage: L = M.frequency_distribution().function() sage: sorted(L.items()) <BLANKLINE> [(A, 0.250000000000000), (B, 0.250000000000000), (C, 0.250000000000000), (D, 0.250000000000000)] The binary number system:: sage: M = BinaryStrings().encoding("abcd") sage: L = M.frequency_distribution().function() sage: sorted(L.items()) [(0, 0.593750000000000), (1, 0.406250000000000)] The hexadecimal number system:: sage: M = HexadecimalStrings().encoding("abcd") sage: L = M.frequency_distribution().function() sage: sorted(L.items()) <BLANKLINE> [(1, 0.125000000000000), (2, 0.125000000000000), (3, 0.125000000000000), (4, 0.125000000000000), (6, 0.500000000000000)] Get the observed frequency probability distribution of digrams in the string "ABCD". This string consists of the following digrams: "AB", "BC", and "CD". Now find out the frequency probability of each of these digrams as they occur in the string "ABCD":: sage: M = AlphabeticStrings().encoding("abcd") sage: D = M.frequency_distribution(length=2).function() sage: sorted(D.items()) [(AB, 0.333333333333333), (BC, 0.333333333333333), (CD, 0.333333333333333)] """ if not length in (1, 2): raise NotImplementedError("Not implemented") if prec == 0: RR = RealField() else: RR = RealField(prec) S = self.parent() n = S.ngens() if length == 1: Alph = S.gens() else: Alph = tuple([ x*y for x in S.gens() for y in S.gens() ]) X = {} N = len(self)-length+1 eps = RR(Integer(1)/N) for i in range(N): c = self[i:i+length] if c in X: X[c] += eps else: X[c] = eps # Return a dictionary of probability distribution. This should # allow for easier parsing of the dictionary. from sage.probability.random_variable import DiscreteProbabilitySpace return DiscreteProbabilitySpace(Alph, X, RR)
def an_numerical(self, prec = None, use_database=True, proof=None): r""" Return the numerical analytic order of `Sha`, which is a floating point number in all cases. INPUT: - ``prec`` - integer (default: 53) bits precision -- used for the L-series computation, period, regulator, etc. - ``use_database`` - whether the rank and generators should be looked up in the database if possible. Default is ``True`` - ``proof`` - bool or ``None`` (default: ``None``, see proof.[tab] or sage.structure.proof) proof option passed onto regulator and rank computation. .. note:: See also the :meth:`an` command, which will return a provably correct integer when the rank is 0 or 1. .. WARNING:: If the curve's generators are not known, computing them may be very time-consuming. Also, computation of the L-series derivative will be time-consuming for large rank and large conductor, and the computation time for this may increase substantially at greater precision. However, use of very low precision less than about 10 can cause the underlying PARI library functions to fail. EXAMPLES:: sage: EllipticCurve('11a').sha().an_numerical() 1.00000000000000 sage: EllipticCurve('37a').sha().an_numerical() 1.00000000000000 sage: EllipticCurve('389a').sha().an_numerical() 1.00000000000000 sage: EllipticCurve('66b3').sha().an_numerical() 4.00000000000000 sage: EllipticCurve('5077a').sha().an_numerical() 1.00000000000000 A rank 4 curve:: sage: EllipticCurve([1, -1, 0, -79, 289]).sha().an_numerical() # long time (3s on sage.math, 2011) 1.00000000000000 A rank 5 curve:: sage: EllipticCurve([0, 0, 1, -79, 342]).sha().an_numerical(prec=10, proof=False) # long time (22s on sage.math, 2011) 1.0 See :trac:`1115`:: sage: sha=EllipticCurve('37a1').sha() sage: [sha.an_numerical(prec) for prec in xrange(40,100,10)] # long time (3s on sage.math, 2013) [1.0000000000, 1.0000000000000, 1.0000000000000000, 1.0000000000000000000, 1.0000000000000000000000, 1.0000000000000000000000000] """ if prec is None: prec = RealField().precision() RR = RealField(prec) prec2 = prec+2 RR2 = RealField(prec2) try: an = self.__an_numerical if an.parent().precision() >= prec: return RR(an) else: # cached precision too low pass except AttributeError: pass # it's critical to switch to the minimal model. E = self.Emin r = Integer(E.rank(use_database=use_database, proof=proof)) L = E.lseries().dokchitser(prec=prec2) Lr= RR2(L.derivative(1,r)) # L.derivative() returns a Complex Om = RR2(E.period_lattice().omega(prec2)) Reg = E.regulator(use_database=use_database, proof=proof, precision=prec2) T = E.torsion_order() cp = E.tamagawa_product() Sha = RR((Lr*T*T)/(r.factorial()*Om*cp*Reg)) self.__an_numerical = Sha return Sha
def _sage_(self): """ Convert self to a Sage object. EXAMPLES:: sage: a = axiom(1/2); a #optional - axiom 1 - 2 sage: a.sage() #optional - axiom 1/2 sage: _.parent() #optional - axiom Rational Field sage: gp(axiom(1/2)) #optional - axiom 1/2 sage: fricas(1/2).sage() #optional - fricas 1/2 DoubleFloat's in Axiom are converted to be in RDF in Sage. :: sage: axiom(2.0).as_type('DoubleFloat').sage() #optional - axiom 2.0 sage: _.parent() #optional - axiom Real Double Field sage: axiom(2.1234)._sage_() #optional - axiom 2.12340000000000 sage: _.parent() #optional - axiom Real Field with 53 bits of precision sage: a = RealField(100)(pi) sage: axiom(a)._sage_() #optional - axiom 3.1415926535897932384626433833 sage: _.parent() #optional - axiom Real Field with 100 bits of precision sage: axiom(a)._sage_() == a #optional - axiom True sage: axiom(2.0)._sage_() #optional - axiom 2.00000000000000 sage: _.parent() #optional - axiom Real Field with 53 bits of precision We can also convert Axiom's polynomials to Sage polynomials. sage: a = axiom(x^2 + 1) #optional - axiom sage: a.type() #optional - axiom Polynomial Integer sage: a.sage() #optional - axiom x^2 + 1 sage: _.parent() #optional - axiom Univariate Polynomial Ring in x over Integer Ring sage: axiom('x^2 + y^2 + 1/2').sage() #optional - axiom y^2 + x^2 + 1/2 sage: _.parent() #optional - axiom Multivariate Polynomial Ring in y, x over Rational Field """ P = self._check_valid() type = str(self.type()) if type in ["Type", "Domain"]: return self._sage_domain() if type == "Float": from sage.rings.all import RealField, ZZ prec = max(self.mantissa().length()._sage_(), 53) R = RealField(prec) x, e, b = self.unparsed_input_form().lstrip('float(').rstrip( ')').split(',') return R(ZZ(x) * ZZ(b)**ZZ(e)) elif type == "DoubleFloat": from sage.rings.all import RDF return RDF(repr(self)) elif type.startswith('Polynomial'): from sage.rings.all import PolynomialRing base_ring = P(type.lstrip('Polynomial '))._sage_domain() vars = str(self.variables())[1:-1] R = PolynomialRing(base_ring, vars) return R(self.unparsed_input_form()) #If all else fails, try using the unparsed input form try: import sage.misc.sage_eval return sage.misc.sage_eval.sage_eval(self.unparsed_input_form()) except: raise NotImplementedError
def __init__(self, B, sigma=1, c=None, precision=None): r""" Construct a discrete Gaussian sampler over the lattice `Λ(B)` with parameter ``sigma`` and center `c`. INPUT: - ``B`` -- a basis for the lattice, one of the following: - an integer matrix, - an object with a ``matrix()`` method, e.g. ``ZZ^n``, or - an object where ``matrix(B)`` succeeds, e.g. a list of vectors. - ``sigma`` -- Gaussian parameter `σ>0`. - ``c`` -- center `c`, any vector in `\ZZ^n` is supported, but `c ∈ Λ(B)` is faster. - ``precision`` -- bit precision `≥ 53`. EXAMPLES:: sage: from sage.stats.distributions.discrete_gaussian_lattice import DiscreteGaussianDistributionLatticeSampler sage: n = 2; sigma = 3.0; m = 5000 sage: D = DiscreteGaussianDistributionLatticeSampler(ZZ^n, sigma) sage: f = D.f sage: c = D._normalisation_factor_zz(); c 56.2162803067524 sage: l = [D() for _ in range(m)] sage: v = vector(ZZ, n, (-3,-3)) sage: l.count(v), ZZ(round(m*f(v)/c)) (39, 33) sage: target = vector(ZZ, n, (0,0)) sage: l.count(target), ZZ(round(m*f(target)/c)) (116, 89) sage: from sage.stats.distributions.discrete_gaussian_lattice import DiscreteGaussianDistributionLatticeSampler sage: qf = QuadraticForm(matrix(3, [2, 1, 1, 1, 2, 1, 1, 1, 2])) sage: D = DiscreteGaussianDistributionLatticeSampler(qf, 3.0); D Discrete Gaussian sampler with σ = 3.000000, c=(0, 0, 0) over lattice with basis <BLANKLINE> [2 1 1] [1 2 1] [1 1 2] sage: D() (0, 1, -1) """ precision = DiscreteGaussianDistributionLatticeSampler.compute_precision(precision, sigma) self._RR = RealField(precision) self._sigma = self._RR(sigma) try: B = matrix(B) except (TypeError, ValueError): pass try: B = B.matrix() except AttributeError: pass self.B = B self._G = B.gram_schmidt()[0] try: c = vector(ZZ, B.ncols(), c) except TypeError: try: c = vector(QQ, B.ncols(), c) except TypeError: c = vector(RR, B.ncols(), c) self._c = c self.f = lambda x: exp(-(vector(ZZ, B.ncols(), x) - c).norm() ** 2 / (2 * self._sigma ** 2)) # deal with trivial case first, it is common if self._G == 1 and self._c == 0: self._c_in_lattice = True D = DiscreteGaussianDistributionIntegerSampler(sigma=sigma) self.D = tuple([D for _ in range(self.B.nrows())]) self.VS = FreeModule(ZZ, B.nrows()) return w = B.solve_left(c) if w in ZZ ** B.nrows(): self._c_in_lattice = True D = [] for i in range(self.B.nrows()): sigma_ = self._sigma / self._G[i].norm() D.append(DiscreteGaussianDistributionIntegerSampler(sigma=sigma_)) self.D = tuple(D) self.VS = FreeModule(ZZ, B.nrows()) else: self._c_in_lattice = False
def deriv_at1(self, k=None, prec=None): r""" Compute `L'(E,1)` using `k` terms of the series for `L'(E,1)`, under the assumption that `L(E,1) = 0`. The algorithm used is from Section 7.5.3 of Henri Cohen's book *A Course in Computational Algebraic Number Theory*. INPUT: - ``k`` -- number of terms of the series. If zero or ``None``, use `k = \sqrt{N}`, where `N` is the conductor. - ``prec`` -- numerical precision in bits. If zero or ``None``, use a reasonable automatic default. OUTPUT: A tuple of real numbers ``(L1, err)`` where ``L1`` is an approximation for `L'(E,1)` and ``err`` is a bound on the error in the approximation. .. WARNING:: This function only makes sense if `L(E)` has positive order of vanishing at 1, or equivalently if `L(E,1) = 0`. ALGORITHM: - Compute the root number eps. If it is 1, return 0. - Compute the Fourier coefficients `a_n`, for `n` up to and including `k`. - Compute the sum .. MATH:: 2 \cdot \sum_{n=1}^{k} (a_n / n) \cdot E_1(2 \pi n/\sqrt{N}), where `N` is the conductor of `E`, and `E_1` is the exponential integral function. - Compute a bound on the tail end of the series, which is .. MATH:: 2 e^{-2 \pi (k+1) / \sqrt{N}} / (1 - e^{-2 \pi/\sqrt{N}}). For a proof see [Grigorov-Jorza-Patrascu-Patrikis-Stein]. This is exactly the same as the bound for the approximation to `L(E,1)` produced by :meth:`at1`. EXAMPLES:: sage: E = EllipticCurve('37a') sage: E.lseries().deriv_at1() (0.3059866, 0.000801045) sage: E.lseries().deriv_at1(100) (0.3059997738340523018204836833216764744526377745903, 1.52493e-45) sage: E.lseries().deriv_at1(1000) (0.305999773834052301820483683321676474452637774590771998..., 2.75031e-449) With less numerical precision, the error is bounded by numerical accuracy:: sage: L,err = E.lseries().deriv_at1(100, prec=64) sage: L,err (0.305999773834052302, 5.55318e-18) sage: parent(L) Real Field with 64 bits of precision sage: parent(err) Real Field with 24 bits of precision and rounding RNDU Rank 2 and rank 3 elliptic curves:: sage: E = EllipticCurve('389a1') sage: E.lseries().deriv_at1() (0.0000000, 0.000000) sage: E = EllipticCurve((1, 0, 1, -131, 558)) # curve 59450i1 sage: E.lseries().deriv_at1() (-0.00010911444, 0.142428) sage: E.lseries().deriv_at1(4000) (6.990...e-50, 1.31318e-43) """ sqrtN = sqrt(self.__E.conductor()) if k: k = int(k) else: k = int(ceil(sqrtN)) if prec: prec = int(prec) else: # Estimate number of bits for the computation, based on error # estimate below (the denominator of that error is close enough # to 1 that we can ignore it). # 9.065 = 2*Pi/log(2) # 1.443 = 1/log(2) # 12 is an arbitrary extra number of bits (it is chosen # such that the precision is 24 bits when the conductor # equals 11 and k is the default value 4) prec = int(9.065 * k / sqrtN + 1.443 * log(k)) + 12 R = RealField(prec) # Compute error term with bounded precision of 24 bits and # round towards +infinity Rerror = RealField(24, rnd='RNDU') if self.__E.root_number() == 1: # Order of vanishing at 1 of L(E) is even and assumed to be # positive, so L'(E,1) = 0. return (R.zero(), Rerror.zero()) an = self.__E.anlist(k) # list of Sage Integers pi = R.pi() sqrtN = R(self.__E.conductor()).sqrt() v = exp_integral.exponential_integral_1(2 * pi / sqrtN, k) # Compute series sum and accumulate floating point errors L = R.zero() error = Rerror.zero() # Sum of |an[n]|/n sumann = Rerror.zero() for n in xrange(1, k + 1): term = (v[n - 1] * an[n]) / n L += term error += term.epsilon(Rerror) * 5 + L.ulp(Rerror) sumann += Rerror(an[n].abs()) / n L *= 2 # Add error term for exponential_integral_1() errors. # Absolute error for 2*v[i] is 4*max(1, v[0])*2^-prec if v[0] > 1.0: sumann *= Rerror(v[0]) error += (sumann >> (prec - 2)) # Add series error (we use (-2)/(z-1) instead of 2/(1-z) # because this causes 1/(1-z) to be rounded up) z = (-2 * pi / sqrtN).exp() zpow = ((-2 * (k + 1)) * pi / sqrtN).exp() error += ((-2) * Rerror(zpow)) / Rerror(z - 1) return (L, error)
def at1(self, k=None, prec=None): r""" Compute `L(E,1)` using `k` terms of the series for `L(E,1)` as explained in Section 7.5.3 of Henri Cohen's book *A Course in Computational Algebraic Number Theory*. If the argument `k` is not specified, then it defaults to `\sqrt{N}`, where `N` is the conductor. INPUT: - ``k`` -- number of terms of the series. If zero or ``None``, use `k = \sqrt{N}`, where `N` is the conductor. - ``prec`` -- numerical precision in bits. If zero or ``None``, use a reasonable automatic default. OUTPUT: A tuple of real numbers ``(L, err)`` where ``L`` is an approximation for `L(E,1)` and ``err`` is a bound on the error in the approximation. This function is disjoint from the PARI ``elllseries`` command, which is for a similar purpose. To use that command (via the PARI C library), simply type ``E.pari_mincurve().elllseries(1)``. ALGORITHM: - Compute the root number eps. If it is -1, return 0. - Compute the Fourier coefficients `a_n`, for `n` up to and including `k`. - Compute the sum .. MATH:: 2 \cdot \sum_{n=1}^{k} \frac{a_n}{n} \cdot \exp(-2*pi*n/\sqrt{N}), where `N` is the conductor of `E`. - Compute a bound on the tail end of the series, which is .. MATH:: 2 e^{-2 \pi (k+1) / \sqrt{N}} / (1 - e^{-2 \pi/\sqrt{N}}). For a proof see [Grigov-Jorza-Patrascu-Patrikis-Stein]. EXAMPLES:: sage: L, err = EllipticCurve('11a1').lseries().at1() sage: L, err (0.253804, 0.000181444) sage: parent(L) Real Field with 24 bits of precision sage: E = EllipticCurve('37b') sage: E.lseries().at1() (0.7257177, 0.000800697) sage: E.lseries().at1(100) (0.7256810619361527823362055410263965487367603361763, 1.52469e-45) sage: L,err = E.lseries().at1(100, prec=128) sage: L 0.72568106193615278233620554102639654873 sage: parent(L) Real Field with 128 bits of precision sage: err 1.70693e-37 sage: parent(err) Real Field with 24 bits of precision and rounding RNDU Rank 1 through 3 elliptic curves:: sage: E = EllipticCurve('37a1') sage: E.lseries().at1() (0.0000000, 0.000000) sage: E = EllipticCurve('389a1') sage: E.lseries().at1() (-0.001769566, 0.00911776) sage: E = EllipticCurve('5077a1') sage: E.lseries().at1() (0.0000000, 0.000000) """ sqrtN = sqrt(self.__E.conductor()) if k: k = int(k) else: k = int(ceil(sqrtN)) if prec: prec = int(prec) else: # Use the same precision as deriv_at1() below for # consistency prec = int(9.065 * k / sqrtN + 1.443 * log(k)) + 12 R = RealField(prec) # Compute error term with bounded precision of 24 bits and # round towards +infinity Rerror = RealField(24, rnd='RNDU') if self.__E.root_number() == -1: return (R.zero(), Rerror.zero()) an = self.__E.anlist(k) # list of Sage Integers pi = R.pi() sqrtN = R(self.__E.conductor()).sqrt() z = (-2 * pi / sqrtN).exp() zpow = z # Compute series sum and accumulate floating point errors L = R.zero() error = Rerror.zero() for n in xrange(1, k + 1): term = (zpow * an[n]) / n zpow *= z L += term # We express relative error in units of epsilon, where # epsilon is a number divided by 2^precision. # Instead of multiplying the error by 2 after the loop # (to account for L *= 2), we already multiply it now. # # For multiplication and division, the relative error # in epsilons is bounded by (1+e)^n - 1, where n is the # number of operations (assuming exact inputs). # exp(x) additionally multiplies this error by abs(x) and # adds one epsilon. The inputs pi and sqrtN each contribute # another epsilon. # Assuming that 2*pi/sqrtN <= 2, the relative error for z is # 7 epsilon. This implies a relative error of (8n-1) epsilon # for zpow. We add 2 for the computation of term and 1/2 to # compensate for the approximation (1+e)^n = 1+ne. # # The error of the addition is at most half an ulp of the # result. # # Multiplying everything by two gives: error += term.epsilon(Rerror) * (16 * n + 3) + L.ulp(Rerror) L *= 2 # Add series error (we use (-2)/(z-1) instead of 2/(1-z) # because this causes 1/(1-z) to be rounded up) error += ((-2) * Rerror(zpow)) / Rerror(z - 1) return (L, error)