module sfkummer; % Functions and rules for the Kummer M and U functions.

% Author: Chris Cannam, Sept/Oct 1992.

imports complex!*on!*switch, complex!*off!*switch,
   complex!*restore!*switch, sq2bf!*;

exports kummerm!*calc;

% Provides algebraic things for both functions, and numeric for (only)
% the M function.  The amount of non-working code for the U function I
% had to cut out of this before getting this version was a sight to
% behold.

algebraic (operator kummerM, kummerU);

symbolic operator kummerm!*calc;


algebraic (kummer!*rules := {

kummerU(~a,~b,~z)  =>  ( pi / sin (pi * b)) *
      ( (kummerM(a,b,z) / (gamma(1+a-b) * gamma(b))) -
	 ((z**(1-b)) * (kummerM(1+a-b,2-b,z)/(gamma(a) * gamma(2-b)))))
   when numberp b and (impart b neq 0 or b neq floor b)
      and numberp a and (impart a neq 0 or a neq floor a or a > 0)
         and not(z=0 and repart(1-b) < 0)
      	 and ((a-b) neq floor repart (a-b) or (a-b) > -1),

kummerU(~a,~b,~z)  =>  ( pi / sin (pi * b)) *
      ( -((z**(1-b)) * (kummerM(1+a-b,2-b,z)/(gamma(a) * gamma(2-b)))))
   when numberp b and (impart b neq 0 or b neq floor b)
      and not(z=0 and repart(1-b) < 0)
		% ComplexInfinity otherwise, but we can't calculate with
		% CI.
      and numberp a and (impart a neq 0 or a neq floor a or a > 0),

kummerM(~a,~b,~z)  =>  exp z	 when a = b,

kummerM(~a,~b,~z)  =>  ((2 * exp (z/2)) / z) * sinh (z/2)
   when numberp a and numberp b and numberp z
      and a = 1 and b = 2 and impart z = 0 and z neq 0,

kummerM(~a,~b,~z)  =>  ((-2 * i * exp (z/2)) / z) * sin (-z / (2*i))
   when numberp a and numberp b and numberp z
      and a = 1 and b = 2 and repart z = 0 and z neq 0,

kummerM(~a,~b,~z)  =>  infinity
   when numberp a and numberp b
      and impart b = 0 and b < 0 and b = floor b
      	 and not (impart a = 0 and a < 0 and a = floor a and a >= b),

kummerM(~a,~b,~z)  =>  do!*kummerm(a,b,z)
   when symbolic !*rounded
      and numberp a and numberp b and numberp z
      	 and b neq 0
      	    and impart a = 0 and impart b = 0 and impart z = 0
               and not (repart b = floor repart b
      	       	     	and repart a = floor repart a
      	       	     	and repart a < 0 and repart b < 0
      	       	     	and repart a >= repart b),

%%df(kummerM(~a,~b,~z),z)  =>  (a/b) * kummerM(a+1, b+1, z),

%%df(kummerU(~a,~b,~z),z)  =>  -a * kummerU(a+1,b+1,z)

% AS (13.4.13)
df(KummerM(~a,~b,~z),z)  =>
	1/z*((b-a)*KummerM(a-1,b,z)-(b-a-z)*KummerM(a,b,z)),
% AS (13.4.26)
df(KummerU(~a,~b,~z),z)  =>
	(- KummerU(a-1,b,z) + (a-b+z)*KummerU(a,b,z))/z

})$


algebraic (let kummer!*rules);



algebraic procedure do!*kummerm(a,b,z);
   algebraic sf!*eval('kummerm!*calc, {a,b,z});


algebraic procedure kummerm!*calc(a,b,z);
   begin scalar a0, b0, z0, result, alglist!*;
      integer prepre, precom;
      precom := complex!*off!*switch();
      prepre := precision 0;
      if prepre < !!nfpd then precision (!!nfpd + 1)
      else precision (prepre + 2);
      a0 := a; b0 := b; z0 := z;
      result :=
      	 algebraic symbolic kummerm!*calc!*sub(a0,b0,z0);
      complex!*restore!*switch(precom);
      precision prepre;
      return result;
   end;


symbolic procedure kummerm!*calc!*sub(a,b,z);
   begin scalar result, this,
      	 admissable, pAmod, pBmod;
      integer rp, orda, k;
      a := sq2bf!* a; b := sq2bf!* b; z := sq2bf!* z;
      result := bfone!*; k := 1;
      pAmod := timbf(a,z); pBmod := b;
      admissable := divbf(bfone!*,
      	 i2bf!: (bf!*base**(5 + c!:prec!:())));
      orda := order!: admissable - 5;
      this := bfone!*; rp := c!:prec!:();
      while greaterp!: (abs!: this, admissable) do
      	 << this := divide!:(times!:(this,pAmod),
   	       	  times!:(pBmod, i2bf!: k),rp);
      	    rp := order!: this - orda;
      	    result := plus!:(result, this);
      	    k := k + 1;
      	    pAmod := plus!:(pAmod, z);
      	    pBmod := plus!:(pBmod, bfone!*);
      	 >>;
      return mk!*sq !*f2q mkround result;
   end;

endmodule;

end;



