예제 #1
0
    def __init__(self,G,prec=500,verbose=None):
        r"""
        Creates an ambient space of Maass waveforms
        (i.e. there are apriori no members).

        INPUT:

            - `'G``    -- subgroup of the modular group
            - ``prec`` -- default working precision in bits 

        EXAMPLES::


            sage: S=MaassWaveForms(Gamma0(1)); S
            Space of Maass waveforms on the group G:
            Arithmetic Subgroup of PSL2(Z) with index 1. Given by: 
            perm(S)=()
            perm(ST)=()
            Constructed from G=Modular Group SL(2,Z)

        """
        from mysubgroup import MySubgroup
        if(not isinstance(G, MySubgroup)):
            if(isinstance(G,int) or isinstance(G,sage.rings.integer.Integer)):
                self._G=MySubgroup(Gamma0(G))
            else:
                try:
                    self._G=MySubgroup(G)
                except TypeError:
                    raise TypeError,"Incorrect input!! Need subgroup of PSL2Z! Got :%s" %(G)
        else:
            self._G=G

        self.verbose=verbose
        self.prec=prec
        self._Weyl_law_const=self._Weyl_law_consts()
        maass_forms=dict() # list of members 
        if(verbose==None):
            self._verbose=0 # output debugging stuff or not
        else:
            self._verbose=verbose
        self._symmetry=None
