##    Title:    compoly
##    Created:  Aug  20 17:24:22 1991
##    Author:   Bruno Salvy and Francois Morain
##              <salvy@inria.fr> <morain@inria.fr>
##
## Description: Implements the Gutierrez et al. algorithm for polynomial
## decomposition. 
##      Use: compoly( r, x );
##              where r is a polynomial in the variable x
##              returns a pair p(x),x=q(x) such that
##              subs( x=q(x),p(x) ) == r
##              if such a pair cannot be found it returns FAIL
##

unprotect(compoly):
compoly := proc(F, x)
local n, m, gh, f, lc;
    if nargs<>2 or not type(x,name) or not type(F,polynom(anything,x))
	then ERROR(`invalid arguments`) fi;
    f:=`compoly/expandx`(F,x);
    if not has(f,x) then RETURN(FAIL) fi;
    lc:=lcoeff(f,x); f:=`compoly/expandx`(f/lc,x);
    n:=degree(f, x);
    for m in sort([op(numtheory[divisors](n) minus {1,n})]) do
        gh:=`compoly/polydecm`(f, x, m, n);
        if gh<>FAIL then RETURN(`compoly/expandx`(lc*op(1,gh),x),x=op(2,gh))fi;
    od;
    RETURN(FAIL)
end:
protect(compoly):

`compoly/polydecm` := proc(f, x, m, n)
local b, t, i, g, h;
    t:=iquo(n,m);
    # M2: Find candidate
    h:=series(1+convert([seq(b[i]*x^i,i=1..m)],`+`),x,m+1);
    for i to m do
        h:=subs(b[i]=`compoly/lsolve`(coeff(series(h^t,x,i+1),x,i)-
            coeff(f,x,n-i),b[i]),h)
    od;
    h:=`compoly/expandx`(x^m*convert(subs(x=1/x,h),polynom),x);
    # M3: h(X)-adic division
    g:=`compoly/polyhadic`(f, h, x, t);
    if g <> FAIL then RETURN([g, h]) else RETURN(FAIL) fi
end:

`compoly/polyhadic` := proc(f, h, x, t)
local q, i, r;
    q:=f;
    for i from 0 to t-1 do
        r[i]:=rem(q, h, x, 'q');
        if has(r[i],x) then RETURN(FAIL) fi
    od;
    RETURN(x^t+convert([seq(r[i]*x^i,i=0..t-1)],`+`))
end:

`compoly/lsolve`:=proc(f,x) -coeff(f,x,0)/coeff(f,x,1) end:
`compoly/expandx`:=proc(f,x) convert(normal(series(f,x,infinity)),polynom) end:

#save compoly, `compoly/lsolve`, `compoly/expandx`,
#     `compoly/polydecm`, `compoly/polyhadic`, `compoly.m`;
#quit
