Ticket #2535: trac-2535-final.patch

File trac-2535-final.patch, 10.0 KB (added by craigcitro, 14 years ago)
  • sage/modular/hecke/submodule.py

    # HG changeset patch
    # User Craig Citro <craigcitro@gmail.com>
    # Date 1232656022 28800
    # Node ID 4c5a31dd4733c64ab4ff042434e05d374671a47b
    # Parent  f8fb0bf3e547d65a0f90f5b27d543c8cf4ca9da0
    Fix trac #2535.
    
    diff -r f8fb0bf3e547 -r 4c5a31dd4733 sage/modular/hecke/submodule.py
    a b  
    2727
    2828import module
    2929import ambient_module
     30
     31from sage.rings.polynomial.polynomial_ring import polygen
    3032
    3133def is_HeckeSubmodule(x):
    3234    return isinstance(x, HeckeSubmodule)
     
    245247        return d.restrict_domain(self)
    246248       
    247249
    248     def dual_free_module(self, bound=None, anemic=True):
    249         """
     250    def dual_free_module(self, bound=None, anemic=True, use_star=True):
     251        r"""
    250252        Compute embedded dual free module if possible.  In general
    251253        this won't be possible, e.g., if this space is not Hecke
    252254        equivariant, possibly if it is not cuspidal, or if the
    253255        characteristic is not 0.  In all these cases we raise a
    254256        RuntimeError exception.
     257
     258        If use_star is True (which is the default), we also use the
     259        +/- eigenspaces for the star operator to find the dual free
     260        module of self. If the self does not have a star involution,
     261        use_star will automatically be set to True.
     262
     263        EXAMPLES:
     264            sage: M = ModularSymbols(11, 2)
     265            sage: M.dual_free_module()
     266            Vector space of dimension 3 over Rational Field
     267            sage: Mpc = M.plus_submodule().cuspidal_submodule()
     268            sage: Mcp = M.cuspidal_submodule().plus_submodule()
     269            sage: Mcp.dual_free_module() == Mpc.dual_free_module()
     270            True
     271            sage: Mpc.dual_free_module()
     272            Vector space of degree 3 and dimension 1 over Rational Field
     273            Basis matrix:
     274            [  1 5/2   5]
     275
     276            sage: M = ModularSymbols(35,2).cuspidal_submodule()
     277            sage: M.dual_free_module(use_star=False)
     278            Vector space of degree 9 and dimension 6 over Rational Field
     279            Basis matrix:
     280            [   1    0    0    0   -1    0    0    4   -2]
     281            [   0    1    0    0    0    0    0 -1/2  1/2]
     282            [   0    0    1    0    0    0    0 -1/2  1/2]
     283            [   0    0    0    1   -1    0    0    1    0]
     284            [   0    0    0    0    0    1    0   -2    1]
     285            [   0    0    0    0    0    0    1   -2    1]
     286
     287            sage: M = ModularSymbols(40,2)
     288            sage: Mmc = M.minus_submodule().cuspidal_submodule()
     289            sage: Mcm = M.cuspidal_submodule().minus_submodule()
     290            sage: Mcm.dual_free_module() == Mmc.dual_free_module()
     291            True
     292            sage: Mcm.dual_free_module()
     293            Vector space of degree 13 and dimension 3 over Rational Field
     294            Basis matrix:
     295            [ 0  1  0  0  0  0  1  0 -1 -1  1 -1  0]
     296            [ 0  0  1  0 -1  0 -1  0  1  0  0  0  0]
     297            [ 0  0  0  0  0  1  1  0 -1  0  0  0  0]
     298
     299            sage: M = ModularSymbols(43).cuspidal_submodule()
     300            sage: S = M[0].plus_submodule() + M[1].minus_submodule()
     301            sage: S.dual_free_module(use_star=False)
     302            Traceback (most recent call last):
     303            ...
     304            RuntimeError: Computation of embedded dual vector space failed (cut down to rank 6, but should have cut down to rank 3).
     305            sage: S.dual_free_module().dimension() == S.dimension()
     306            True
    255307        """
    256308        try:
    257309            return self.__dual_free_module
    258310        except AttributeError:
    259             if self.dimension() == 0:
    260                 self.__dual_free_module = self.ambient_hecke_module().dual_free_module().zero_submodule()
    261                 return self.__dual_free_module
    262                
    263             # ALGORITHM: Compute the char poly of each Hecke operator on the
    264             # submodule, then use it to cut out a submodule of the dual.  If
    265             # the dimension cuts down to the dimension of self terminate
    266             # with success.  If it stays bigger beyond the bound (Sturm)
    267             # bound, raise a RuntimeError exception.
    268             misc.verbose("computing")
    269             N = self.level()
    270             A = self.ambient_hecke_module()
    271             if A.dimension() == self.dimension():
    272                 self.__dual_free_module = A.free_module()
    273                 return self.__dual_free_module
     311            pass
     312
     313        misc.verbose("computing")
     314
     315        A = self.ambient_hecke_module()
     316
     317        if self.dimension() == 0:
     318            self.__dual_free_module = A.zero_submodule()
     319            return self.__dual_free_module
     320
     321        if A.dimension() == self.dimension():
     322            self.__dual_free_module = A.free_module()
     323            return self.__dual_free_module           
     324
     325        # ALGORITHM: Compute the char poly of each Hecke operator on
     326        # the submodule, then use it to cut out a submodule of the
     327        # dual.  If the dimension cuts down to the dimension of self
     328        # terminate with success.  If it stays larger beyond the Sturm
     329        # bound, raise a RuntimeError exception.
     330
     331        # In the case that the sign of self is not 1, we need to use
     332        # the star involution as well as the Hecke operators in order
     333        # to find the dual of self.
     334        #
     335        # Note that one needs to comment out the line caching the
     336        # result of this computation below in order to get meaningful
     337        # timings.
     338
     339        # If the star involution doesn't make sense for self, then we
     340        # can't use it.
     341        if not hasattr(self, 'star_eigenvalues'):
     342            use_star = False
     343
     344        if use_star:
     345            # If the star involution has both + and - eigenspaces on self,
     346            # then we compute the dual on each eigenspace, then put them
     347            # together.
     348            if len(self.star_eigenvalues()) == 2:
     349                V = self.plus_submodule(compute_dual = False).dual_free_module() + \
     350                    self.minus_submodule(compute_dual = False).dual_free_module()
     351                return V
     352
     353            # At this point, we know that self is an eigenspace for star.   
     354            V = A.sign_submodule(self.sign()).dual_free_module()
     355        else:
    274356            V = A.free_module()
    275             p = 2
    276             if bound is None:
    277                 bound = A.hecke_bound()
    278             while True:
    279                 misc.verbose("using T_%s"%p)
    280                 if anemic:
    281                     while N % p == 0: p = arith.next_prime(p)
    282                 f = self.hecke_polynomial(p)
    283                 T = A.dual_hecke_matrix(p)
    284                 V = T.kernel_on(V, poly=f, check=False)
    285                 if V.dimension() <= self.dimension():
    286                     break
    287                 p = arith.next_prime(p)
    288                 if p > bound:
    289                     break
    290357
    291             if V.rank() == self.rank():
    292                 self.__dual_free_module = V
    293                 return V
    294             else:
    295                 # failed
    296                 raise RuntimeError, "Computation of embedded dual vector space failed " + \
    297                       "(cut down to rank %s, but should have cut down to rank %s)."%(V.rank(), self.rank())
     358        N = self.level()
     359        p = 2
     360        if bound is None:
     361            bound = A.hecke_bound()
     362        while True:
     363            if anemic:
     364                while N % p == 0: p = arith.next_prime(p)
     365            misc.verbose("using T_%s"%p)
     366            f = self.hecke_polynomial(p)
     367            T = A.dual_hecke_matrix(p)
     368            V = T.kernel_on(V, poly=f, check=False)
     369            if V.dimension() <= self.dimension():
     370                break
     371            p = arith.next_prime(p)
     372            if p > bound:
     373                break
     374
     375        if V.rank() == self.rank():
     376            self.__dual_free_module = V
     377            return V
     378        else:
     379            # Failed to reduce V to the appropriate dimension
     380            raise RuntimeError, "Computation of embedded dual vector space failed " + \
     381                  "(cut down to rank %s, but should have cut down to rank %s)."%(V.rank(), self.rank())
    298382
    299383
    300384    def free_module(self):
     385        """
     386        Return the free module corresponding to self.
     387
     388        EXAMPLES:
     389            sage: M = ModularSymbols(33,2).cuspidal_subspace() ; M
     390            Modular Symbols subspace of dimension 6 of Modular Symbols space of dimension 9 for Gamma_0(33) of weight 2 with sign 0 over Rational Field
     391            sage: M.free_module()
     392            Vector space of degree 9 and dimension 6 over Rational Field
     393            Basis matrix:
     394            [ 0  1  0  0  0  0  0 -1  1]
     395            [ 0  0  1  0  0  0  0 -1  1]
     396            [ 0  0  0  1  0  0  0 -1  1]
     397            [ 0  0  0  0  1  0  0 -1  1]
     398            [ 0  0  0  0  0  1  0 -1  1]
     399            [ 0  0  0  0  0  0  1 -1  0]
     400        """
    301401        return self.__submodule
    302402
    303403    def module(self):
    304         return self.__submodule
     404        r"""
     405        Alias for \code{self.free_module()}.
     406
     407        EXAMPLES:
     408            sage: M = ModularSymbols(17,4).cuspidal_subspace()
     409            sage: M.free_module() is M.module()
     410            True
     411        """
     412        return self.free_module()
    305413
    306414    def intersection(self, other):
    307415        """
    308416        Returns the intersection of self and other, which must both
    309417        lie in a common ambient space of modular symbols.
     418       
    310419        EXAMPLES:
    311420            sage: M = ModularSymbols(43, sign=1)
    312421            sage: A = M[0] + M[1]
     
    342451        return M
    343452
    344453    def is_ambient(self):
     454        r"""
     455        Return \code{True} if self is an ambient space of modular
     456        symbols.
     457
     458        EXAMPLES:
     459            sage: M = ModularSymbols(17,4)
     460            sage: M.cuspidal_subspace().is_ambient()
     461            False
     462            sage: A = M.ambient_hecke_module()
     463            sage: S = A.submodule(A.basis())
     464            sage: sage.modular.hecke.submodule.HeckeSubmodule.is_ambient(S)
     465            True
     466        """
    345467        return self.free_module() == self.ambient_hecke_module().free_module()
    346468
    347469    def is_new(self, p=None):