x.pl 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. #!/usr/bin/perl
  2. # Author: Daniel "Trizen" Șuteu
  3. # Date: 28 January 2019
  4. # https://github.com/trizen
  5. # A new algorithm for generating Fermat pseudoprimes to base 2.
  6. # See also:
  7. # https://oeis.org/A050217 -- Super-Poulet numbers: Poulet numbers whose divisors d all satisfy d|2^d-2.
  8. # https://oeis.org/A214305 -- Fermat pseudoprimes to base 2 with two prime factors.
  9. # See also:
  10. # https://en.wikipedia.org/wiki/Fermat_pseudoprime
  11. # https://trizenx.blogspot.com/2018/08/investigating-fibonacci-numbers-modulo-m.html
  12. use 5.020;
  13. use warnings;
  14. use strict;
  15. use ntheory qw(:all);
  16. use experimental qw(signatures);
  17. use List::Util qw(uniqnum);
  18. # I found upper-bounds only for the next 5 terms:
  19. # a(5) <= 32203213602841
  20. # a(6) <= 323346556958041
  21. # a(7) <= 2528509579568281
  22. # a(8) <= 5189206896360728641
  23. # a(9) <= 12155831039329417441
  24. # Notice that the upper-bounds a(5)-a(9) are all semiprimes and are of the form p * (2*(p-1) + 1), for some prime number p.
  25. # I couldn't find an upper-bound for a(10), which may be larger than 2^64 (assuming that it exists).
  26. # More generally, we can look for numbers of the form k = p*q, where p and q are odd primes, such that d|((p-1)/2) and d|((q-1)/2), satisfying:
  27. # prime(n)^d == -1 (mod p)
  28. # prime(n)^d == -1 (mod q)
  29. # This can be implemented efficiently by iterating over the odd primes bellow a certain limit and grouping primes together by divisors `d` that satisfy the wanted property.
  30. # When a group has two or more primes, we iterate over all the combinations of two of those primes, say p and q, and generate k = p*q.
  31. # Once we have k = p*q, it's very likely that:
  32. # prime(n)^((k-1)/2) == -1 (mod k)
  33. # For each such number k, we check if:
  34. # b^((k-1)/2) == 1 (mod k) for every natural b < prime(n)
  35. # Several more upper-bounds (example), with possible gaps, for each a(2)-a(7):
  36. # a(2) <= { 5173601, 6787327, 15978007, 314184487, 581618143, 682528687, 717653129, 1536112001, 1854940231, 1860373241, 2693739751, 3344191241, 4916322919, ... }
  37. # a(3) <= { 2329584217, 4394140633, 18491988217, 71430713857, 146463308377, 306190965697, 542381064457, 662181331897, 1749760817617, 2600044182457, 3420965597017, ... }
  38. # a(4) <= { 188985961, 922845241, 41610787921, 55165631041, 85103495641, 130173194161, 178420380841, 451403438041, 577255246921, 669094855201, 842611640041, 1038185022241, ... }
  39. # a(5) <= { 32203213602841, 92223430598881, 181122243848281, 244362410507881, 323731175307121, 359643366744481, 383326325785201, 503561507122801, ... }
  40. # a(6) <= { 323346556958041, 449287527233161, 871447814622001, 2419909071073201, ... }
  41. # a(7) <= { 2528509579568281, 51558565269914641, 251985537187183801, ... }
  42. # b(n) is the smallest odd composite k such that prime(n)^((k-1)/2) == 1 (mod k) and q^((k-1)/2) == -1 (mod k) for every prime q < prime(n).
  43. # b(n) : 341, 29341, ? Is this sequence finite?
  44. # b(3) <= 75350936251
  45. # b(4) <= 493813961816587
  46. # b(5) <= 32398013051587
  47. # b(6) <=
  48. # b(3) <= { 75350936251, 142186219181, 183413388211, 187403492251, 244970876021, 247945488451, 405439595861, 1121610731251, 1566655993781, 1990853572901, 2731649128781, 5042919827861, 5792018372251, 5830202612851, 6226129086451, 6664768278451, 7738029492211, 8648900162251, 9425030475451, 9429387401741, 10216085978251, 14804189283451, 15263877377251, 15883263707851, ... }
  49. # b(4) <= { 493813961816587, 655462669313563, 712305136356547, 1012925163368467, 1063809017035267, 1350727530916147, 1406616417615667, 1554737931642307, 1794376822387267, 2167215816099907, 2402921698865827, ... }
  50. # b(5) <= { 32398013051587, 4627853036319787, 7333470436409443, 29645348137369147, 36140749487965627, 44213562255703843, 62804051517546907, 92101327510561027, 94423328872035643, 118469127753064747, ... }
  51. my $N = 7;
  52. my $multiplier = 4;
  53. my $P = nth_prime($N);
  54. my $MAX = ~0;
  55. my $LIMIT = 1e6;
  56. my @primes_bellow = @{primes($P-1)};
  57. use Math::GMPz;
  58. sub prod {
  59. my $prod = 1;
  60. foreach my $n(@_) {
  61. $prod *= $n;
  62. }
  63. $prod;
  64. }
  65. # a(5) = 11530801
  66. # a(7) = 15656266201
  67. my @primes = @{primes(100)};
  68. sub non_residue {
  69. my ($n) = @_;
  70. foreach my $p (@primes) {
  71. #if ($p > $Q) {
  72. # return -1;
  73. # }
  74. sqrtmod($p, $n) // return $p;
  75. }
  76. return -1;
  77. }
  78. #~ #139309114031, a(9) <= 7947339136801, a(10) <= 72054898434289.
  79. #~ say non_residue(139309114031, nth_prime(8));
  80. #~ say non_residue(7947339136801, nth_prime(9));
  81. #~ say non_residue(72054898434289, nth_prime(10));
  82. #~ __END__
  83. #~ say non_residue(72054898434289, nth_prime(10));
  84. #~ __END__
  85. sub isok {
  86. my ($k) = @_;
  87. if (powmod($P, ($k-1)>>1, $k) == 1) {
  88. return vecall { powmod($_, ($k-1)>>1, $k) == $k-1 } @primes_bellow;
  89. }
  90. return;
  91. #~ my $res;
  92. #~ my $p = nth_prime($n);
  93. #~ for(my $k = $A000229[$n-1]*$A000229[$n-1]; ; $k+=2) {
  94. #~ if (!is_prime($k) and powmod($p, ($k-1)>>1, $k) == $k-1) {
  95. #~ my $q = non_residue($k, $p);
  96. #~ if ($p == $q) {
  97. #~ return $k;
  98. #~ }
  99. #~ }
  100. #~ }
  101. #~ return $res;
  102. }
  103. forprimes {
  104. if (is_prime(($_-1)*$multiplier+ 1)) {
  105. my $k = Math::GMPz->new($_)* (($_-1)*$multiplier + 1);
  106. #(($_-1)*$multiplier + 1);
  107. if (isok($k)) {
  108. die "a($N) <= $k\n";
  109. }
  110. }
  111. } 1e10,1e11;
  112. __END__
  113. sub fermat_pseudoprimes ($limit, $callback) {
  114. say "Collecting primes...";
  115. my %common_divisors;
  116. forprimes {
  117. my $p = $_;
  118. my $common = 0;
  119. foreach my $d (divisors(($p-1)>>1)) {
  120. if (powmod($P, $d, $p) == 1 and vecall { powmod($_, $d, $p) == $p-1 } @primes_bellow ) {
  121. push @{$common_divisors{$d}}, $p;
  122. }
  123. }
  124. #if (@div) {
  125. # push @{$common_divisors{"@div"}}, $p;
  126. #}
  127. #~ if ($common) {
  128. #~ foreach my $n(2..100) {
  129. #~ if (is_prime(($p-1)*$n + 1)) {
  130. #~ my $q = ($p-1)*$n + 1;
  131. #~ foreach my $d (divisors($q - 1)) {
  132. #~ if (powmod($P, $d, $q) == $q-1) {
  133. #~ push @{$common_divisors{$d}}, $q;
  134. #~ }
  135. #~ }
  136. #~ }
  137. #~ }
  138. #~ }
  139. # }
  140. } 3, $limit;
  141. say "Generating combinations...";
  142. #~ forprimes {
  143. #~ my $p = $_;
  144. #~ foreach my $d (divisors($p - 1)) {
  145. #~ if (powmod($P, $d, $p) == $p-1) {
  146. #~ push @{$common_divisors{$d}}, $p;
  147. #~ }
  148. #~ }
  149. #~ } $limit>>1, $limit;
  150. my %seen;
  151. foreach my $value (values %common_divisors) {
  152. my $arr = [uniqnum(@$value)];
  153. my $l = $#{$arr} + 1;
  154. # say $l;
  155. foreach my $k (2..$l) {
  156. forcomb {
  157. my $n = prod(@{$arr}[@_]);
  158. if ($n <= $MAX) {
  159. $callback->($n) #if !$seen{$n}++;
  160. }
  161. } $l, $k;
  162. }
  163. }
  164. }
  165. #~ sub is_fermat_pseudoprime ($n, $base) {
  166. #~ powmod($base, $n - 1, $n) == 1;
  167. #~ }
  168. #~ sub is_fibonacci_pseudoprime($n) {
  169. #~ (lucas_sequence($n, 1, -1, $n - kronecker($n, 5)))[0] == 0;
  170. #~ }
  171. my @values;
  172. my %seen;
  173. fermat_pseudoprimes(
  174. $LIMIT,
  175. sub ($k) {
  176. # is_fermat_pseudoprime($n, 2) || die "error for n=$n";
  177. #~ if (kronecker($n, 5) == -1) {
  178. #~ if (is_fibonacci_pseudoprime($n)) {
  179. #~ die "Found a special pseudoprime: $n = prod(@f)";
  180. #~ }
  181. #~ }
  182. #~ if (powmod($P, ($k-1)>>1, $k) != $k-1) {
  183. #~ say "false: $k";
  184. #~ }
  185. #say $k;
  186. if (isok($k) and !$seen{$k}++) {
  187. say "Found: $k";
  188. push @values, $k;
  189. }
  190. # push @pseudoprimes, $n;
  191. }
  192. );
  193. say "b($N) <= { ", join(', ', sort { $a <=> $b} @values), " }";
  194. say "Min: b($N) <= ", vecmin(@values);