almost_strong_fermat_psp_from_multiple.pl 1.7 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465
  1. #!/usr/bin/perl
  2. # Generate Fermat pseudoprimes to a given base, that can potentially be strong pseudoprimes to multiple bases.
  3. use 5.036;
  4. use ntheory qw(:all);
  5. use Math::GMPz;
  6. sub fermat_pseudoprimes_from_multiple ($base, $bases, $m, $callback) {
  7. my $u = Math::GMPz::Rmpz_init();
  8. my $v = Math::GMPz::Rmpz_init();
  9. my $w = Math::GMPz::Rmpz_init_set_ui($base);
  10. #my $L = znorder($base, $m);
  11. my $L = lcm(map { znorder($_, $m) } @{$bases});
  12. $m = Math::GMPz->new("$m");
  13. $L = Math::GMPz->new("$L");
  14. Math::GMPz::Rmpz_invert($v, $m, $L) || return;
  15. my $count = 0;
  16. for (my $p = Math::GMPz::Rmpz_init_set($v) ; ++$count < 1e4 ; Math::GMPz::Rmpz_add($p, $p, $L)) {
  17. Math::GMPz::Rmpz_mul($v, $m, $p);
  18. Math::GMPz::Rmpz_sub_ui($u, $v, 1);
  19. Math::GMPz::Rmpz_powm($u, $w, $u, $v);
  20. if (Math::GMPz::Rmpz_cmp_ui($u, 1) == 0) {
  21. $callback->(Math::GMPz::Rmpz_init_set($v));
  22. }
  23. }
  24. }
  25. my %table;
  26. my @primes = @{primes(nth_prime(11))};
  27. forprimes {
  28. my $p = $_;
  29. #my $sig = join(' ', map{ kronecker($_,$p) } @primes);
  30. my $sig = join(' ', map { valuation(znorder($_, $p), 2) } @primes);
  31. push @{$table{$sig}}, $p;
  32. } $primes[-1]+1, 1e6;
  33. foreach my $key(sort { scalar(@{$table{$a}}) <=> scalar(@{$table{$b}})} keys %table) {
  34. #say "$key -> @{$table{$key}}" if scalar(@{$table{$key}} > 1);
  35. my @values = @{$table{$key}};
  36. scalar(@values) > 1 or next;
  37. say "# Generating for $key with ", scalar(@values), " primes";
  38. forcomb {
  39. my @comb = @values[@_];
  40. my $m = vecprod(@comb);
  41. fermat_pseudoprimes_from_multiple(2, \@primes, $m, sub ($n) { say $n if ($n > ~0) });
  42. } scalar(@values), 2;
  43. }