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 ≤ p < 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 > 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 > 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 ≤ p ≤ b < 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 ≤ p ≤ b < 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}