generate_frobenius_pseudoprimes.pl 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. #!/usr/bin/perl
  2. # Generate Frobenius pseudoprimes to the polynomial x^2 + 5x + 5.
  3. # No known such pseudoprime `n` is known with `legendre(n,5) = -1`.
  4. use 5.020;
  5. use warnings;
  6. use experimental qw(signatures);
  7. use List::Util qw(shuffle);
  8. use ntheory qw(forcomb forprimes kronecker divisors lucas_sequence factor_exp factor);
  9. use Math::Prime::Util::GMP qw(is_frobenius_pseudoprime vecprod binomial);
  10. sub rad ($n) {
  11. vecprod(map{$_->[0]}factor_exp($n));
  12. }
  13. sub gpf ($n) {
  14. (factor($n))[-1];
  15. }
  16. sub fermat_pseudoprimes ($limit, $callback) {
  17. my %common_divisors;
  18. warn ":: Sieving...\n";
  19. forprimes {
  20. my $p = $_;
  21. #foreach my $d (divisors($p - kronecker($p, 5))) {
  22. foreach my $d(divisors($p-kronecker($p, 5))) {
  23. next if ($d == 1);
  24. next if ($d+1 >= $p);
  25. #if ((lucas_sequence($p, -5, 5, $d))[1] == 2 and
  26. my ($U, $V) = (lucas_sequence($p, -5, 5, $d));
  27. #if ($U == 0 and $V == 2) {
  28. #if ($U == 0 and $V == 2) {
  29. if ($U == 0 and $V == 2) {
  30. #say join ' ', factor $d;
  31. push @{$common_divisors{rad($d)}}, $p;
  32. #push @{$common_divisors{ vecsum todigits($p, $d) }}, $p;
  33. }
  34. }
  35. } $limit;
  36. warn ":: Generating combinations...\n";
  37. foreach my $arr (values %common_divisors) {
  38. my $l = scalar(@$arr);
  39. $arr = [shuffle @$arr];
  40. foreach my $k (2 .. $l) {
  41. binomial($l, $k) > 1e3 and last;
  42. forcomb {
  43. # my $n = prod(@{$arr}[@_]);
  44. # $callback->($n) #if !$seen{$n}++;
  45. my $n = vecprod(@{$arr}[@_]);
  46. if ($n > ~0) {
  47. $callback->($n);
  48. }
  49. } $l, $k;
  50. }
  51. }
  52. }
  53. sub is_fermat_pseudoprime ($n, $base) {
  54. powmod($base, $n - 1, $n) == 1;
  55. }
  56. sub is_fibonacci_pseudoprime($n) {
  57. (lucas_sequence($n, 1, -1, $n - kronecker($n, 5)))[0] == 0;
  58. }
  59. my %seen;
  60. fermat_pseudoprimes(
  61. 1e7,
  62. sub ($n) {
  63. #if is_fermat_pseudoprime($n, 2) || die "error for n=$n";
  64. #if (kronecker($n, 5) == -1) {
  65. # if (is_fibonacci_pseudoprime($n)) {
  66. # die "Found a special pseudoprime: $n = prod(@f)";
  67. # }
  68. #}
  69. #push @pseudoprimes, $n;
  70. #say $n if ($n > 1e15 and is_pseudoprime($n, 2) and !$seen{$n}++);
  71. if (is_frobenius_pseudoprime($n, -5, 5)) {
  72. say $n if !$seen{$n}++;
  73. if (kronecker($n,5) == -1) {
  74. die "Counter-example: $n";
  75. }
  76. }
  77. }
  78. );