upper-bounds_with_residue.pl 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  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. # a(n) is the smallest odd composite k such that prime(n)^((k-1)/2) == -1 (mod k) and b^((k-1)/2) == 1 (mod k) for every natural b < prime(n).
  19. # a(n) : 3277, 5173601, 2329584217, 188985961, ... Is this sequence infinite?
  20. # I found upper-bounds only for the next 5 terms:
  21. # a(5) <= 32203213602841
  22. # a(6) <= 323346556958041
  23. # a(7) <= 2528509579568281
  24. # a(8) <= 5189206896360728641
  25. # a(9) <= 12155831039329417441
  26. # 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.
  27. # I couldn't find an upper-bound for a(10), which may be larger than 2^64 (assuming that it exists).
  28. # 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:
  29. # prime(n)^d == -1 (mod p)
  30. # prime(n)^d == -1 (mod q)
  31. # 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.
  32. # 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.
  33. # Once we have k = p*q, it's very likely that:
  34. # prime(n)^((k-1)/2) == -1 (mod k)
  35. # For each such number k, we check if:
  36. # b^((k-1)/2) == 1 (mod k) for every natural b < prime(n)
  37. # Several more upper-bounds (example), with possible gaps, for each a(2)-a(7):
  38. # a(2) <= { 5173601, 6787327, 15978007, 314184487, 581618143, 682528687, 717653129, 1536112001, 1854940231, 1860373241, 2693739751, 3344191241, 4916322919, ... }
  39. # a(3) <= { 2329584217, 4394140633, 18491988217, 71430713857, 146463308377, 306190965697, 542381064457, 662181331897, 1749760817617, 2600044182457, 3420965597017, ... }
  40. # a(4) <= { 188985961, 922845241, 41610787921, 55165631041, 85103495641, 130173194161, 178420380841, 451403438041, 577255246921, 669094855201, 842611640041, 1038185022241, ... }
  41. # a(5) <= { 32203213602841, 92223430598881, 181122243848281, 244362410507881, 323731175307121, 359643366744481, 383326325785201, 503561507122801, ... }
  42. # a(6) <= { 323346556958041, 449287527233161, 871447814622001, 2419909071073201, ... }
  43. # a(7) <= { 2528509579568281, 51558565269914641, 251985537187183801, ... }
  44. # Let b(n) be the smallest odd composite k such that q^((k-1)/2) == -1 (mod k) for every prime q <= prime(n).
  45. #~ b(1) = 3277
  46. #~ b(2) = 1530787
  47. #~ b(3) <= 3697278427
  48. #~ b(4) <= 118670087467
  49. #~ b(5) <= 2152302898747
  50. #~ b(6) <= 614796634515444067
  51. #~ b(7) <= 614796634515444067
  52. my $N = 5;
  53. my $multiplier = 4;
  54. my $P = nth_prime($N);
  55. my $MAX = ~0;
  56. my $LIMIT = 1e5;
  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. my @primes_bellow = @{primes($P)};
  69. sub non_residue {
  70. my ($n) = @_;
  71. foreach my $p (@primes) {
  72. #if ($p > $Q) {
  73. # return -1;
  74. # }
  75. sqrtmod($p, $n) // return $p;
  76. }
  77. return -1;
  78. }
  79. #~ #139309114031, a(9) <= 7947339136801, a(10) <= 72054898434289.
  80. #~ say non_residue(139309114031, nth_prime(8));
  81. #~ say non_residue(7947339136801, nth_prime(9));
  82. #~ say non_residue(72054898434289, nth_prime(10));
  83. #~ __END__
  84. #~ say non_residue(72054898434289, nth_prime(10));
  85. #~ __END__
  86. sub isok {
  87. my ($k) = @_;
  88. my $t = $k-1;
  89. my $u = $t>>1;
  90. vecall { powmod($_, $u, $k) == $t } @primes_bellow;
  91. }
  92. #say isok(614796634515444067);
  93. #say isok(8614572538322761627);
  94. #392044843, 1568179369
  95. #~ foreach my $p(factor(2152302898747)) {
  96. #~ foreach my $d(divisors(($p-1)>>1)) {
  97. #~ if (vecall {my $t = powmod($_, $d, $p); ($t == $p-1) } @primes_bellow) {
  98. #~ say "$p : $d -> ", join(', ', divisors($d));
  99. #~ }
  100. #~ }
  101. #~ say '';
  102. #~ }
  103. # Let a'(n) be the smallest odd prime p such that b^((p-1)/2) == 1 (mod p) for every natural b < prime(n).
  104. # a(n) is the least number such that the n-th prime is the least quadratic nonresidue (not necessarily coprime) modulo a(n).
  105. #~ __END__
  106. #~ forprimes {
  107. #~ if (is_prime(($_-1)*$multiplier + 1)) {
  108. #~ my $k = Math::GMPz->new($_)*(($_-1)*$multiplier + 1);
  109. #~ if (isok($k)) {
  110. #~ die "a($N) <= $k\n";
  111. #~ }
  112. #~ }
  113. #~ } 1e11, 1e12;
  114. #~ __END__
  115. sub fermat_pseudoprimes ($limit, $callback) {
  116. say "Collecting primes...";
  117. my %common_divisors;
  118. forprimes {
  119. my $p = $_;
  120. my $common = 0;
  121. foreach my $d (divisors(($p-1)>>1)) {
  122. #if (powmod($P, $d, $p) == $p-1 ) {
  123. if (vecall { powmod($_, $d, $p) == $p-1 } @primes_bellow) {
  124. #push @{$common_divisors{$d}}, $p;
  125. foreach my $g (divisors($d)) {
  126. if ($g * 1000 >= $d) {
  127. push @{$common_divisors{$g}}, $p;
  128. }
  129. }
  130. }
  131. }
  132. #if (@div) {
  133. # push @{$common_divisors{"@div"}}, $p;
  134. #}
  135. #~ if ($common) {
  136. #~ foreach my $n(2..100) {
  137. #~ if (is_prime(($p-1)*$n + 1)) {
  138. #~ my $q = ($p-1)*$n + 1;
  139. #~ foreach my $d (divisors($q - 1)) {
  140. #~ if (powmod($P, $d, $q) == $q-1) {
  141. #~ push @{$common_divisors{$d}}, $q;
  142. #~ }
  143. #~ }
  144. #~ }
  145. #~ }
  146. #~ }
  147. # }
  148. } 3, $limit;
  149. say "Generating combinations...";
  150. #~ forprimes {
  151. #~ my $p = $_;
  152. #~ foreach my $d (divisors($p - 1)) {
  153. #~ if (powmod($P, $d, $p) == $p-1) {
  154. #~ push @{$common_divisors{$d}}, $p;
  155. #~ }
  156. #~ }
  157. #~ } $limit>>1, $limit;
  158. my %seen;
  159. foreach my $value (values %common_divisors) {
  160. my $arr = [uniqnum(@$value)];
  161. my $l = $#{$arr} + 1;
  162. if ($l > 100) {
  163. say "Combinations: $l";
  164. }
  165. foreach my $k (2..$l) {
  166. forcomb {
  167. my $n = prod(@{$arr}[@_]);
  168. if ($n <= $MAX) {
  169. $callback->($n) #if !$seen{$n}++;
  170. }
  171. } $l, $k;
  172. }
  173. }
  174. }
  175. #~ sub is_fermat_pseudoprime ($n, $base) {
  176. #~ powmod($base, $n - 1, $n) == 1;
  177. #~ }
  178. #~ sub is_fibonacci_pseudoprime($n) {
  179. #~ (lucas_sequence($n, 1, -1, $n - kronecker($n, 5)))[0] == 0;
  180. #~ }
  181. my @values;
  182. my %seen;
  183. fermat_pseudoprimes(
  184. $LIMIT,
  185. sub ($k) {
  186. # is_fermat_pseudoprime($n, 2) || die "error for n=$n";
  187. #~ if (kronecker($n, 5) == -1) {
  188. #~ if (is_fibonacci_pseudoprime($n)) {
  189. #~ die "Found a special pseudoprime: $n = prod(@f)";
  190. #~ }
  191. #~ }
  192. #~ if (powmod($P, ($k-1)>>1, $k) != $k-1) {
  193. #~ say "false: $k";
  194. #~ }
  195. if (isok($k) and !$seen{$k}++) {
  196. say "Found: $k";
  197. push @values, $k;
  198. }
  199. # push @pseudoprimes, $n;
  200. }
  201. );
  202. say "a($N) <= { ", join(', ', sort { $a <=> $b} @values), " }";
  203. say "Min: a($N) <= ", vecmin(@values);