예제 #2
0
class MaassWaveForms (Parent):
    r"""
    Describes a space of Maass waveforms
    """
    def __init__(self,G,prec=500,verbose=None):
        r"""
        Creates an ambient space of Maass waveforms
        (i.e. there are apriori no members).

        INPUT:

            - `'G``    -- subgroup of the modular group
            - ``prec`` -- default working precision in bits 

        EXAMPLES::


            sage: S=MaassWaveForms(Gamma0(1)); S
            Space of Maass waveforms on the group G:
            Arithmetic Subgroup of PSL2(Z) with index 1. Given by: 
            perm(S)=()
            perm(ST)=()
            Constructed from G=Modular Group SL(2,Z)

        """
        from mysubgroup import MySubgroup
        if(not isinstance(G, MySubgroup)):
            if(isinstance(G,int) or isinstance(G,sage.rings.integer.Integer)):
                self._G=MySubgroup(Gamma0(G))
            else:
                try:
                    self._G=MySubgroup(G)
                except TypeError:
                    raise TypeError,"Incorrect input!! Need subgroup of PSL2Z! Got :%s" %(G)
        else:
            self._G=G

        self.verbose=verbose
        self.prec=prec
        self._Weyl_law_const=self._Weyl_law_consts()
        maass_forms=dict() # list of members 
        if(verbose==None):
            self._verbose=0 # output debugging stuff or not
        else:
            self._verbose=verbose
        self._symmetry=None

    def _repr_(self):
        r"""
        Return the string representation of self.

        EXAMPLES::


            sage: M=MaassWaveForms(MySubgroup(Gamma0(1)));M
            Space of Maass waveforms on the group G:
            Arithmetic Subgroup of PSL2(Z) with index 1. Given by:
                perm(S)=()
                perm(ST)=()
            Constructed from G=Modular Group SL(2,Z)


        """
        s="Space of Maass waveforms on the group G:\n"+str(self._G)
        return s

    def __reduce__(self):
        r""" Used for pickling.
        """
        return(MaassWaveForms,(self._G,self.prec,self.verbose))

    def __cmp__(self,other):
        r""" Compare self to other
        """
        if(self._G <> other._G or self.prec<>other.prec):
            return False
        else:
            return True
        
    def get_element_in_range(self,R1,R2,ST=None,neps=10):
        r""" Finds element of the space self with R in the interval R1 and R2

        INPUT:

        - ``R1`` -- lower bound (real)
        - ``R1`` -- upper bound (real)
        
        """
        if(ST <>None):
            ST0=ST
        else:
            ST0=self._ST
        l=self.split_interval(R1,R2)
        if(self._verbose>1):
            print "Split into intervals:"
            for [r1,r2,y] in l:
                print "[",r1,",",r2,"]:",y
        Rl=list()
        for [r1,r2,y] in l:
            [R,er]=find_single_ev(self,r1,r2,Yset=y,ST=ST0,neps=neps)
            Rl.append([R,er])
        print "R=",R
        print "er=",er


    def _Weyl_law_consts(self):
        r"""
        Compute constants for the Weyl law on self._G

        OUTPUT:

        - tuple of real numbers

        EXAMPLES::


            sage: M=MaassWaveForms(MySubgroup(Gamma0(1)))
            sage: M._Weyl_law_consts()
            (0, 2/pi, (log(pi) - log(2) + 2)/pi, 0, -2)
        """
        import mpmath
        pi=mpmath.fp.pi
        ix=Integer(self._G.index())
        nc=Integer(len(self._G.cusps()))
        if(self._G.is_congruence()):
            lvl=Integer(self._G.level())
        else:
            lvl=0
        n2=Integer(self._G.nu2())
        n3=Integer(self._G.nu3())
        c1=ix/Integer(12)
        c2=Integer(2)*nc/pi
        c3=nc*(Integer(2)-ln(Integer(2))+ln(pi))/pi
        if(lvl<>0):
            A=1
            for q in divisors(lvl):
                num_prim_dc=0
                DG=DirichletGroup(q)
                for chi in DG.list():
                    if(chi.is_primitive()):
                        num_prim_dc=num_prim_dc+1
                for m in divisors(lvl):
                    if(lvl % (m*q) == 0   and m % q ==0 ): 
                        fak=(q*lvl)/gcd(m,lvl/m)
                        A=A*Integer(fak)**num_prim_dc        
            c4=-ln(A)/pi
        else:
            c4=Integer(0)
        # constant term
        c5=-ix/144+n2/8+n3*2/9-nc/4-1
        return (c1,c2,c3,c4,c5)

    def Weyl_law_N(self,T,T1=None):
        r"""
        The counting function for this space. N(T)=#{disc. ev.<=T}
        
        INPUT:
        
        -  ``T`` -- double


        EXAMPLES::

            sage: M=MaassWaveForms(MySubgroup(Gamma0(1))
            sage: M.Weyl_law_N(10)
            0.572841337202191
            
        """
        (c1,c2,c3,c4,c5)=self._Weyl_law_const
        cc1=RR(c1); cc2=RR(c2); cc3=RR(c3); cc4=RR(c4); cc5=RR(c5)
        #print "c1,c2,c3,c4,c5=",cc1,cc2,cc3,cc4,cc5
        t=sqrt(T*T+0.25)
        try: 
            lnt=ln(t)
        except TypeError:
            lnt=mpmath.ln(t)
        #print "t,ln(t)=",t,lnt
        NT=cc1*t*t-cc2*t*lnt+cc3*t+cc4*t+cc5
        if(T1<>None):
            t=sqrt(T1*T1+0.25)
            NT1=cc1*(T1*T1+0.25)-cc2*t*ln(t)+cc3*t+cc4*t+cc5
            return RR(abs(NT1-NT))
        else:
            return RR(NT)

    def next_eigenvalue(self,R):
        r"""
        An estimate of where the next eigenvlue will be, i.e. the smallest R1>R so that N(R1)-N(R)>=1

        INPUT:
        - ``R`` -- real > 0

        OUTPUT:
        - real > R

        EXAMPLES::

            sage: M.next_eigenvalue(10.0)
            12.2500000000000

        
        """
        #cdef nmax
        N=self.Weyl_law_N(R)
        try:
            for j in range(1,10000):
                R1=R+j*RR(j)/100.0
                N1=self.Weyl_law_N(R1)
                if(N1-N >= 1.0):
                    raise StopIteration()
        except StopIteration:
            return R1
        else:
            raise ArithmeticError,"Could not find next eigenvalue! in interval: [%s,%s]" %(R,R1)
        
    def Weyl_law_Np(self,T,T1=None):
        r"""
        The derviative of the counting function for this space. N(T)=#{disc. ev.<=T}
        
        INPUT:
        
        -  ``T`` -- double


        EXAMPLES::

            sage: M=MaassWaweForms(MySubgroup(Gamma0(1))
            sage: M.Weyl_law_Np(10)
        
        """
        (c1,c2,c3,c4,c5)=self._Weyl_law_const
        cc1=RR(c1); cc2=RR(c2); cc3=RR(c3); cc4=RR(c4); cc5=RR(c5)
        #print "c1,c2,c3,c4,c5=",c1,c2,c3,c4,c5
        NpT=2.0*cc1*T-cc2*(ln(T)+1.0)+cc3+cc4
        return RR(NpT)


    #### Split an interv
    def split_interval(self,R1,R2):
        r"""
        Split an interval into pieces, each containing (on average) at most one
        eigenvalue as well as a 0<Y<Y0 s.t. K_IR(Y) has no zero here

        INPUT:
        
            - ''R1'' -- real
            - ''R2'' -- real

        OUPUT:

            - list of triplets (r1,r2,y) where [r1,r2] does not contain a zero of K_ir(y)

        EXAMPLES::


            sage: M._next_kbes
            sage: l=M.split_interval(9.0,11.0)
            sage: print l[0],'\n',l[1],'\n',l[2],'\n',l[3]
            (9.00000000000000, 9.9203192604549457, 0.86169527676551638)
            (9.9203192704549465, 10.135716354265259, 0.86083358148875089)
            (10.13571636426526, 10.903681677771321, 0.86083358148875089)
            (10.903681687771321, 11.0000000000000, 0.85997274790726208)
            
        """
        # It is enough to work with double precision
        base=mpmath.fp
        pi=base.pi
        # Locate all zeros of K_IR(Y0) first
        #def f(r):
        #    ir=base.mpc(0 ,r)
        #    return base.besselk(ir,Y0)
        # First we find the next zero 
        # First split into intervals having at most one zero
        ivs=list()
        rnew=R1; rold=R1
        while (rnew < R2):
            rnew=min(R2,self.next_eigenvalue(rold))
            if( abs(rold-rnew)==0.0):
                print "ivs=",ivs
                exit
            iv=(rold,rnew)
            ivs.append(iv)
            rold=rnew

        # We now need to split these intervals into pieces with at most one zero of the K-Bessel function
        Y00=base.mpf(0.995)*base.sqrt(base.mpf(3))/base.mpf(2 *self._G._level)
        new_ivs=list()
        for (r1,r2) in ivs:
            print "r1,r2=",r1,r2
            Y0=Y00; r11=r1
            i=0
            while(r11 < r2 and i<1000):
                t=self._next_kbessel_zero(r11,r2,Y0*pi);i=i+1
                print "t=",t
                iv=(r11,t,Y0); new_ivs.append(iv)
                # must find Y0 s.t. |besselk(it,Y0)| is large enough
                Y1=Y0
                k=base.besselk(base.mpc(0,t),Y1).real*mpmath.exp(t*0.5*base.pi)
                j=0
                while(j<1000 and abs(k)<1e-3):
                    Y1=Y1*0.999;j=j+1
                    k=base.besselk(base.mpc(0,t),Y1).real*mpmath.exp(t*0.5*base.pi)
                Y0=Y1
                r11=t+1E-08
        return new_ivs


    def _next_kbessel_zero(self,r1,r2,y):
        r"""
        The first zero after r1 i the interval [r1,r2] of K_ir(y),K_ir(2y)
        
        INPUT:

            - ´´r1´´ -- double
            - ´´r2´´ -- double
            - ´´y´´  -- double
    
        OUTPUT:

            - ''double''

        EXAMPLES::

        
            sage: M=MaassWaveForms(MySubgroup(Gamma0(1)))
            sage: Y0=0.995*sqrt(3.0)/2.0
            sage: M._next_kbessel_zero(9.0,15.0,Y0)
            9.9203192604549439
            sage: M._next_kbessel_zero(9.921,15.0,Y0)
            10.139781183668587


        CAVEAT:
            The rootfinding algorithm is not very sophisticated and might miss roots
            
        """
        base=mpmath.fp
        h=(r2-r1)/500.0
        t1=-1.0; t2=-1.0
        r0=base.mpf(r1)
        kd0=my_mpmath_kbes_diff_r(r0,y,base)
        #print "r0,y=",r0,y,kd0
        while(t1<r1 and r0<r2):

            # Let us first find a R-value for which the derivative changed sign
            kd=my_mpmath_kbes_diff_r(r0,y,base)
            i=0
            while(kd*kd0>0 and i<500 and r0<r2):
                i=i+1
                r0=r0+h
                kd=my_mpmath_kbes_diff_r(r0,y,base)
                #print "r0,kd=",r0,kd
                #print "kd*kd0=",kd*kd0
            #print "-r0,y,kd=",r0,y,kd
            #t1=base.findroot(lambda x :  base.besselk(base.mpc(0,x),base.mpf(y),verbose=True).real,r0)
            try:
                t1=base.findroot(lambda x :  my_mpmath_kbes(x,y,base),r0)
            except ValueError:
                t1=base.findroot(lambda x :  my_mpmath_kbes(x,y,mpmath.mp),r0)
            r0=r0+h
        if(r0>=r2 or t1>=r2):
            t1=r2
        r0=r1
        kd0=my_mpmath_kbes_diff_r(r0,y,base)
        while(t2<r1 and r0<r2):
            kd=my_mpmath_kbes_diff_r(r0,y,base)
            i=0
            while(kd*kd0>0 and i<500 and r0<r2):
                i=i+1
                r0=r0+h
                kd=my_mpmath_kbes_diff_r(r0,y,base)
            try:
                t2=base.findroot(lambda x :  my_mpmath_kbes(x,2*y,base),r0)
            except ValueError:
                t2=base.findroot(lambda x :  my_mpmath_kbes(x,2*y,mpmath.mp),r0)
            #t2=base.findroot(lambda x :  base.besselk(base.mpc(0,x),base.mpf(2*y),verbose=True).real,r0)
            r0=r0+h
        if(r0>=r2 or t2>=r2):
            t2=r2
            #print "zero(besselk,y1,y2)(",r1,r2,")=",t1,t2
        t=min(min(max(r1,t1),max(r1,t2)),r2)
        return t