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

   $Header: /home/was/magma/packages/modform/code/RCS/arithmetic.m,v 1.6 2002/04/15 07:26:44 was Exp $

   $Log: arithmetic.m,v $
   Revision 1.6  2002/04/15 07:26:44  was
   ...

   Revision 1.5  2002/04/15 07:25:00  was
   Made * more flexible for f*T.

   Revision 1.4  2001/06/30 03:12:29  was
   Changed '+' slightly.

   Revision 1.3  2001/05/30 18:53:33  was
   Done.

   Revision 1.2  2001/05/16 04:11:36  was
   *** empty log message ***

   Revision 1.1  2001/05/16 03:50:39  was
   Initial revision

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

import "predicates.m" : Element;

function CreateModularFormFromOperation(op,g,h)
   assert op in {"*", "-", "+", "scalar"};
   if Type(g) eq ModFrmElt then
      assert BaseRing(Parent(g)) eq BaseRing(Parent(h));
   end if;
   assert Type(h) eq ModFrmElt;
   f := HackobjCreateRaw(ModFrmElt);
   f`created_from := <op,g,h>;
   if op eq "scalar" then
      f`parent := Parent(h);
      return f;
   end if;
   Mg := Parent(g);
   Mh := Parent(h);
   N := LCM(Level(Mg), Level(Mh));
   if IsRingOfAllModularForms(Mg) then
      M := Mg;
   elif IsRingOfAllModularForms(Mh) then
      M := Mh;
   else
      case op:
         when "*":
            k := Weight(g) + Weight(h);
            if  IsGamma0(Mg) and IsGamma0(Mh) then
                M := ModularForms(N,k);
            else
                M := ModularForms(Gamma1(N),k);
            end if;
         when "+": 
            if Weight(g) eq Weight(h) then
               if IsGamma0(Mg) and IsGamma0(Mh) then
                  M := ModularForms(N,Weight(g));
               else
                  M := ModularForms(Gamma1(N),Weight(g)); 
               end if;
            else 
               M := ModularForms();  
            end if;
         else:
            error "CreateModularFormFromOperation -- Invalid operation.";
      end case;
   end if;
   f`parent := BaseExtend(M,BaseRing(Mg));
   return f;
end function;


intrinsic '+'(f::ModFrmElt,g::ModFrmElt) -> ModFrmElt 
   {}
   require BaseRing(Parent(f)) eq BaseRing(Parent(g)) : 
     "Arguments 1 and 2 have incompatible coefficient rings.";

   if AmbientSpace(Parent(f)) ne AmbientSpace(Parent(g)) then
      return CreateModularFormFromOperation("+",f,g);      
   end if;

   M := Parent(f);
   if M eq Parent(g) then
      return M!(Element(f)+Element(g));
   else
      A := AmbientSpace(M);
      return A!f + A!g;
   end if;

end intrinsic; 

intrinsic '-'(f::ModFrmElt,g::ModFrmElt) -> ModFrmElt 
   {}
   require BaseRing(Parent(f)) eq BaseRing(Parent(g)) : 
     "Arguments 1 and 2 have incompatible coefficient rings.";

   return f+ (-1)*g;
end intrinsic; 

intrinsic '-'(f::ModFrmElt, g::RngSerPowElt) -> RngSerPowElt
{}
   t, _ := IsCoercible(Parent(g),PowerSeries(f,1));
   require t : "The q-expansion of argument 1 must be coercible into the parent of argument 2.";
   return f+(-g);
end intrinsic;

intrinsic '-'(g::RngSerPowElt, f::ModFrmElt) -> RngSerPowElt
{}
   t, _ := IsCoercible(Parent(g),PowerSeries(f,1));
   require t : "The q-expansion of argument 1 must be coercible into the parent of argument 2.";
   return g+(-f);
end intrinsic;

intrinsic '-'(f::ModFrmElt) -> ModFrmElt
{}
   return (-1)*f;
end intrinsic;

intrinsic '+'(g::RngSerPowElt, f::ModFrmElt) -> RngSerPowElt
{}
   t, _ := IsCoercible(Parent(g),PowerSeries(f,1));
   require t : "The q-expansion of argument 1 must be coercible into the parent of argument 2.";
   return f+g;
end intrinsic;

intrinsic '+'(f::ModFrmElt, g::RngSerPowElt) -> RngSerPowElt
{}
   t, _ := IsCoercible(Parent(g),PowerSeries(f,1));
   require t : "The q-expansion of argument 1 must be coercible into the parent of argument 2.";
   if RelativePrecision(g) ne -1 then
      _, ff := IsCoercible(Parent(g),PowerSeries(f,AbsolutePrecision(g)));
      return ff + g;
   else
      _, ff := IsCoercible(Parent(g),PowerSeries(f));
      return ff + g; 
   end if;
end intrinsic;

intrinsic '*'(f::ModFrmElt, T::AlgMatElt) -> ModFrmElt
{}
   require Degree(Parent(T)) eq Dimension(Parent(Element(f))) : 
         "The degrees of arguments 1 and 2 are incompatible.";
   Rf := BaseRing(Parent(f));
   RT := BaseRing(Parent(T));
   if Type(Rf) ne Type(RT) then
      if Type(Rf) eq RngInt then
         f := BaseExtend(Parent(f),RT)!Eltseq(f);      
      end if;
      if Type(RT) eq RngInt then
         T := BaseExtend(Parent(T),Rf)!Eltseq(T);
      end if;
   end if;
   return Parent(f)!(Element(f)*T);
end intrinsic;


intrinsic '*'(f::ModFrmElt, x::RngElt) -> ModFrmElt
   {}
   require x in BaseRing(Parent(f)) : 
        "Argument 1 must be in the base ring of the parent of argument 2.";
   return x*f;
end intrinsic;

intrinsic '*'(x::RngElt, f::ModFrmElt) -> ModFrmElt
   {}
   M := Parent(f);
  require x in BaseRing(M) : "Argument 1 must be in the base ring of the parent of argument 2.";

   /*   if not (x in BaseRing(M)) then
      M2 := BaseExtend(M, Parent(x));
      bang in the element ...
   */
   return M!(x*Element(f));
end intrinsic;

intrinsic '/'(f::ModFrmElt, x::RngElt) -> ModFrmElt
   {}
   require x ne 0 : "Division by zero.";
   require 1/x in BaseRing(Parent(f)) : "Argument 2 is not in the base ring of argument 1.";
   return (1/x)*f;
end intrinsic;

intrinsic '^'(f::ModFrmElt, n::RngElt) -> ModFrmElt
   {}
   requirege  n, 1;
   g := f;
   for i in [2..n] do   // very bad.
      g := g * f;
   end for;
   return g;
end intrinsic;

intrinsic '*'(f::ModFrmElt,g::ModFrmElt) -> ModFrmElt 
   {}
   require BaseRing(Parent(f)) eq BaseRing(Parent(g)) : 
     "Arguments 1 and 2 have incompatible coefficient rings.";
   return CreateModularFormFromOperation("*",f,g);   
end intrinsic; 



