%mathpiper,def="ReversePoly"

/* Lagrangian power series reversion. Copied
   from Knuth seminumerical algorithms */

ReversePoly(_f,_g,_var,_newvar,_degree) <--
[
  Local(orig,origg,G,V,W,U,n,initval,firstder,j,k,newsum);
  orig:=MakeUni(f,var);
  origg:=MakeUni(g,var);
  initval:=Coef(orig,0);
  firstder:=Coef(orig,1);
  V:=Coef(orig,1 .. Degree(orig));
  V:=Concat(V,FillList(0,degree));
  G:=Coef(origg,1 .. Degree(origg));
  G:=Concat(G,FillList(0,degree));
  W:=FillList(0,Length(V)+2);
  W[1]:=G[1]/firstder;
  U:=FillList(0,Length(V)+2);
  U[1]:=1/firstder;
  n:=1;
  While(n<degree-1)
  [
    n++;
    For(k:=0,k<n-1,k++)
    [
      newsum:=U[k+1];
      For(j:=2,j<=k+1,j++)
      [
        newsum:=newsum-U[k+2-j]*V[j];
      ];
      U[k+1]:=newsum/firstder;
    ];
    newsum:=0;
    For(k:=2,k<=n,k++)
    [
      newsum:=newsum - k*U[n+1-k]*V[k];
    ];
    U[n]:=newsum/firstder;
    newsum:=0;
    For(k:=1,k<=n,k++)
    [
      newsum:=newsum + k*U[n+1-k]*G[k]/n;
    ];
    W[n]:=newsum;
  ];
  DestructiveInsert(W,1,Coef(origg,0));
  Subst(newvar,newvar-initval)
    NormalForm(UniVariate(newvar,0,W));
];

%/mathpiper



%mathpiper_docs,name="ReversePoly",categories="User Functions;Series"
*CMD ReversePoly --- solve $h(f(x)) = g(x) + O(x^n)$ for $h$
*STD
*CALL
	ReversePoly(f, g, var, newvar, degree)

*PARMS

{f}, {g} -- functions of "var"

{var} -- a variable

{newvar} -- a new variable to express the result in

{degree} -- the degree of the required solution

*DESC

This function returns a polynomial in "newvar", say "h(newvar)",
with the property that "h(f(var))" equals "g(var)" up to order
"degree". The degree of the result will be at most "degree-1". The
only requirement is that the first derivative of "f" should not be zero.

This function is used to determine the Taylor series expansion of the
inverse of a function "f": if we take "g(var)=var", then
"h(f(var))=var" (up to order "degree"), so "h" will be the
inverse of "f".

*E.G.

In> f(x):=Eval(Expand((1+x)^4))
Result: True;
In> g(x) := x^2
Result: True;
In> h(y):=Eval(ReversePoly(f(x),g(x),x,y,8))
Result: True;
In> BigOh(h(f(x)),x,8)
Result: x^2;
In> h(x)
Result: (-2695*(x-1)^7)/131072+(791*(x-1)^6)
	/32768 +(-119*(x-1)^5)/4096+(37*(x-1)^4)
	/1024+(-3*(x-1)^3)/64+(x-1)^2/16;

*SEE InverseTaylor, Taylor, BigOh
%/mathpiper_docs