def slog(self,z,debug=0): """ slog continued into the complex plane where possible. Should always be possible if the real part of the development point is left from the lower fixed point """ z = num(z,self.iprec) if z.is_real(): res=self.slog_real(z,debug) elif self.lfp == None: #Only complex fixed points res=self.slog2(z) else: res=self.slog1(z) if self.prec == None: return res else: return num(res,self.prec)
def logb(self,z): """ Logarithm with branch cut such that for imaginary values y: -pi < y <= pi for real fixpoint otherwise: 2*pi*(k-1) <= y < 2*pi*k for k>=1 2*pi*k < y <= 2*pi*(k+1) for k<=-1 where k is the fixpoint_number """ k = self.fixpoint_number if self.real_fp: res = z.log() elif k>=1: res = (log(-z.conjugate())-num(i*(2*pi*k-pi),self.iprec)).conjugate() elif k<=-1: res = log(-z)+num(i*(2*pi*k+pi),self.iprec) return res/self.lnb
def exp_fixpoint(b=e,k=1,prec=53,iprec=None): """ Counting fixpoints as follows: For b<=e^(1/e): 0 denotes the lower fixpoint on the real axis, 1 denotes the upper fixed point on the real axis, 2 denotes the fixpoint in the upper halfplane closest to the real axis, 3 the second-closest, etc For b>e^(1/e): 1 denotes the fixpoint in the upper halfplane closest to the real axis, 2 the second-closest fixed point, etc. Or in other words order the repelling fixed points of the upper halfplane by their distance from the real axis, give the closest fixed point the number 1. The attracting fixed point (existent only for b<e**(1/e)) gets index 0. Fixpoint k mirrored into the lower halfplane gets index -k. """ if iprec==None: iprec=prec+10 b=num(b,iprec) if k==0: assert b <= e**(1/e), "b must be <= e**(1/e) for fixpoint number 0, but b=" + repr(b) if k>=0: branch = -k elif b <= e**(1/e) and k==-1: branch = -1 else: branch = -k-1 mpmath.mp.prec = iprec fp = mpmath.lambertw(-mpmath.ln(b),branch)/(-mpmath.ln(b)) if type(fp) == sage.libs.mpmath.ext_main.mpf: return num(fp,prec) return ComplexField(prec)(fp.real,fp.imag)
def slog_real(self,x,debug=0): """ Development point is x0 real continued slog """ if self.iprec != None: x = num(x,self.iprec) b = self.b x0 = self.x0 pfp = self.pfp lfp = self.lfp if lfp == None: direction = 1 elif x < lfp and x0 < lfp: direction = 1 elif pfp < x and pfp < x0: direction = 1 elif lfp < x and x < pfp and lfp < x0 and x0 < pfp: direction = -1 else: print "x and x0 must be in the same segment of R divided by the lower and upper fixed point", "x:",x,"x0:",x0,"lfp:",lfp,"ufp",pfp return NaN n=0 while direction*(x - x0) < 0: if debug>=2: print n,':','x:',x,'x0',x0,'dir',direction xp = x x = b**x n+=1 if n>0: if abs(xp-x0) < abs(x-x0): n-=1 x=xp if debug>=1: print 'x->b^x n:',n,'x:',x return self.c + self.slog_raw0(x) - n while direction*(x - x0) > 0 and x>0: if debug>=2: print n,':','x:',x,'x0',x0,'dir',direction xp = x x = x.log(b) n+=1 if n>0 and abs(xp-x0) < abs(x-x0): n-=1 x=xp if debug>=1: print 'x->log_b(x) n:',n,'x:',x return self.c + self.slog_raw0(x) + n
def iterate(self,x,debug=0): iprec=self.iprec prec=self.prec z0= self.fp xin = x err=2.0**(-prec) if debug>=1: print 'N:',self.N,'iprec:',iprec,'prec:',prec,'z0:',z0,'err:',err #lnb = b.log() n = 0 xn = num(x,iprec) yn = self.iterate_raw0(xn) while True: yp=yn xp=x n += 1 if self.attracting: xn = self.f(xn) else: xn = self.fi(xn) yn = self.iterate_raw0(xn) if self.attracting: for k in range(n): yn = self.fi(yn) else: for k in range(n): yn = self.f(yn) if self.attracting: d = abs(yn - yp) else: d = abs(yn - yp) if debug >=2: print n,":","d:",d.n(20),"yn:",yn,"xn:",xn if xp == xn: if debug>=0: print "slog: increase iprec(",iprec,") or decrease prec(",prec,") to get a result for x:",x return NaN if d<err: res = yn.n(prec) if debug>=1: print 'res:',res,'n:',n,'d:',d.n(20),'err:',err return res
def slog(self,x,debug=0): iprec=self.iprec prec=self.prec b = self.b z0= self.fp a = z0.log() xin = x err=2.0**(-prec) if debug>=1: print 'N:',self.N,'iprec:',iprec,'prec:',prec,'b:',b,'z0:',z0,'a:',a,'err:',err #lnb = b.log() n = 0 xn = num(x,iprec) yn = self.slog_raw0(xn) while True: yp=yn xp=x n += 1 if self.attracting: xn = b**xn else: xn = self.logb(xn) yn = self.slog_raw0(xn) if self.attracting: d = abs(yn - (yp+1)) else: d = abs(yn - (yp-1)) if debug >=2: print n,":","d:",d.n(20),"yn:",yn,"xn:",xn if xp == xn or d == 1: if debug>=0: print "slog: increase iprec(",iprec,") or decrease prec(",prec,") to get a result for x:",x,"b:",b return NaN if d<err: res = self.c + yn.n(prec) if self.attracting: res -= n else: res += n if debug>=1: print 'res:',res,'n:',n,'d:',d.n(20),'err:',err return res
def slog_subtractive(self,x,debug=0): iprec=self.iprec prec=self.prec b = self.b z0= self.fp xin = x err=2.0**(-prec) if debug>=1: print 'N:',self.N,'iprec:',iprec,'prec:',prec,'b:',b,'z0:',z0,'err:',err #lnb = b.log() n = 0 xn = num(x,iprec) yn = self.slog_raw0(xn) while True: yp=yn xp=xn n += 1 if self.attracting: xn = b**xn else: xn = self.log(xn)/self.lnb yn = self.slog_raw0(xn) if self.attracting: d = abs(yn - (yp+1)) else: d = abs(yn - (yp-1)) if debug >=2: print n,":","d:",d.n(20),"yn:",yn,"xn:",xn if xp == xn or d == 1: if debug>=0: print "slog: precision failed for x:",x return NaN if d<err: res = self.c + yn.n(prec) if self.attracting: res -= n else: res += n if debug>=1: print 'res:',res,'n:',n,'d:',d.n(20),'err:',err return res
def chi(self,x,debug=0): n = 0 xn = num(x,self.iprec) yn = self.chi_raw0(xn) if yn.is_zero(): return self.R(0) a = self.fpd err=2.0**(-self.prec) if debug>=1: print 'chi: x',x,'N:',self.N,'iprec:',self.iprec,'prec:',self.prec,'b:',self.b,'fp:',self.fp,'a:',a,'err:',err while True: if xn.is_zero(): return self.R(NaN) yp=yn xp=xn n += 1 if self.attracting: xn = self.b**xn else: xn = self.log(xn)/self.lnb yn = self.chi_raw0(xn) if self.attracting: d = abs(log(yn/(yp*a))) else: d = abs(log(yn/(yp/a))) if debug >=2: print n,":","d:",d.n(20),"yn:",yn,"xn:",xn if xp == xn or d == 1: if debug>=0: print "chi: precision failed for x:",x return self.R(NaN) if d<err: if self.attracting: res = yn/a**n else: res = yn*a**n if debug>=1: print 'chi:',res,'n:',n,'d:',d.n(20),'err:',err return res
def slog1(self,z): """ In the complex plane continued slog for base <= eta and x0 near attracting fixpoint """ slog = self.slog1 slog_raw = self.slog_raw b = self.b x0 = self.x0 N = self.N z = num(z,self.iprec) r = self.r n = 0 while abs(z-x0) > r/2: z = b**z n += 1 return self.c + self.slog_raw0(z) - n
def chii(self,x,debug=0): xn = num(x,self.iprec) yn = self.chii_raw0(xn) a = self.fpd if debug>=1: print 'chii: x:',x,'prec:',self.prec,'b:',self.b,'fp:',self.fp,'a:',a n = 0 while True: yp=yn xp=xn n += 1 if self.attracting: xn *= a else: xn /= a yn = self.chii_raw0(xn) #yn = self.fp + self.direction*xn for m in range(n): if self.attracting: yn = self.log(yn)/self.lnb else: yn = self.b**yn d = abs(yn-yp) if debug >=2: print n,":","d:",d.n(20),"yn:",yn,"xn:",xn if d.is_NaN(): #p = PrecisionError(self.iprec,self.prec,"chii","x:",x) #raise p if debug>=0: print "chii: precision failed for x:",x return d if d<self.err: res = yn if debug>=1: print 'chii:',res,'n:',n,'d:',d.n(20),'err:',self.err return res
def slog2(self,z): """ In the complex plane continued slog for base > eta """ b = self.b z = num(z,self.iprec) n = 0 while self.cmp_ir(z) == -1: z = b**z n += 1 if n > 0: return self.c + self.slog_raw0(z) - n n = 0 while self.cmp_ir(z) == +1: z = z.log(b) n+=1 assert self.cmp_ir(z) == 0, self.cmp_ir(z) return self.c + self.slog_raw0(z) + n
def __init__(self,b=sqrt(2),fixpoint_number=0,u=None,prec=53,iprec=None,N=5,direction=-1,debug=0): """ for the numbering of fixed points see function exp_fixpoint u is the initial value such that slog(u)=0 and sexp(0)=u for the attracting fixed point it defaults to u=1 otherwise it is undetermined direction can be +1 (real values when approaching from the right of the fixpoint) or -1 (real values when approaching from the left of the fixed point) """ if debug >= 1: if b==sqrt(2): print 'b:',b if fixpoint_number==0: print 'fixpoint_number:',fixpoint_number if prec==53: print 'prec:',prec if N==5: print 'N:',N if direction==-1: print 'direction:',direction bsym = b self.bsym = bsym self.N = N if iprec==None: iprec=prec+10 if debug>=1: print 'iprec:',iprec self.iprec = iprec self.prec = prec self.fixpoint_number = fixpoint_number eta = e**(1/e) bname = repr(bsym).strip('0').replace('.',',') if bsym == sqrt(2): bname = "sqrt2" if bsym == eta: bname = "eta" self.lnb = num(ln(bsym),iprec) b = num(bsym,iprec) self.b = b self.path = "savings/islog_%s"%bname + "_N%04d"%N + "_iprec%05d"%iprec + "_fp%d"%fixpoint_number if iprec != None: b = num(b,iprec) self.b = b else: if b == e and x0 == 0: R = QQ else: R = SR self.attracting = False if b < eta and fixpoint_number == 0: self.attracting = True self.real_fp = False if b <= eta and abs(fixpoint_number) <= 1: self.real_fp = True self.parabolic = False if self.bsym == eta and abs(fixpoint_number) <= 1: self.parabolic = True if direction == +1: self.attracting = False if direction == -1: self.attracting = True if b <= eta and abs(fixpoint_number) <= 1: R = RealField(iprec) else: R = ComplexField(iprec) self.R = R if self.parabolic: fp = R(e) #just for not messing it into a complex number else: fp = exp_fixpoint(b,fixpoint_number,prec=iprec) self.fp = fp #fixpoint self.fpd = self.log(fp) #fixpont derivative self.direction = direction FR = FormalPowerSeriesRing(R) fps = FR.Dec_exp(FR([0,b.log()])).rmul(fp) if self.parabolic: fps=fps.set_item(1,1).reclass() if debug>=1: print "fp:",fp [rho,ps] = fps.abel_coeffs() if debug>=2: print 'fps:',fps if debug>=2: print 'rho:',rho if debug>=2: print 'abel_ps:',ps self.chi_ps = fps.schroeder() self.chipoly = self.chi_ps.polynomial(N+1) self.chi_raw0 = lambda z: self.chipoly(direction*(z-self.fp)) PR = PolynomialRing(R,'x') self.slogpoly = ps.polynomial(N) if debug>=2: print self.slogpoly self.slog_raw0 = lambda z: rho*(direction*(z-self.fp)).log() + self.slogpoly(z-self.fp) #slog(u)==0 self.c = 0 if self.attracting and direction==-1 and u==None: u=1 if debug>=1: print 'u:',u if not u==None: self.c = -self.slog(u) pass
def __init__(self,f,N,iprec=512,u=None,x0=0,fname=None,extendable=True): """ x0 is the development point for the Carleman matrix for the abel function u is the initial value such that abel(u)=0 or equivalently super(0)=u if no u is specified we have abel(x0)=0 iprec=None means try to work with the rational numbers if it is extendable then you can increase N without recomputing everything. """ self.fps = None if isinstance(f,sage.symbolic.expression.Expression): x = f.variables()[0] f = f.function(x) if isinstance(f,FormalPowerSeries): self.fps = f f = f.polynomial(N-1) self.f = f self.N = N self.iprec = iprec x0sym = x0 self.x0sym = x0sym self.prec = None self.extendable = extendable self.u = u x0name = repr(x0sym) if x0name.find('.') > -1: if x0.is_real(): x0name = repr(float(x0sym)).strip('0').replace('.',',') else: x0name = repr(complex(x0sym)).strip('0').replace('.',',') # by some reason save does not work with additional . inside the path if iprec==None: iprec_part = 'QQ' else: iprec_part = '%05d'%iprec self.path = "savings/iabel_%s"%fname + "_N%04d"%N + "_iprec" + iprec_part + "_a%s"%x0name if iprec != None: x0 = num(x0sym,iprec) if x0.is_real(): R = RealField(iprec) else: R = ComplexField(iprec) else: R = QQ self.x0 = x0 self.R = R #Carleman matrix #too slow #C = Matrix([ [ln(b)**n/factorial(n)*sum([binomial(m,k)*k**n*(b**x0)**k*(-x0)**(m-k) for k in range(m+1)]) for n in range(N)] for m in range(N)]) if self.fps == None: x = self.f.args()[0] coeffs = taylor(self.f.substitute({x:x+x0sym})-x0sym,x,0,N-1).polynomial(self.R) coeffs = [coeffs[n] for n in xrange(N-1)] else: coeffs = [ self.fps[n] for n in xrange(0,N) ] print "taylor computed" C = self.fast_carleman_matrix(coeffs) self.A = C.submatrix(1,0,N-1,N-1) - identity_matrix(R,N).submatrix(1,0,N-1,N-1) print "A computed." self._init_abel()
def abel(self,x): x = num(x,self.iprec) res = self.abel_raw0(x) if self.prec == None: return res return res.n(self.prec)
def __init__(self,b,N,iprec=512,u=None,x0=0): """ x0 is the development point for the Carleman matrix for the slog u is the initial value such that slog(u)=0 or equivalently sexp(0)=u if no u is specified we have slog(x0)=0 """ bsym = b self.bsym = bsym self.N = N self.iprec = iprec x0sym = x0 self.x0sym = x0sym self.prec = None bname = repr(bsym).strip('0').replace('.',',') if bsym == sqrt(2): bname = "sqrt2" if bsym == e**(1/e): bname = "eta" x0name = repr(x0sym) if x0name.find('.') > -1: if x0.is_real(): x0name = repr(float(x0sym)).strip('0').replace('.',',') else: x0name = repr(complex(x0sym)).strip('0').replace('.',',') # by some reason save does not work with additional . inside the path self.path = "savings/itet_%s"%bname + "_N%04d"%N + "_iprec%05d"%iprec + "_a%s"%x0name if iprec != None: b = num(bsym,iprec) self.b = b x0 = num(x0sym,iprec) if x0.is_real(): R = RealField(iprec) else: R = ComplexField(iprec) self.x0 = x0 else: if b == e and x0 == 0: R = QQ else: R = SR self.R = R #Carleman matrix if x0 == 0: #C = Matrix([[ m**n*log(b)**n/factorial(n) for n in range(N)] for m in range(N)]) coeffs = [ln(b)**n/factorial(n) for n in xrange(N)] else: #too slow #C = Matrix([ [ln(b)**n/factorial(n)*sum([binomial(m,k)*k**n*(b**x0)**k*(-x0)**(m-k) for k in range(m+1)]) for n in range(N)] for m in range(N)]) coeffs = [b**x0-x0]+[b**x0*ln(b)**n/factorial(n) for n in xrange(1,N)] def psmul(A,B): N = len(B) return [sum([A[k]*B[n-k] for k in xrange(n+1)]) for n in xrange(N)] C = Matrix(R,N) row = vector(R,[1]+(N-1)*[0]) C[0] = row for m in xrange(1,N): row = psmul(row,coeffs) C[m] = row A = (C - identity_matrix(N)).submatrix(1,0,N-1,N-1) self.A = A print "A computed." if iprec != None: A = num(A,iprec) row = A.solve_left(vector([1] + (N-2)*[0])) print "A solved." self.slog0coeffs = [0]+[row[n] for n in range(N-1)] self.slog0poly = PolynomialRing(R,'x')(self.slog0coeffs[:int(N)/2]) slog0ps = FormalPowerSeriesRing(R)(self.slog0coeffs) sexp0ps = slog0ps.inv() #print self.slog0ps | self.sexp0ps self.sexp0coeffs = sexp0ps[:N] self.sexp0poly = PolynomialRing(R,'x')(self.sexp0coeffs[:int(N)/2]) self.slog_raw0 = lambda z: self.slog0poly(z-self.x0) print "slog reversed." #the primary or the upper fixed point pfp = exp_fixpoint(b,1,prec=iprec) self.pfp = pfp r = abs(x0-pfp) #lower fixed point lfp = None if b <= R(e**(1/e)): lfp = exp_fixpoint(b,0,prec=iprec) r = min(r,abs(x0-lfp)) self.lfp = lfp self.r = r self.c = 0 if not u == None: self.c = - self.slog(u)