001/*
002 * $Id: PrimeInteger.java 5735 2017-02-18 20:32:34Z kredel $
003 */
004
005package edu.jas.arith;
006
007
008import java.util.ArrayList;
009import java.util.BitSet;
010import java.util.Collections;
011import java.util.List;
012import java.util.Map;
013import java.util.Random;
014import java.util.SortedMap;
015import java.util.SortedSet;
016import java.util.TreeMap;
017import java.util.TreeSet;
018
019import org.apache.log4j.Logger;
020
021
022/**
023 * Integer prime factorization. Code from ALDES/SAC2 and MAS module SACPRIM.
024 * 
025 * See ALDES/SAC2 or MAS code in SACPRIM.
026 * See Symja <code>org/matheclipse/core/expression/Primality.java</code> for Pollard
027 *      algorithm.
028 * @author Heinz Kredel
029 */
030
031public final class PrimeInteger {
032
033
034    private static final Logger logger = Logger.getLogger(PrimeInteger.class);
035
036
037    /**
038     * Maximal long, which can be factored by IFACT(long). Has nothing to do
039     * with SAC2.BETA.
040     */
041    final public static long BETA = PrimeList.getLongPrime(61, 1).longValue();
042
043
044    /**
045     * Medium prime divisor range.
046     */
047    //final static long IMPDS_MIN = 1000;  // SAC2/Aldes 
048    //final static long IMPDS_MAX = 5000;  // "
049    //final static long IMPDS_MIN = 2000;  
050    //final static long IMPDS_MAX = 10000; 
051    final static long IMPDS_MIN = 10000;
052
053
054    final static long IMPDS_MAX = 128000;
055
056
057    /**
058     * List of small prime numbers.
059     */
060    final public static List<Long> SMPRM = smallPrimes(2, (int) (IMPDS_MIN >> 1));
061
062
063    /**
064     * List of units of Z mod 210.
065     */
066    final public static List<Long> UZ210 = getUZ210();
067
068
069    /**
070     * Digit prime generator. K and m are positive beta-integers. L is the list
071     * (p(1),...,p(r)) of all prime numbers p such that m le p lt m+2*K, with
072     * p(1) lt p(2) lt ... lt p(r).
073     * See also SACPRIM.DPGEN.
074     * @param m start integer
075     * @param K number of integers
076     * @return the list L of prime numbers p with m &le; p &lt; m + 2*K.
077     */
078    public static List<Long> smallPrimes(long m, int K) {
079        int k;
080        long ms;
081        ms = m;
082        if (ms <= 1) {
083            ms = 1;
084        }
085        m = ms;
086        if (m % 2 == 0) {
087            m++;
088            K--;
089        }
090        //if (kp % 2 == 0) { 
091        //    k = kp/2; 
092        //} else { 
093        //    k = (kp+1)/2; 
094        //}
095        k = K;
096
097        /* init */
098        long h = 2 * (k - 1);
099        long m2 = m + h; // mp    
100        BitSet p = new BitSet(k);
101        p.set(0, k);
102        //for (int i = 0; i < k; i++) { 
103        //    p.set(i); 
104        //}
105
106        /* compute */
107        int r, d = 0;
108        int i, c = 0;
109        while (true) {
110            switch (c) {
111            /* mark multiples of d for d=3 and d=6n-/+1 with d**2<=m2 */
112            case 2:
113                d += 2;
114                c = 3;
115                break;
116            case 3:
117                d += 4;
118                c = 2;
119                break;
120            case 0:
121                d = 3;
122                c = 1;
123                break;
124            case 1:
125                d = 5;
126                c = 2;
127                break;
128             default: 
129                throw new RuntimeException("this should not happen");
130            }
131            if (d > (m2 / d)) {
132                break;
133            }
134            r = (int) (m % d);
135            if (r + h >= d || r == 0) {
136                if (r == 0) {
137                    i = 0;
138                } else {
139                    if (r % 2 == 0) {
140                        i = d - (r / 2);
141                    } else {
142                        i = (d - r) / 2;
143                    }
144                }
145                if (m <= d) {
146                    i += d;
147                }
148                while (i < k) {
149                    p.set(i, false);
150                    i += d;
151                }
152            }
153        }
154        /* output */
155        int l = p.cardinality(); // l = 0
156        //for (i=0; i<k; i++) { 
157        //    if (p.get(i)) { 
158        //         l++;
159        //     } 
160        //}
161        if (ms <= 2) {
162            l++;
163        }
164        //if (ms <= 1) { 
165        //}
166        List<Long> po = new ArrayList<Long>(l);
167        if (l == 0) {
168            return po;
169        }
170        //l = 0;
171        if (ms == 1) {
172            //po.add(2); 
173            //l++; 
174            p.set(0, false);
175        }
176        if (ms <= 2) {
177            po.add(2L);
178            //l++; 
179        }
180        long pl = m;
181        //System.out.println("pl = " + pl + " p[0] = " + p[0]);
182        //System.out.println("k-1 = " + (k-1) + " p[k-1] = " + p[k-1]);
183        for (i = 0; i < k; i++) {
184            if (p.get(i)) {
185                po.add(pl);
186                //l++; 
187            }
188            pl += 2;
189        }
190        //System.out.println("SMPRM = " + po);
191        return po;
192    }
193
194
195    /**
196     * Integer small prime divisors. n is a positive integer. F is a list of
197     * primes (q(1),q(2),...,q(h)), h non-negative, q(1) le q(2) le ... lt q(h),
198     * such that n is equal to m times the product of the q(i) and m is not
199     * divisible by any prime in SMPRM. Either m=1 or m gt 1,000,000. 
200     * <br /> In JAS F is a map and m=1 or m &gt; 4.000.000.
201     * See also SACPRIM.ISPD.
202     * @param n integer to factor.
203     * @param F a map of pairs of prime numbers and multiplicities (p,e) with p**e
204     *            divides n and e maximal, F is modified.
205     * @return n/F a factor of n not divisible by any prime number in SMPRM.
206     */
207    public static long smallPrimeDivisors(long n, SortedMap<Long, Integer> F) {
208        //SortedMap<Long, Integer> F = new TreeMap<Long, Integer>();
209        List<Long> LP;
210        long QL = 0;
211        long PL;
212        long RL = 0;
213        boolean TL;
214
215        long ML = n;
216        LP = SMPRM; //smallPrimes(2, 500); //SMPRM;
217        TL = false;
218        int i = 0;
219        do {
220            PL = LP.get(i);
221            QL = ML / PL;
222            RL = ML % PL;
223            if (RL == 0) {
224                Integer e = F.get(PL);
225                if (e == null) {
226                    e = 1;
227                } else {
228                    e++;
229                }
230                F.put(PL, e);
231                ML = QL;
232            } else {
233                i++;
234            }
235            TL = (QL <= PL);
236        } while (!(TL || (i >= LP.size())));
237        //System.out.println("TL = " + TL + ", ML = " + ML + ", PL = " + PL + ", QL = " + QL);
238        if (TL && (ML != 1L)) {
239            Integer e = F.get(ML);
240            if (e == null) {
241                e = 1;
242            } else {
243                e++;
244            }
245            F.put(ML, e);
246            ML = 1;
247        }
248        //F.put(ML, 0); // hack
249        return ML;
250    }
251
252
253    /**
254     * Integer small prime divisors. n is a positive integer. F is a list of
255     * primes (q(1),q(2),...,q(h)), h non-negative, q(1) le q(2) le ... lt q(h),
256     * such that n is equal to m times the product of the q(i) and m is not
257     * divisible by any prime in SMPRM. Either m=1 or m gt 1,000,000. 
258     * <br /> In JAS F is a map and m=1 or m &gt; 4.000.000.
259     * See also SACPRIM.ISPD.
260     * @param n integer to factor.
261     * @param F a map of pairs of prime numbers and multiplicities (p,e) with p**e
262     *            divides n and e maximal, F is modified.
263     * @return n/F a factor of n not divisible by any prime number in SMPRM.
264     */
265    public static java.math.BigInteger smallPrimeDivisors(java.math.BigInteger n, SortedMap<java.math.BigInteger, Integer> F) {
266        List<Long> LP;
267        java.math.BigInteger QL = java.math.BigInteger.ZERO;
268        java.math.BigInteger PL;
269        java.math.BigInteger RL = java.math.BigInteger.ZERO;
270        boolean TL;
271
272        java.math.BigInteger ML = n;
273        LP = SMPRM; //smallPrimes(2, 500); //SMPRM;
274        TL = false;
275        int i = 0;
276        do {
277            PL = java.math.BigInteger.valueOf( LP.get(i) );
278            java.math.BigInteger[] xx = ML.divideAndRemainder(PL);
279            QL = xx[0]; //ML.divide(PL);
280            RL = xx[1]; //ML.remainder(PL);
281            if (RL.equals(java.math.BigInteger.ZERO)) {
282                Integer e = F.get(PL);
283                if (e == null) {
284                    e = 1;
285                } else {
286                    e++;
287                }
288                F.put(PL, e);
289                ML = QL;
290            } else {
291                i++;
292            }
293            TL = (QL.compareTo(PL) <= 0);
294        } while (!(TL || (i >= LP.size())));
295        //System.out.println("TL = " + TL + ", ML = " + ML + ", PL = " + PL + ", QL = " + QL);
296        if (TL && (!ML.equals(java.math.BigInteger.ONE))) {
297            Integer e = F.get(ML);
298            if (e == null) {
299                e = 1;
300            } else {
301                e++;
302            }
303            F.put(ML, e);
304            ML = java.math.BigInteger.ONE;
305        }
306        //F.put(ML, 0); // hack
307        return ML;
308    }
309
310
311    /**
312     * Integer primality test. n is a positive integer. r is true, if n is
313     * prime, else false.
314     * @param n integer to test.
315     * @return true if n is prime, else false.
316     */
317    public static boolean isPrime(long n) {
318        java.math.BigInteger N = java.math.BigInteger.valueOf(n);
319        if (N.isProbablePrime(N.bitLength())) {
320            return true;
321        }
322        SortedMap<Long, Integer> F = factors(n);
323        return (F.size() == 1) && F.values().contains(1);
324    }
325
326
327    /**
328     * Test prime factorization. n is a positive integer. r is true, if n =
329     * product_i(pi**ei) and each pi is prime, else false.
330     * @param n integer to test.
331     * @param F a map of pairs of prime numbers (p,e) with p**e divides n.
332     * @return true if n = product_i(pi**ei) and each pi is prime, else false.
333     */
334    public static boolean isPrimeFactorization(long n, SortedMap<Long, Integer> F) {
335        long f = 1L;
336        for (Map.Entry<Long, Integer> m : F.entrySet()) {
337            long p = m.getKey();
338            if (!isPrime(p)) {
339                return false;
340            }
341            int e = m.getValue();
342            long pe = java.math.BigInteger.valueOf(p).pow(e).longValue();
343            f *= pe;
344        }
345        return n == f;
346    }
347
348
349    /**
350     * Test factorization. n is a positive integer. r is true, if n =
351     * product_i(pi**ei), else false.
352     * @param n integer to test.
353     * @param F a map of pairs of numbers (p,e) with p**e divides n.
354     * @return true if n = product_i(pi**ei), else false.
355     */
356    public static boolean isFactorization(long n, SortedMap<Long, Integer> F) {
357        long f = 1L;
358        for (Map.Entry<Long, Integer> m : F.entrySet()) {
359            long p = m.getKey();
360            int e = m.getValue();
361            long pe = java.math.BigInteger.valueOf(p).pow(e).longValue();
362            f *= pe;
363        }
364        return n == f;
365    }
366
367
368    /**
369     * Integer factorization. n is a positive integer. F is a list (q(1),
370     * q(2),...,q(h)) of the prime factors of n, q(1) le q(2) le ... le q(h),
371     * with n equal to the product of the q(i). <br /> In JAS F is a map.
372     * See also SACPRIM.IFACT.
373     * @param n integer to factor.
374     * @return a map of pairs of numbers (p,e) with p**e divides n.
375     */
376    public static SortedMap<Long, Integer> factors(long n) {
377        if (n > BETA) {
378            throw new UnsupportedOperationException("factors(long) only for longs less than BETA: " + BETA);
379        }
380        long ML, PL, AL, BL, CL, MLP, RL, SL;
381        SortedMap<Long, Integer> F = new TreeMap<Long, Integer>();
382        SortedMap<Long, Integer> FP = null;
383        // search small prime factors
384        ML = smallPrimeDivisors(n, F); // , F, ML
385        if (ML == 1L) {
386            return F;
387        }
388        //System.out.println("F = " + F);
389        // search medium prime factors
390        AL = IMPDS_MIN;
391        do {
392            MLP = ML - 1;
393            RL = (new ModLong(new ModLongRing(ML), 3)).power(MLP).getVal(); //(3**MLP) mod ML; 
394            if (RL == 1L) {
395                FP = factors(MLP);
396                SL = primalityTestSelfridge(ML, MLP, FP);
397                if (SL == 1) {
398                    logger.info("primalityTestSelfridge: FP = " + FP);
399                    Integer e = F.get(ML);
400                    if (e == null) {
401                        e = 1;
402                    } else { // will not happen
403                        e++;
404                    }
405                    F.put(ML, e); 
406                    return F;
407                }
408            }
409            CL = Roots.sqrtInt(new BigInteger(ML)).getVal().longValue(); //SACI.ISQRT( ML, CL, TL );
410            //System.out.println("CL = " + CL + ", ML = " + ML + ", CL^2 = " + (CL*CL));
411            BL = Math.max(IMPDS_MAX, CL / 3L);
412            if (AL > BL) {
413                PL = 1L;
414            } else {
415                logger.info("mediumPrimeDivisorSearch: a = " + AL + ", b = " + BL);
416                PL = mediumPrimeDivisorSearch(ML, AL, BL); //, PL, ML );
417                //System.out.println("PL = " + PL);
418                if (PL != 1L) {
419                    AL = PL;
420                    Integer e = F.get(PL);
421                    if (e == null) {
422                        e = 1;
423                    } else {
424                        e++;
425                    }
426                    F.put(PL, e); 
427                    ML = ML / PL;
428                }
429            }
430        } while (PL != 1L);
431        // fixed: the ILPDS should also be in the while loop, was already wrong in SAC2/Aldes and MAS
432        // seems to be okay for integers smaller than beta
433        java.math.BigInteger N = java.math.BigInteger.valueOf(ML);
434        if (N.isProbablePrime(N.bitLength())) {
435            F.put(ML, 1);
436            return F;
437        }
438        AL = BL;
439        BL = CL;
440        logger.info("largePrimeDivisorSearch: a = " + AL + ", b = " + BL + ", m = " + ML);
441        // search large prime factors
442        do {
443            //ILPDS( ML, AL, BL, PL, ML );
444            PL = largePrimeDivisorSearch(ML, AL, BL);
445            if (PL != 1L) {
446                Integer e = F.get(PL);
447                if (e == null) {
448                    e = 1;
449                } else {
450                    e++;
451                }
452                F.put(PL, e);
453                ML = ML / PL;
454                AL = PL;
455                CL = Roots.sqrtInt(BigInteger.valueOf(ML)).getVal().longValue(); //SACI.ISQRT( ML, CL, TL );
456                //System.out.println("CL = " + CL + ", ML = " + ML + ", CL^2 = " + (CL*CL));
457                BL = Math.min(BL, CL);
458                if (AL > BL) {
459                    PL = 1L;
460                }
461            }
462        } while (PL != 1L);
463        //System.out.println("PL = " + PL + ", ML = " + ML);
464        if (ML != 1L) {
465            Integer e = F.get(ML);
466            if (e == null) {
467                e = 1;
468            } else {
469                e++;
470            }
471            F.put(ML, e);
472        }
473        return F;
474    }
475
476
477    /**
478     * Integer factorization, Pollard rho algorithm. n is a positive integer. F
479     * is a list (q(1), q(2),...,q(h)) of the prime factors of n, q(1) le q(2)
480     * le ... le q(h), with n equal to the product of the q(i). <br /> In
481     * JAS F is a map.
482     * See also SACPRIM.IFACT.
483     * @param n integer to factor.
484     * @return a map F of pairs of numbers (p,e) with p**e divides n and p
485     *            probable prime.
486     */
487    public static SortedMap<Long, Integer> factorsPollard(long n) {
488        if (n > BETA) {
489            throw new UnsupportedOperationException("factors(long) only for longs less than BETA: " + BETA);
490        }
491        SortedMap<Long, Integer> F = new TreeMap<Long, Integer>();
492        factorsPollardRho(n, F); 
493        return F;
494    }
495
496
497    /**
498     * Integer medium prime divisor search. n, a and b are positive integers
499     * such that a le b le n and n has no positive divisors less than a. If n
500     * has a prime divisor in the closed interval from a to b then p is the
501     * least such prime and q=n/p. Otherwise p=1 and q=n.
502     * See also SACPRIM.IMPDS.
503     * @param n integer to factor.
504     * @param a lower bound.
505     * @param b upper bound.
506     * @return p a prime factor of n, with a &le; p &le; b &lt; n.
507     */
508    public static long mediumPrimeDivisorSearch(long n, long a, long b) {
509        List<Long> LP;
510        long R, J1Y, RL1, RL2, RL, PL;
511
512        RL = a % 210;
513        LP = UZ210;
514        long ll = LP.size();
515        int i = 0;
516        while (RL > LP.get(i)) {
517            i++; 
518        }
519        RL1 = LP.get(i); 
520        PL = a + (RL1 - RL); 
521        //System.out.println("PL = " + PL + ", BL = " + BL);
522        while (PL <= b) {
523            R = n % PL; //SACI.IQR( NL, PL, QL, R );
524            if (R == 0) {
525                return PL;
526            }
527            i++; 
528            if (i >= ll) { 
529                LP = UZ210;
530                RL2 = (RL1 - 210L);
531                i = 0;
532            } else {
533                RL2 = RL1;
534            }
535            RL1 = LP.get(i); 
536            J1Y = (RL1 - RL2);
537            PL = PL + J1Y; 
538        }
539        PL = 1L; //SACI.IONE;
540        //QL = NL;
541        return PL;
542    }
543
544
545    /**
546     * Integer selfridge primality test. m is an integer greater than or equal
547     * to 3. mp=m-1. F is a list (q(1),q(2),...,q(k)), q(1) le q(2) le ... le
548     * q(k), of the prime factors of mp, with mp equal to the product of the
549     * q(i). An attempt is made to find a root of unity modulo m of order m-1.
550     * If the existence of such a root is discovered then m is prime and s=1. If
551     * it is discovered that no such root exists then m is not a prime and s=-1.
552     * Otherwise the primality of m remains uncertain and s=0.
553     * See also SACPRIM.ISPT.
554     * @param m integer to test.
555     * @param mp integer m-1.
556     * @param F a map of pairs (p,e), with primes p, multiplicity e and with
557     *            p**e divides mp and e maximal.
558     * @return s = -1 (not prime), 0 (unknown) or 1 (prime).
559     */
560    public static int primalityTestSelfridge(long m, long mp, SortedMap<Long, Integer> F) {
561        long AL, BL, QL, QL1, MLPP, PL1, PL;
562        int SL;
563        //List<Long> SMPRM = smallPrimes(2, 500); //SMPRM;
564        List<Long> PP;
565
566        List<Map.Entry<Long, Integer>> FP = new ArrayList<Map.Entry<Long, Integer>>(F.entrySet());
567        QL1 = 1L; //SACI.IONE;
568        PL1 = 1L;
569        int i = 0;
570        while (true) {
571            do {
572                if (i == FP.size()) { 
573                    logger.info("SL=1: m = " + m);
574                    SL = 1;
575                    return SL;
576                }
577                QL = FP.get(i).getKey();
578                i++; 
579            } while (!(QL > QL1));
580            QL1 = QL;
581            PP = SMPRM;
582            int j = 0;
583            do {
584                if (j == PP.size()) {
585                    logger.info("SL=0: m = " + m);
586                    SL = 0;
587                    return SL;
588                }
589                PL = PP.get(j); 
590                j++; 
591                if (PL > PL1) {
592                    PL1 = PL;
593                    AL = (new ModLong(new ModLongRing(m), PL)).power(mp).getVal(); //(PL**MLP) mod ML; 
594                    if (AL != 1) {
595                        logger.info("SL=-1: m = " + m);
596                        SL = (-1);
597                        return SL;
598                    }
599                }
600                MLPP = mp / QL; 
601                BL = (new ModLong(new ModLongRing(m), PL)).power(MLPP).getVal(); //(PL**MLPP) mod ML; 
602            } while (BL == 1L);
603        }
604    }
605
606
607    /**
608     * Integer large prime divisor search. n is a positive integer with no prime
609     * divisors less than 17. 1 le a le b le n. A search is made for a divisor p
610     * of the integer n, with a le p le b. If such a p is found then np=n/p,
611     * otherwise p=1 and np=n. A modular version of Fermats method is used, and
612     * the search goes from a to b.
613     * See also SACPRIM.ILPDS.
614     * @param n integer to factor.
615     * @param a lower bound.
616     * @param b upper bound.
617     * @return p a prime factor of n, with a &le; p &le; b &lt; n.
618     */
619    public static long largePrimeDivisorSearch(long n, long a, long b) { // return PL, NLP ignored
620        if (n > BETA) {
621            throw new UnsupportedOperationException(
622                            "largePrimeDivisorSearch only for longs less than BETA: " + BETA);
623        }
624        List<ModLong> L = null;
625        List<ModLong> LP;
626        long RL1, RL2, J1Y, r, PL, TL;
627        long RL, J2Y, XL1, XL2, QL, XL, YL, YLP;
628        long ML = 0L;
629        long SL = 0L;
630        QL = n / b;
631        RL = n % b;
632        XL1 = b + QL;
633        SL = XL1 % 2L;
634        XL1 = XL1 / 2L; // after SL
635        if ((RL != 0) || (SL != 0)) {
636            XL1 = XL1 + 1L;
637        }
638        QL = n / a;
639        XL2 = a + QL;
640        XL2 = XL2 / 2L;
641        L = residueListFermat(n); //FRESL( NL, ML, L ); // ML not returned
642        if (L.isEmpty()) {
643            return n;
644        }
645        ML = L.get(0).ring.getModul().longValue(); // sic
646        // check is okay: sort: L = SACSET.LBIBMS( L ); revert: L = MASSTOR.INV( L );
647        Collections.sort(L);
648        Collections.reverse(L);
649        //System.out.println("FRESL: " + L);
650        r = XL2 % ML;
651        LP = L;
652        int i = 0;
653        while (i < LP.size() && r < LP.get(i).getVal()) {
654            i++; 
655        }
656        if (i == LP.size()) {
657            i = 0; //LP = L;
658            SL = ML;
659        } else {
660            SL = 0L;
661        }
662        RL1 = LP.get(i).getVal(); 
663        i++; 
664        SL = ((SL + r) - RL1);
665        XL = XL2 - SL;
666        TL = 0L;
667        while (XL >= XL1) {
668            J2Y = XL * XL;
669            YLP = J2Y - n;
670            //System.out.println("YLP = " + YLP + ", J2Y = " + J2Y);
671            YL = Roots.sqrtInt(BigInteger.valueOf(YLP)).getVal().longValue(); // SACI.ISQRT( YLP, YL, TL );
672            //System.out.println("YL = sqrt(YLP) = " + YL);
673            TL = YLP - YL * YL;
674            if (TL == 0L) {
675                PL = XL - YL;
676                return PL;
677            }
678            if (i < LP.size()) {
679                RL2 = LP.get(i).getVal(); 
680                i++; 
681                SL = (RL1 - RL2);
682            } else {
683                i = 0;
684                RL2 = LP.get(i).getVal(); 
685                i++; 
686                J1Y = (ML + RL1);
687                SL = (J1Y - RL2);
688            }
689            RL1 = RL2;
690            XL = XL - SL;
691        }
692        PL = 1L; 
693        // unused NLP = NL;
694        return PL;
695    }
696
697
698    /**
699     * Fermat residue list, single modulus. m is a positive beta-integer. a
700     * belongs to Z(m). L is a list of the distinct b in Z(m) such that b**2-a
701     * is a square in Z(m).
702     * See also SACPRIM.FRLSM.
703     * @param m integer to factor.
704     * @param a element of Z mod m.
705     * @return Lp a list of Fermat residues for modul m.
706     */
707    public static List<ModLong> residueListFermatSingle(long m, long a) {
708        List<ModLong> Lp;
709        SortedSet<ModLong> L;
710        List<ModLong> S, SP;
711        int MLP;
712        ModLong SL, SLP, SLPP;
713
714        ModLongRing ring = new ModLongRing(m);
715        ModLong am = ring.fromInteger(a);
716        MLP = (int) (m / 2L);
717        S = new ArrayList<ModLong>();
718        for (int i = 0; i <= MLP; i++) {
719            SL = ring.fromInteger(i);
720            SL = SL.multiply(SL); //SACM.MDPROD( ML, IL, IL );
721            S.add(SL); 
722        }
723        L = new TreeSet<ModLong>();
724        SP = S;
725        for (int i = MLP; i >= 0; i -= 1) {
726            SL = SP.get(i); 
727            SLP = SL.subtract(am); //SACM.MDDIF( ML, SL, AL );
728            int j = S.indexOf(SLP); 
729            if (j >= 0) { // != 0
730                SLP = ring.fromInteger(i);
731                L.add(SLP); 
732                SLPP = SLP.negate(); 
733                if (!SLPP.equals(SLP)) {
734                    L.add(SLPP); 
735                }
736            }
737        }
738        Lp = new ArrayList<ModLong>(L);
739        return Lp;
740    }
741
742
743    /**
744     * Fermat residue list. n is a positive integer with no prime divisors less
745     * than 17. m is a positive beta-integer and L is an ordered list of the
746     * elements of Z(m) such that if x**2-n is a square then x is congruent to a
747     * (modulo m) for some a in L.
748     * See also SACPRIM.FRESL.
749     * @param n integer to factor.
750     * @return Lp a list of Fermat residues for different modules.
751     */
752    public static List<ModLong> residueListFermat(long n) {
753        List<ModLong> L, L1;
754        List<Long> H, M;
755        long AL1, AL2, AL3, AL4, BL1, HL, J1Y, J2Y, KL, KL1, ML1, ML;
756        //too large: long BETA = Long.MAX_VALUE - 1L; 
757
758        // modulus 2**5.
759        BL1 = 0L;
760        AL1 = n % 32L; 
761        AL2 = AL1 % 16L; 
762        AL3 = AL2 % 8L; 
763        AL4 = AL3 % 4L; 
764        if (AL4 == 3L) {
765            ML = 4L;
766            if (AL3 == 3L) {
767                BL1 = 2L;
768            } else {
769                BL1 = 0L;
770            }
771        } else {
772            if (AL3 == 1L) {
773                ML = 8L;
774                if (AL2 == 1L) {
775                    BL1 = 1L;
776                } else {
777                    BL1 = 3L;
778                }
779            } else {
780                ML = 16L;
781                switch ((short) (AL1 / 8L)) {
782                case (short) 0: 
783                    BL1 = 3L;
784                    break;
785                case (short) 1: 
786                    BL1 = 7L;
787                    break;
788                case (short) 2: 
789                    BL1 = 5L;
790                    break;
791                case (short) 3: 
792                    BL1 = 1L;
793                    break;
794                default: 
795                    throw new RuntimeException("this should not happen");
796                }
797            }
798        }
799        L = new ArrayList<ModLong>();
800        ModLongRing ring = new ModLongRing(ML);
801        ModLongRing ring2;
802        if (ML == 4L) {
803            L.add(ring.fromInteger(BL1));
804        } else {
805            J1Y = ML - BL1;
806            L.add(ring.fromInteger(BL1));
807            L.add(ring.fromInteger(J1Y));
808        }
809        KL = L.size();
810
811        // modulus 3**3.
812        AL1 = n % 27L; 
813        AL2 = AL1 % 3L; 
814        if (AL2 == 2L) {
815            ML1 = 3L;
816            ring2 = new ModLongRing(ML1);
817            KL1 = 1L;
818            L1 = new ArrayList<ModLong>();
819            L1.add(ring2.fromInteger(0));
820        } else {
821            ML1 = 27L;
822            ring2 = new ModLongRing(ML1);
823            KL1 = 4L;
824            L1 = residueListFermatSingle(ML1, AL1);
825            // ring2 == L1.get(0).ring
826        }
827        //L = SACM.MDLCRA( ML, ML1, L, L1 );
828        L = ModLongRing.chineseRemainder(ring.getONE(), ring2.getONE(), L, L1);
829        ML = (ML * ML1);
830        ring = new ModLongRing(ML); // == L.get(0).ring
831        KL = (KL * KL1);
832        //System.out.println("FRESL: L = " + L + ", ring = " + ring.toScript());
833
834        // modulus 5**2.
835        AL1 = n % 25L; 
836        AL2 = AL1 % 5L; 
837        if ((AL2 == 2L) || (AL2 == 3L)) {
838            ML1 = 5L;
839            ring2 = new ModLongRing(ML1);
840            J1Y = (AL2 - 1L);
841            J2Y = (6L - AL2);
842            L1 = new ArrayList<ModLong>();
843            L1.add(ring2.fromInteger(J1Y));
844            L1.add(ring2.fromInteger(J2Y));
845            KL1 = 2L;
846        } else {
847            ML1 = 25L;
848            ring2 = new ModLongRing(ML1);
849            L1 = residueListFermatSingle(ML1, AL1);
850            KL1 = 7L;
851        }
852        if (ML1 >= BETA / ML) {
853            return L;
854        }
855        //L = SACM.MDLCRA( ML, ML1, L, L1 );
856        L = ModLongRing.chineseRemainder(ring.getONE(), ring2.getONE(), L, L1);
857        ML = (ML * ML1);
858        ring = new ModLongRing(ML);
859        KL = (KL * KL1);
860        //System.out.println("FRESL: L = " + L + ", ring = " + ring.toScript());
861
862        // moduli 7,11,13.
863        L1 = new ArrayList<ModLong>();
864        M = new ArrayList<Long>(3);
865        H = new ArrayList<Long>(3);
866        //M = MASSTOR.COMPi( 7, MASSTOR.COMPi( 11, 13 ) );
867        M.add(7L);
868        M.add(11L);
869        M.add(13L);
870        //H = MASSTOR.COMPi( 64, MASSTOR.COMPi( 48, 0 ) );
871        H.add(64L);
872        H.add(48L);
873        H.add(0L);
874        int i = 0;
875        while (true) {
876            ML1 = M.get(i); 
877            if (ML1 >= BETA / ML) {
878                return L;
879            }
880            ring2 = new ModLongRing(ML1);
881            AL1 = n % ML1; 
882            L1 = residueListFermatSingle(ML1, AL1);
883            KL1 = L1.size(); 
884            //L = SACM.MDLCRA( ML, ML1, L, L1 );
885            L = ModLongRing.chineseRemainder(ring.getONE(), ring2.getONE(), L, L1);
886            ML = (ML * ML1);
887            ring = new ModLongRing(ML);
888            KL = (KL * KL1);
889            //System.out.println("FRESL: L = " + L + ", ring = " + ring.toScript());
890            HL = H.get(i); 
891            i++;
892            if (KL > HL) {
893                return L;
894            }
895        }
896        // return ?
897    }
898
899
900    /**
901     * Compute units of Z sub 210.
902     * See also SACPRIM.UZ210.
903     * @return list of units of Z sub 210.
904     */
905    public static List<Long> getUZ210() {
906        List<Long> UZ = new ArrayList<Long>();
907        java.math.BigInteger z210 = java.math.BigInteger.valueOf(210);
908        //for (int i = 209; i >= 1; i -= 2) {
909        for (long i = 1; i <= 209; i += 2) {
910            if (z210.gcd(java.math.BigInteger.valueOf(i)).equals(java.math.BigInteger.ONE)) {
911                UZ.add(i);
912            }
913        }
914        return UZ;
915    }
916
917
918    /**
919     * Integer factorization. n is a positive integer. F is a list (q(1),
920     * q(2),...,q(h)) of the prime factors of n, q(1) le q(2) le ... le q(h),
921     * with n equal to the product of the q(i). <br /> In JAS F is a map.
922     * See also SACPRIM.IFACT, uses Pollards rho method.
923     * @param n integer to factor.
924     * @return a map of pairs of numbers (p,e) with p**e divides n.
925     */
926    public static SortedMap<java.math.BigInteger, Integer> factors(java.math.BigInteger n) {
927        java.math.BigInteger b = java.math.BigInteger.valueOf(BETA);
928        SortedMap<java.math.BigInteger, Integer> F = new TreeMap<java.math.BigInteger, Integer>();
929        if (n.compareTo(b) > 0) {
930            n = smallPrimeDivisors(n, F);
931            if (n.compareTo(b) > 0) {
932                logger.info("run factorsPollardRho on n = " + n);
933                factorsPollardRho(n, F); 
934                return F;
935            }
936        }
937        long s = n.longValue();
938        SortedMap<Long, Integer> ff = factors(s); // useless 2nd smallPrimeDiv search
939        for (Map.Entry<Long, Integer> m : ff.entrySet()) {
940            java.math.BigInteger mm = java.math.BigInteger.valueOf(m.getKey());
941            F.put(mm, m.getValue());            
942        }
943        return F;
944    }
945
946
947    /**
948     * Integer factorization using Pollards rho algorithm. n is a positive
949     * integer. F is a list (q(1), q(2),...,q(h)) of the prime factors of n,
950     * q(1) le q(2) le ... le q(h), with n equal to the product of the q(i).
951     * <br /> In JAS F is a map.
952     * @param n integer to factor.
953     * @param F a map of pairs of numbers (p,e) with p**e divides n and p is
954     *            probable prime, F is modified.
955     */
956    public static void factorsPollardRho(java.math.BigInteger n, SortedMap<java.math.BigInteger, Integer> F) {
957        java.math.BigInteger factor;
958        java.math.BigInteger temp = n;
959        int iterationCounter = 0;
960        Integer count;
961        while (!temp.isProbablePrime(32)) {
962            factor = rho(temp);
963            if (factor.equals(temp)) {
964                if (iterationCounter++ > 4) {
965                    break;
966                }
967            } else {
968                iterationCounter = 1;
969            }
970            count = F.get(factor);
971            if (count == null) {
972                F.put(factor, 1);
973            } else {
974                F.put(factor, count + 1);
975            }
976            temp = temp.divide(factor);
977        }
978        count = F.get(temp);
979        if (count == null) {
980            F.put(temp, 1);
981        } else {
982            F.put(temp, count + 1);
983        }
984    }
985
986
987    /**
988     * Random number generator.
989     */
990    //final static SecureRandom random = new SecureRandom();
991    final static Random random = new Random();
992
993
994    /**
995     * Search cycle with Pollards rho algorithm x**2 + c mod n. n is a positive
996     * integer. <br />
997     * @param n integer test.
998     * @return x-y with gcd(x-y, n) = 1.
999     */
1000    static java.math.BigInteger rho(java.math.BigInteger n) {
1001        java.math.BigInteger divisor;
1002        java.math.BigInteger c = new java.math.BigInteger(n.bitLength(), random);
1003        java.math.BigInteger x = new java.math.BigInteger(n.bitLength(), random);
1004        java.math.BigInteger xx = x;
1005        do {
1006            x = x.multiply(x).mod(n).add(c).mod(n);
1007            xx = xx.multiply(xx).mod(n).add(c).mod(n);
1008            xx = xx.multiply(xx).mod(n).add(c).mod(n);
1009            divisor = x.subtract(xx).gcd(n);
1010        } while (divisor.equals(java.math.BigInteger.ONE));
1011        return divisor;
1012    }
1013
1014
1015    /**
1016     * Integer factorization using Pollards rho algorithm. n is a positive
1017     * integer. F is a list (q(1), q(2),...,q(h)) of the prime factors of n,
1018     * q(1) le q(2) le ... le q(h), with n equal to the product of the q(i).
1019     * <br /> In JAS F is a map.
1020     * @param n integer to factor.
1021     * @param F a map of pairs of numbers (p,e) with p**e divides n and p is
1022     *            probable prime, F is modified.
1023     */
1024    public static void factorsPollardRho(long n, SortedMap<Long, Integer> F) {
1025        long factor;
1026        long temp = n;
1027        int iterationCounter = 0;
1028        Integer count;
1029        while (!java.math.BigInteger.valueOf(temp).isProbablePrime(32)) {
1030            factor = rho(temp);
1031            if (factor == temp) {
1032                if (iterationCounter++ > 4) {
1033                    break;
1034                }
1035            } else {
1036                iterationCounter = 1;
1037            }
1038            count = F.get(factor);
1039            if (count == null) {
1040                F.put(factor, 1);
1041            } else {
1042                F.put(factor, count + 1);
1043            }
1044            temp = temp / factor;
1045        }
1046        count = F.get(temp);
1047        if (count == null) {
1048            F.put(temp, 1);
1049        } else {
1050            F.put(temp, count + 1);
1051        }
1052        //System.out.println("random = " + random.getAlgorithm());
1053    }
1054
1055
1056    /**
1057     * Search cycle with Pollards rho algorithm x**2 + c mod n. n is a positive
1058     * integer. c is a random constant.
1059     * @param n integer test.
1060     * @return x-y with gcd(x-y, n) == 1.
1061     */
1062    static long rho(long n) {
1063        long divisor;
1064        int bl = java.math.BigInteger.valueOf(n).bitLength();
1065        long c = new java.math.BigInteger(bl, random).longValue(); // .abs()
1066        long x = new java.math.BigInteger(bl, random).longValue(); // .abs()
1067        ModLongRing ring = new ModLongRing(n);
1068        ModLong cm = new ModLong(ring, c);
1069        ModLong xm = new ModLong(ring, x);
1070        ModLong xxm = xm;
1071        do {
1072            xm = xm.multiply(xm).sum(cm);
1073            xxm = xxm.multiply(xxm).sum(cm);
1074            xxm = xxm.multiply(xxm).sum(cm);
1075            divisor = gcd(xm.getVal() - xxm.getVal(), n);
1076        } while (divisor == 1L);
1077        return divisor;
1078    }
1079
1080
1081    static long gcd(long a, long b) {
1082        return BigInteger.valueOf(a).gcd(BigInteger.valueOf(b)).getVal().longValue();
1083    }
1084
1085}