freeze;
 
/****-*-magma-* EXPORT DATE: 2004-03-08 ************************************
                                                                            
                     MODFORM: Modular Forms in MAGMA
 
                              William A. Stein        
                         
   FILE: subspaces.m

   $Header: /home/was/magma/packages/ModFrm/code/RCS/subspaces.m,v 1.6 2002/06/28 04:31:34 was Exp $

   $Log: subspaces.m,v $
   Revision 1.6  2002/06/28 04:31:34  was
   Fixed caching of new subspaces.  It was totally wrong before.

   Revision 1.5  2002/05/06 05:32:52  was
   Correct access via SpaceTypeParam.

   Revision 1.4  2002/04/18 23:26:28  was
   *** empty log message ***

   Revision 1.3  2002/04/13 07:27:05  was
   Added stuff for p-new subspaces.

   Revision 1.2  2001/05/30 18:57:30  was
   Created.

   Revision 1.1  2001/05/16 03:52:12  was
   Initial revision

      
 ***************************************************************************/


import "creation.m" : CopyOfDefiningModularFormsObject;

import "predicates.m": AssociatedSpaceOverZ,
                       SpaceType, 
                       SpaceTypeParam;


function MakeSubspace(M, type, param)
   assert Type(M) eq ModFrm;
   assert Type(type) eq MonStgElt;
   assert IsAmbientSpace(M);
   assert type in {"zero", "ambient", "cusp", "eis", "new", "cusp_new", "eis_new"};

   if type eq "ambient" then
      return M;
   end if;

   if type eq "zero" then
      return ZeroSubspace(M);
   end if;

   function MakeSpaceWithType()
      S := CopyOfDefiningModularFormsObject(M);
      delete S`dimension;
      S`ambient_space := M;
      S`type := type;
      S`type_param := param;
      if Type(BaseRing(S)) ne RngInt then
         MZ := AssociatedSpaceOverZ(M);
         case type: 
            when "cusp":
               A := CuspidalSubspace(MZ);
            when "eis":
               A := EisensteinSubspace(MZ);
            when "new":
               A := NewSubspace(MZ,param);
            when "cusp_new":
               A := NewSubspace(CuspidalSubspace(MZ),param);
            when "eis_new":
               A := NewSubspace(EisensteinSubspace(MZ),param);
            else
               error "Bug in subspaces.m";
         end case;
         S`associated_space_over_z := A;
      end if;
      return S;
   end function;


   case type:
      when "cusp":
         if not assigned M`cusp then
            M`cusp := MakeSpaceWithType();
         end if;
         return M`cusp;
      when "eis":
         if not assigned M`eis then
            M`eis := MakeSpaceWithType();
         end if;
         return M`eis;

      when "new":
         if not assigned M`new then
            M`new := [* *];
         end if;
         if exists(i) { i : i in [1..#M`new] | M`new[i][1] eq param} then
            return M`new[i][2];
         end if;
         Append(~M`new,<param,MakeSpaceWithType()>);
         return M`new[#M`new][2];

      when "cusp_new":
         if not assigned M`cusp_new then
            M`cusp_new := [* *];
         end if;
         if exists(i) { i : i in [1..#M`cusp_new] | M`cusp_new[i][1] eq param} then
            return M`cusp_new[i][2];
         end if;
         Append(~M`cusp_new,<param,MakeSpaceWithType()>);
         return M`cusp_new[#M`cusp_new][2];


      when "eis_new":
         if not assigned M`eis_new then
            M`eis_new := [* *];
         end if;
         if exists(i) { i : i in [1..#M`eis_new] | M`eis_new[i][1] eq param} then
            return M`eis_new[i][2];
         end if;
         Append(~M`eis_new,<param,MakeSpaceWithType()>);
         return M`eis_new[#M`eis_new][2];

      else:
          assert false;
   end case;
   
end function;


intrinsic CuspidalSubspace(M::ModFrm) -> ModFrm
{The cuspidal subspace of M.}
   if not assigned M`cuspidal_subspace then
      vprint ModularForms : "ModularForms: Computing cuspidal subspace.";
      if assigned M`dimension and M`dimension eq 0 then
         return M;
      end if;
      A := AmbientSpace(M);
      case SpaceType(M):
         when "full":
            M`cuspidal_subspace := MakeSubspace(A, "cusp", 0);
         when "cusp", "cusp_new", "cusp_newform":
            return M;
         when "eis", "eis_new", "eis_newform":
            M`cuspidal_subspace := MakeSubspace(A, "zero", 0);
         when "new":
            M`cuspidal_subspace := MakeSubspace(A, "cusp_new", 0);            
         else:
            error "Typo in CuspidalSubspace." ;
      end case;
   end if;
   if assigned M`cuspidal_subspace then
      return M`cuspidal_subspace;
   end if;
   error "CuspidalSubspace -- bug.";
end intrinsic;


intrinsic EisensteinSubspace(M::ModFrm) -> ModFrm
{The Eisenstein subspace of M.}
   if not assigned M`eisenstein_subspace then
      vprint ModularForms : "ModularForms: Computing eisenstein subspace.";
      if assigned M`dimension and M`dimension eq 0 then
         return M;
      end if;
      A := AmbientSpace(M);
      case SpaceType(M):
         when "full":
            M`eisenstein_subspace := MakeSubspace(A, "eis", 0);
         when "cusp", "cusp_new", "cusp_newform":
            M`eisenstein_subspace := MakeSubspace(A, "zero", 0);
         when "eis", "eis_new", "eis_newform": 
            M`eisenstein_subspace := true;
            return M;
         when "new":
            M`eisenstein_subspace := MakeSubspace(A, "eis_new", 0);      
         else:
            error "Typo in EisensteinSubspace." ;
      end case;
   end if;
   if Type(M`eisenstein_subspace) eq BoolElt then
      return M;
   end if;
   return M`eisenstein_subspace;
   error "EisensteinSubspace -- bug.";
end intrinsic;

intrinsic NewSubspace(M::ModFrm) -> ModFrm
{The new subspace of M.}
   return NewSubspace(M, 0);
end intrinsic;

intrinsic NewSubspace(M::ModFrm, p::RngIntElt) -> ModFrm
{The p-new subspace of M.}
   require IsPrime(p) or p eq 0 : "Argument 2 must be prime.";
   vprint ModularForms : "ModularForms: Computing new subspace.";
   if assigned M`dimension and M`dimension eq 0 then
      return M;
   end if;
   if not assigned M`new_subspace then
      M`new_subspace := [* *];
   end if;
   if exists(i) { i : i in [1..#M`new_subspace] | M`new_subspace[i][1] eq p} then
      return M`new_subspace[i][2];
   end if;

   A := AmbientSpace(M);
   case SpaceType(M):
      when "full":
         N := MakeSubspace(A, "new", p);
         Append(~M`new_subspace, <p,N>);
         return N;
      when "cusp":
         N := MakeSubspace(A, "cusp_new", p);
         Append(~M`new_subspace, <p,N>);
         return N;
      when "eis":
         N := MakeSubspace(A, "eis_new", p);
         Append(~M`new_subspace, <p,N>);
         return N;
      when "new", "cusp_new", "eis_new":
         if SpaceTypeParam(M) eq p then
            return M;
         elif SpaceTypeParam(M) eq 0 then
            N := MakeSubspace(A,M`type, p);            
         else
            // This isn't yet fully supported, so give an error.
            error "Construction of NewSubspace of the type you asked for is not yet supported.";
            N := MakeSubspace(A,M`type, p*SpaceTypeParam(M));
         end if;
         Append(~M`new_subspace, <p,N>);
         return N;
      when "eis_newform", "cusp_newform":
         return M;
      else:
         error "Bug in NewSubspace." ;
   end case;
end intrinsic;

intrinsic ZeroSubspace(M::ModFrm)  -> ModFrm
{The trivial subspace of M.}
   S := CopyOfDefiningModularFormsObject(M);
   S`dimension := 0;
   S`type := "zero";
   return S;   
end intrinsic;



