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
Exemple #3
0
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)