#
#-->  irredheu( a:polynom(rational), limit:posint )
#
# Experimental general irreducibility test of a(x) in Q[x] based on finding
# a prime integer evaluation of a polynomial.  The input is a univariate
# polynomial over Q of degree > 0.  The input polynomial is made primitive
# i.e. the sign and content are removed.
#
# Reference: "A Heuristic Polynomial Irreducibility Test"
# Michael Monagan, J. Symbolic Comp., (1992) Vol. 13, No. 1, pp 47-57.
#
# Try limit (optional - default infinity) evaluations and if successful,
# return the prime integer, otherwise return FAIL.
# Note that the primality test used in the library function isprime is
# a probabilistic primality test.  It may, with very low probability, report
# that a number is prime when it isn't.  The user can check that the
# result of `factor/irreduc` is correct by checking that the integer it
# returns is prime using any external algorithm.
# 
# Author: MBM Aug/91
#

macro( FIXDIV = readlib(fixdiv), LIMIT=10^20 );
irredheu := proc(a)
local  B,d,k,F,M,p,q,e,g,x;

	if not type(a,polynom(rational)) then
	    ERROR(`1st argument must be a univariate polynomial over Q`) fi;

	if nargs <> 2 then M := LIMIT
	elif type(args[2],posint) then M := args[2]
	else ERROR(`2nd (optional) argument must be a positive integer`)
	fi;

	p := expand(a); p := p*sign(p)/icontent(p);
	if type(p,rational) then ERROR(`input must not be a constant`) fi;

	x := indets(p);
	if nops(x) <> 1 then ERROR(`multivariate polynomials not handled`) fi;
	x := x[1]; d := degree(p,x);

	q := expand(x^d*subs(x=1/x,p)); # reciprocal polynomial
	if rootbound(q,x) < rootbound(p,x) then p := q fi;

	F := FIXDIV(p,x); B := rootbound(p,x); p := series(p,x,d+1);
	userinfo(1,irredheu,`root bound is `.B);
	userinfo(1,irredheu,`fixed divisor is `.F);

	for k from B+F to B+F+(M-1)/2 do

		userinfo(2,irredheu,`evaluation point `.k);
		e := abs( subsop(0=k,p) );
		g := igcd(e,355929487585205167172661547995662840887819680000);
		if g <= (k-B)^2 and isprime(e/g) then RETURN(e/g) fi;

		userinfo(2,irredheu,`evaluation point `.(-k));
		e := abs( subsop(0=-k,p) );
		g := igcd(e,355929487585205167172661547995662840887819680000);
		if g <= (k-B)^2 and isprime(e/g) then RETURN(e/g) fi
	od;

	FAIL
end:

#
#--> rootbound(f,x);
#
# Given f in Q[x] compute a bound on the complex roots of f
# Inputs f:polynom(rational,x), x:name
# Output b:posint such that b > |r| for all complex roots r of f
# Note: this is better in general than Cauchys bound of
#
#	ceil(1+maxnorm(f)/abs(lcoeff(f)))
#
# Example: for the polynomial x^4-10*x^2+1, rootbound returns 4
# compared with Cauchy's bound of 11.  The roots of this polynomial note are
#
#             -3.146264370, -.3178372452, .3178372452, 3.146264370
#
# Authors MBM, Erich Kaltofen Nov/90
#

rootbound := proc(f,x) local r,d,c,p,t;

    if not type(x,name) then
	ERROR(`2nd argument must be a name`) fi;
    if not type(f,polynom(rational,x)) then
	ERROR(`1st argument must be a polynomial over Q`) fi;

    p := expand(f);
    d := degree(p,x);
    if d = 0 then RETURN(1) fi;

    c := coeff(p,x,d);
    p := map(abs,taylor(p-c*x^d,x,d+1));
    c := abs(c);
    r := 1;
    while c*r^d <= subs(x=r,p) do r := 2*r od;
    r

end:

`help/text/irredheu` := TEXT(
`FUNCTION: irredheu - polynomial irreducibility test`,
`      `,
`CALLING SEQUENCE:`,
`   irredheu(a); or irredheu(a,limit);`,
`      `,
`PARAMETERS:`,
`   a     - a univariate polynomial over the rationals`,
`   limit - (optional) positive integer`,
`      `,
`SYNOPSIS:   `,
`- The irredheu function tests whether a non-constant univariate polynomial`,
`  over the rationals is irreducible using a method based on looking for a prime`,
`  evaluation of the polynomial.`,
`      `,
`- The limit option specifies the maximum number (default infinity) of polyno-`,
`  mial evaluations to be tried.  If the function is unsuccessful in proving`,
`  that the polynomial is irreducible, it will return FAIL.  Otherwise it`,
`  returns a prime integer indicating that it has proven the polynomial irredu-`,
`  cible.  Note, if the input is an irreducible polynomial, this method will`,
`  find a prime evaluation if it is run for long enough.`,
`      `,
`- Note also that the primality test used is the library function isprime.  This`,
`  is a probabilistic primality test.  It may, with very low probability, report`,
`  that a number is prime when it isn't.  The user can check that the number`,
`  returned by irredheu is indeed prime using any method available to estab-`,
`  lish a deterministic proof of irreducibility.`,
`      `,
`- This method can sometimes be very fast.  The running time of the algorithm is`,
`  polynomial in the size of the polynomial a depending on certain well known`,
`  hypotheses.  Certain polynomials, such as the Swinerton-Dyer polynomials that`,
`  exhibit a worst case behaviour of the Berlekamp-Hensel method (used by`,
`  Maple's factor and irreduc commands) do not cause problems with this algo-`,
`  rithm.   `,
`      `,
`- Reference: "A Heuristic Polynomial Irreducibility Test" by Michael Monagan,`,
`  Journal of Symbolic Computation, (1992) Vol. 13, No. 1, pp 47-57.`,
`      `,
`EXAMPLES:   `,
`> irredheu(x^2+1);`,
`                                      101`,
`      `,
`> irredheu(x^10-10*x^2+1);`,
`                                    60465817`,
`      `,
`SEE ALSO:  irreduc`):

`help/text/rootbound` := TEXT(
`FUNCTION: bound - bound on the roots of a polynomial`,`         `,
`CALLING SEQUENCE:`,`   rootbound(a,x);`,`        `,
`PARAMETERS:`,`   a     - a univariate polynomial over the rationals`,
`   x     - a name (variable)`,`         `,`SYNOPSIS:   `,
`- This function rootbound(a,x) returns a bound on the absolute value of the`,
`  complex roots of the polynomial a(x).  The bound is at least as good as`,
`  Cauchy's bound of`,`   `,`        ceil(1+maxnorm(f)/abs(lcoeff(f)))`,`   `,
`  but often considerably better.`,`   `,`EXAMPLE:   `,`> a := x^4-10*x^2+1:`,
`> ceil( 1+maxnorm(a)/abs(lcoeff(a)) );`,`   `,
`                                       11`,`   `,`> rootbound(a,x);`,`   `,
`                                       4`,`   `,`> fsolve(a,x,complex);`,
`   `,
`              -3.146264370, -.3178372452, .3178372452, 3.146264370`):

macro( FIXDIV = FIXDIV, LIMIT=LIMIT );
#save `irredheu.m`;
#quit
