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