#
#--> Subres(a,b,x) mod p
#
#  Input :   a,b: two multivariate polynomials over a finite field
#                 coefficients -- integers, rationals, RootOf's
#              x: a variable,
#
#  Output:      : returns the subresultant sequence,
#		a sequence of polynomials in decreasing degree in x
#
#  Reference:	"Algorithms for Computer Algebra"
#		Geddes K. O, Labahn G., Czapor S.
#
#		"Computer Algebra"
#		J. Davenport, E. Tournier
#
#  G. Labahn and M. Monagan July 1991.
#


`mod/Subres` := proc(a,b,x,p) local t,S;
option `Copyright 1991 by the University of Waterloo`;

    if not type(x,name) then ERROR(`3rd argument must be a name`) fi;
    if not type(p,integer) then ERROR(`4th argument must be an integer`) fi;
    if not type(a,'polynom(anything,x)') or not type(b,polynom(anything,x)) then
	ERROR(`1st and 2nd arguments must be polynomials in `,x) fi;

if printlevel > 1 then
lprint(`mod/Subres: starting a subresultant computation at time`,time()) fi;

    if   type(a,'polynom(rational)') and 
         type(b,'polynom(rational)') then S := `mod/Subres/Zmodp`(a,b,x,p);

    elif type(a,'polynom(algnum)') and
         type(b,'polynom(algnum)') then S := `mod/Subres/Zmodp`(a,b,x,p);

    else ERROR(`1st and 2nd arguments must multivariate polynomials`.
		`over a finite field`);
    fi;

if printlevel > 1 then
lprint(`mod/Subres: finishing a subresultant computation at time`,time()) fi;

    S;

end:


`mod/Subres/Zmodp` := proc(a,b,x,p)
local c,d,j,u,v,r,g,h,du,ddu,dv,ddv,S,s,t;

	u := Expand(a) mod p;
	v := Expand(b) mod p;


        if degree(u,x) < degree(v,x) then
	   t := u; u := v; v := t; s := (-1)^(degree(u,x)*degree(v,x));
        else
	   s := 1;
        fi;


	du := degree(u,x);
	dv := degree(v,x);

if printlevel > 2 then
lprint(`mod/Subres: degrees of input polynomials`,du,dv) fi;

	S := collect(u,x);
	ddu := du; ddv := dv;
	if u = 0 or v = 0 then RETURN(S) fi;
	if du = 0 and dv = 0 then RETURN(1) fi;
	if dv = 0 then RETURN(u,v,Expand(v^du) mod p) fi;

	c := 1;  g := 1;  h := 1;
	while dv > 0 do
		d := du-dv;
		c := c*(-1)^(du*dv);
		r := Prem(u,v,x) mod p;
		u := v; v := r; du := dv; dv := degree(r,x);
		j := degree(u,x);
                S := S, collect(s^((ddu-j)*(ddv-j))*u mod p,x);

if printlevel > 2 then
lprint(`mod/Subres: degree of pseudo remainder`,degree(u,x)) fi;

		Divide(v,g*h^d,'v') mod p;
		g := coeff(u,x,du);
		if d = 1 then h := g else Divide(g^d,h^(d-1),'h') mod p fi;
	od;
	if du = 1 then RETURN( S, Expand(s^(ddu*ddv)*c*v) mod p ) fi;
	Divide(v,h,'r') mod p;
	S, Expand(s^(ddu*ddv)*c*v*r^(du-1)) mod p;

end:

`help/text/Subres` := TEXT(
`FUNCTION: subres - subresultant polynomial remainder sequence`,
`      `,
`CALLING SEQUENCE: Subres(a,b,x) mod p;`,
`      `,
`PARAMETERS:`,
`   a, b - polynomials in the variable x`,
`   x - name`,
`   p - integer`,
`      `,
`SYNOPSIS:   `,
`   `,
`- Given two polynomials a and b in the variable x the function Subres mod p`,
`  computes the subresultant PRS of a and b over a finite field, either the`,
`  integers mod p or a Galois field.  The coefficients of polynomials`,
`  a and b can be rational numbers, algebraic numbers, or more generally,`,
`  multivariate polynomials in other variables over the same number field.`,
`   `,
`- The output returned is the subresultant sequence, a sequence of polynomials`,
`  in x in decreasing degree where the last polynomial in the sequence is the`,
`  resultant of a and b in x, which is a constant in x, i.e. it lies in the`,
`  coefficient domain.`,
`      `,
`- The algorithm is described in the references`,
`   `,
`  "Algorithms for Computer Algebra" by K.O. Geddes, S. Czapor, G. Labahn and`,
`  "Computer Algebra" by J. H. Davenport, Y. Siret, and E. Tournier.`,
`   `,
`EXAMPLES:   `,
`   `,
`> a := x^6+3*x^2+1:`,
`> b := x^4+2*x^2-1:`,
`> Subres(a,b,x) mod 5;`,
`   `,
`                    6      2       4      2         2`,
`                   x  + 3 x  + 1, x  + 2 x  + 4, 3 x  + 4, 4`,
`   `,
`> a := y*x^3+y^2*x^2+2*y*x:`,
`> b := (y-1)*x^2+2*y^4*x-y^2:`,
`> Subres(a,b,x) mod 5;`,
`   `,
`         3    2  2                   2      4        2`,
`      y x  + y  x  + 2 y x, (y + 4) x  + 2 y  x + 4 y ,`,
`   `,
`            3    2    4            7      6      9       5      4      7`,
`          (y  + y  + y  + 2 y + 3 y  + 2 y  + 4 y ) x + y  + 4 y  + 3 y ,`,
`   `,
`             12      11      10      9      8    7      5    4`,
`          2 y   + 3 y   + 4 y   + 2 y  + 3 y  + y  + 3 y  + y`,
`   `,
`> alias(y = RootOf(x^2-3) mod 5):`,
`> a := y*x^3+y^2*x^2+2*y*x:`,
`> b := (y-1)*x^2+2*y^4*x-y^2:`,
`> Subres(a,b,x) mod 5;`,
`   `,
`                 3      2                   2`,
`              y x  + 3 x  + 2 y x, (y + 4) x  + 3 x + 2, x + 1, 2`,
`   `,
`SEE ALSO:  mod, RootOf, Resultant, Prem`
):

#save `Subres.m`;
#quit
