620_from_big_prime_list_2.pl 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. #!/usr/bin/perl
  2. # Author: Daniel "Trizen" Șuteu
  3. # Date: 07 October 2018
  4. # https://github.com/trizen
  5. # A simple algorithm for generating a subset of strong-Lucas pseudoprimes.
  6. # See also:
  7. # https://oeis.org/A217120 -- Lucas pseudoprimes
  8. # https://oeis.org/A217255 -- Strong Lucas pseudoprimes
  9. # https://oeis.org/A177745 -- Semiprimes n such that n divides Fibonacci(n+1).
  10. # https://oeis.org/A212423 -- Frobenius pseudoprimes == 2,3 (mod 5) with respect to Fibonacci polynomial x^2 - x - 1.
  11. use 5.020;
  12. use warnings;
  13. use experimental qw(signatures);
  14. use Math::GMPz;
  15. use ntheory qw(forcomb forprimes is_strong_lucas_pseudoprime random_prime);
  16. use Math::Prime::Util::GMP qw(vecprod powmod divisors kronecker lucas_sequence);
  17. use List::Util qw(uniq);
  18. sub fibonacci_pseudoprimes ($limit, $callback) {
  19. my %common_divisors;
  20. #~ my $r = random_prime(1e8);
  21. #~ my $r2 = random_prime(1e9);
  22. #~ die 'error' if $r <= 1e7;
  23. #~ die 'error' if $r2+1e7 <= $r;
  24. while (<>) {
  25. my $p = (split(' ', $_))[-1] || next;
  26. $p = Math::GMPz->new($p);
  27. #Math::GMPz::Rmpz_kronecker_ui($p, 5) == -1 or next;
  28. say "Processing $p...";
  29. my $p_str = "$p";
  30. foreach my $d (divisors($p - Math::GMPz::Rmpz_kronecker_ui($p, 5))) {
  31. if ((lucas_sequence($p_str, 1, -1, $d))[0] == 0) {
  32. push @{$common_divisors{$d}}, $p_str;
  33. last;
  34. }
  35. }
  36. }
  37. #~ forprimes {
  38. #~ my $p = $_;
  39. #~ foreach my $d (divisors($p - kronecker($p, 5))) {
  40. #~ if ((lucas_sequence($p, 1, -1, $d))[0] == 0) {
  41. #~ push @{$common_divisors{$d}}, $p;
  42. #~ }
  43. #~ }
  44. #~ } 1e7;
  45. #~ forprimes {
  46. #~ my $p = $_;
  47. #~ foreach my $d (divisors($p - kronecker($p, 5))) {
  48. #~ if ((lucas_sequence($p, 1, -1, $d))[0] == 0) {
  49. #~ push @{$common_divisors{$d}}, $p;
  50. #~ }
  51. #~ }
  52. #~ } $r, $r+1e7;
  53. #~ forprimes {
  54. #~ my $p = $_;
  55. #~ foreach my $d (divisors($p - kronecker($p, 5))) {
  56. #~ if ((lucas_sequence($p, 1, -1, $d))[0] == 0) {
  57. #~ push @{$common_divisors{$d}}, $p;
  58. #~ }
  59. #~ }
  60. #~ } $r2, $r2+1e7;
  61. my %seen;
  62. foreach my $arr (values %common_divisors) {
  63. #@$arr = uniq(@$arr);
  64. my $l = $#{$arr} + 1;
  65. foreach my $k (2 .. $l) {
  66. forcomb {
  67. my $n = Math::GMPz->new(vecprod(@{$arr}[@_]));
  68. $callback->($n, @{$arr}[@_]) if !$seen{$n}++;
  69. } $l, $k;
  70. }
  71. }
  72. }
  73. sub PSW_primality_test ($n) {
  74. # Find P such that kronecker(n, P^2 + 4) = -1.
  75. my $P;
  76. for (my $k = 1 ; ; ++$k) {
  77. if (kronecker($n, $k * $k + 4) == -1) {
  78. $P = $k;
  79. last;
  80. }
  81. }
  82. # If LucasU(P, -1, n+1) = 0 (mod n), then n is probably prime.
  83. (lucas_sequence($n, $P, -1, $n + 1))[0] == 0;
  84. }
  85. fibonacci_pseudoprimes(
  86. 10_000,
  87. sub ($n, @f) {
  88. if (is_strong_lucas_pseudoprime($n)) {
  89. say "Lucas pseudoprime: $n";
  90. if (powmod(2, $n-1, $n) == 1) {
  91. die "Found a BPSW counter-example: $n = prod(@f)";
  92. }
  93. }
  94. if (powmod(2, $n-1, $n) == 1) {
  95. say "Fermat pseudoprime: $n";
  96. if (PSW_primality_test($n)) {
  97. die "PSW counter-example: $n = prod(@f)";
  98. }
  99. if (kronecker($n, 5) == -1) {
  100. die "Found a Fibonacci special number: $n = prod(@f)";
  101. }
  102. }
  103. #~ if (kronecker($n, 5) == -1) {
  104. #~ if (powmod(2, $n-1, $n) == 1) {
  105. #~ die "Found a Fibonacci special number: $n = prod(@f)";
  106. #~ }
  107. #~ }
  108. }
  109. );