%mathpiper,def="PollardRhoFactorize"

/* This is Pollard's Rho method of factorizing, as described in
 * "Modern Computer Algebra". It is a rather fast algorithm for
 * factoring, but doesn't scale to polynomials regrettably.
 *
 * It acts 'by chance'. This is the Floyd cycle detection trick, where
 * you move x(i+1) = f(x(i)) and y(i+1) = f(f(y(i))), so the y goes twice
 * as fast as x, and for a certain i x(i) will be equal to y(i).
 *
 * "Modern Computer Algebra" reasons that if f(x) = (x^2+1) mod n for
 * the value n to be factored, then chances are good that gcd(x-y,n)
 * is a factor of n. The function x^2+1 is arbitrary, a higher order
 * polynomial could have been chosen also.
 *
 */

/*
Warning: The Pollard Rho algorithm cannot factor some numbers, e.g. 703, and
can enter an infinite loop. This currently results in an error message: "failed to factorize".
Hopefully the TrialFactorize() step will avoid these situations by excluding
small prime factors.
This problem could also be circumvented by trying a different random initial value for x when a loop is encountered -- hopefully another initial value will not get into a loop. (currently this is not implemented)
*/




/// Polynomial for the Pollard Rho iteration
PollardRhoPolynomial(_x) <-- x^2+1;

2# PollardRhoFactorize(n_IsPrimePower) <-- {GetPrimePower(n)};
3# PollardRhoFactorize(_n) <--
[
  Local(x,y,restarts,gcd,repeat);
  gcd:=1;
  restarts := 100;	// allow at most this many restartings of the algorithm
  While(gcd = 1 And restarts>=0)	// outer loop: this will be typically executed only once but it is needed to restart the iteration if it "stalls"
  [
  	restarts--;
    /* Pick a random value between 1 and n-1 */
    x:= RandomInteger(n-1);

    /* Initialize loop */
    gcd:=1; y:=x;
	repeat := 4;	// allow at most this many repetitions
//		Echo({"debug PollardRho: entering gcd loop, n=", n});

    /* loop until failure or success found */
    While(gcd = 1 And repeat>=0)
    [
      x:= Modulo( PollardRhoPolynomial(x), n);
   	  y:= Modulo( PollardRhoPolynomial(
	  	Modulo( PollardRhoPolynomial(y), n)	// this is faster for large numbers
	  ), n);
   	  If(x-y = 0,
       	 [
		 	gcd := 1;
		 	repeat--;	// guard against "stalling" in an infinite loop but allow a few repetitions
		 ],
       	 gcd:=Gcd(x-y,n)
       	 );
//		Echo({"debug PollardRho: gcd=",gcd," x=", x," y=", y});
   	];
	If(InVerboseMode() And repeat<=0, Echo({"PollardRhoFactorize: Warning: stalled while factorizing ", n, "; counters ", x, y}));
  ];
  Check(restarts>0, "Math", "PollardRhoFactorize: Error: failed to factorize " : ToString(n));
  If(InVerboseMode() And gcd > 1, Echo({"PollardRhoFactorize: Info: while factorizing ", n, " found factor ", gcd}));
  /* Return result found */
  PollardCombineLists(PollardRhoFactorize(gcd), PollardRhoFactorize(Quotient(n,gcd)));
];

%/mathpiper