prog-squarefree-fast.pl 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. #!/usr/bin/perl
  2. # Smallest base-n Fermat pseudoprime with n distinct prime factors.
  3. # https://oeis.org/A271874
  4. # Known terms:
  5. # 341, 286, 11305, 2203201, 12306385
  6. # New terms:
  7. # 341, 286, 11305, 2203201, 12306385, 9073150801, 3958035081, 2539184851126, 152064312120721, 10963650080564545, 378958695265110961, 1035551157050957605345, 57044715596229144811105, 6149883077429715389052001, 426634466310819456228926101, 166532358913107245358261399361
  8. # a(7)-a(17) from ~~~~
  9. # New terms found:
  10. # a(7) = 9073150801
  11. # a(8) = 3958035081
  12. # a(9) = 2539184851126
  13. # a(10) = 152064312120721
  14. # a(11) = 10963650080564545
  15. # a(12) = 378958695265110961
  16. # a(13) = 1035551157050957605345
  17. # a(14) = 57044715596229144811105
  18. # a(15) = 6149883077429715389052001
  19. # a(16) = 426634466310819456228926101
  20. # a(17) = 166532358913107245358261399361
  21. # a(18) = 15417816366043964846263074467761
  22. # a(19) = 7512467783390668787701493308514401
  23. # a(20) = 182551639864089765855891394794831841
  24. # a(21) = 73646340445282784237405289363506168161
  25. # a(22) = 12758106140074522771498516740500829830401
  26. # a(23) = 233342982005748265084053300837644203002001
  27. # a(24) = 41711804619389959984296019492852898455016161
  28. # a(25) = 35654496932132728635037829367481372591614792001
  29. # a(26) = 13513093081489380840188651246675032067011140079201
  30. # a(27) = 2758048007075525871042090011995729226316189827518801
  31. # New terms found (05 March 2023):
  32. #
  33. =for comment
  34. # PARI/GP program (slow):
  35. fermat_psp(A, B, k, base) = A=max(A, vecprod(primes(k))); (f(m, l, p, j) = my(list=List()); forprime(q=p, sqrtnint(B\m, j), if(base%q != 0, my(v=m*q, t=q, r=nextprime(q+1)); while(v <= B, my(L=lcm(l, znorder(Mod(base, t)))); if(gcd(L, v) == 1, if(j==1, if(v>=A && if(k==1, !isprime(v), 1) && (v-1)%L == 0, listput(list, v)), if(v*r <= B, list=concat(list, f(v, L, r, j-1)))), break); v *= q; t *= q))); list); vecsort(Vec(f(1, 1, 2, k)));
  36. a(n) = if(n < 2, return()); my(x=vecprod(primes(n)), y=2*x); while(1, my(v=fermat_psp(x, y, n, n)); if(#v >= 1, return(v[1])); x=y+1; y=2*x); \\ ~~~~
  37. # PARI/GP program (fast):
  38. fermat_psp(A, B, k, base) = A=max(A, vecprod(primes(k))); (f(m, l, lo, k) = my(list=List()); my(hi=sqrtnint(B\m, k)); if(lo > hi, return(list)); if(k==1, forstep(p=lift(1/Mod(m, l)), hi, l, if(isprimepower(p) && gcd(m*base, p) == 1, my(n=m*p); if(n >= A && (n-1) % znorder(Mod(base, p)) == 0, listput(list, n)))), forprime(p=lo, hi, base%p == 0 && next; my(z=znorder(Mod(base, p))); gcd(m,z) == 1 || next; my(q=p, v=m*p); while(v <= B, list=concat(list, f(v, lcm(l, z), p+1, k-1)); q *= p; Mod(base, q)^z == 1 || break; v *= p))); list); vecsort(Set(f(1, 1, 2, k)));
  39. a(n) = if(n < 2, return()); my(x=vecprod(primes(n)), y=2*x); while(1, my(v=fermat_psp(x, y, n, n)); if(#v >= 1, return(v[1])); x=y+1; y=2*x); \\ ~~~~
  40. =cut
  41. use 5.036;
  42. use Math::GMPz;
  43. use ntheory qw(:all);
  44. sub squarefree_fermat_pseudoprimes_in_range ($A, $B, $k, $base, $callback) {
  45. $A = vecmax($A, pn_primorial($k));
  46. $A = Math::GMPz->new("$A");
  47. $B = Math::GMPz->new("$B");
  48. my $u = Math::GMPz::Rmpz_init();
  49. my $v = Math::GMPz::Rmpz_init();
  50. sub ($m, $L, $lo, $k) {
  51. Math::GMPz::Rmpz_tdiv_q($u, $B, $m);
  52. Math::GMPz::Rmpz_root($u, $u, $k);
  53. my $hi = Math::GMPz::Rmpz_get_ui($u);
  54. if ($lo > $hi) {
  55. return;
  56. }
  57. if ($k == 1) {
  58. Math::GMPz::Rmpz_cdiv_q($u, $A, $m);
  59. if (Math::GMPz::Rmpz_fits_ulong_p($u)) {
  60. $lo = vecmax($lo, Math::GMPz::Rmpz_get_ui($u));
  61. }
  62. elsif (Math::GMPz::Rmpz_cmp_ui($u, $lo) > 0) {
  63. if (Math::GMPz::Rmpz_cmp_ui($u, $hi) > 0) {
  64. return;
  65. }
  66. $lo = Math::GMPz::Rmpz_get_ui($u);
  67. }
  68. if ($lo > $hi) {
  69. return;
  70. }
  71. Math::GMPz::Rmpz_invert($v, $m, $L);
  72. if (Math::GMPz::Rmpz_cmp_ui($v, $hi) > 0) {
  73. return;
  74. }
  75. if (Math::GMPz::Rmpz_fits_ulong_p($L)) {
  76. $L = Math::GMPz::Rmpz_get_ui($L);
  77. }
  78. my $t = Math::GMPz::Rmpz_get_ui($v);
  79. $t > $hi && return;
  80. $t += $L while ($t < $lo);
  81. for (my $p = $t ; $p <= $hi ; $p += $L) {
  82. if (is_prime($p) and $base % $p != 0) {
  83. Math::GMPz::Rmpz_mul_ui($v, $m, $p);
  84. Math::GMPz::Rmpz_sub_ui($u, $v, 1);
  85. if (Math::GMPz::Rmpz_divisible_ui_p($u, znorder($base, $p))) {
  86. my $value = Math::GMPz::Rmpz_init_set($v);
  87. $B = $value if ($value < $B);
  88. say "Found upper-bound: $value";
  89. $callback->($value);
  90. }
  91. }
  92. }
  93. return;
  94. }
  95. my $t = Math::GMPz::Rmpz_init();
  96. my $lcm = Math::GMPz::Rmpz_init();
  97. foreach my $p (@{primes($lo, $hi)}) {
  98. $base % $p == 0 and next;
  99. my $z = znorder($base, $p);
  100. Math::GMPz::Rmpz_gcd_ui($Math::GMPz::NULL, $m, $z) == 1 or next;
  101. Math::GMPz::Rmpz_lcm_ui($lcm, $L, $z);
  102. Math::GMPz::Rmpz_mul_ui($t, $m, $p);
  103. __SUB__->($t, $lcm, $p + 1, $k - 1);
  104. }
  105. }
  106. ->(Math::GMPz->new(1), Math::GMPz->new(1), 2, $k);
  107. }
  108. sub a($n) {
  109. say "Searching for a($n)";
  110. my $x = pn_primorial($n);
  111. my $y = 2*$x;
  112. $x = Math::GMPz->new("$x");
  113. $y = Math::GMPz->new("$y");
  114. for (;;) {
  115. say "Sieving range: [$x, $y]";
  116. my @arr;
  117. squarefree_fermat_pseudoprimes_in_range($x, $y, $n, $n, sub($v) { push @arr, $v });
  118. if (@arr) {
  119. @arr = sort {$a <=> $b} @arr;
  120. return $arr[0];
  121. }
  122. $x = $y+1;
  123. $y = 2*$x;
  124. }
  125. }
  126. foreach my $n (20) {
  127. say "a($n) = ", a($n);
  128. }