Skip to content

Commit 7d12fc1

Browse files
committed
Several fixes and simplifications in the generation of non-squarefree Fermat pseudoprimes.
1 parent 08719d8 commit 7d12fc1

7 files changed

+162
-78
lines changed

Math/even_fermat_pseudoprimes_in_range.pl

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
# PARI/GP program:
2222
# even_fermat_psp(A, B, k, base) = A=max(A, vecprod(primes(k))); (f(m, l, p, j) = my(list=List()); forprime(q=p, sqrtnint(B\m, j), if(base%q != 0, my(v=m*q, t=q); while(v <= B, my(L=lcm(l, znorder(Mod(base, t)))); if(gcd(L, v) == 1, if(j==1, if(v>=A && if(k==1, !isprime(v), 1) && (v-1)%L == 0, listput(list, v)), list=concat(list, f(v, L, q+1, j-1))), break); v *= q; t *= q))); list); vecsort(Vec(f(2, 1, 3, k-1)));
2323

24+
# FIXME: it doesn't generate all the terms for bases > 2.
25+
2426
use 5.020;
2527
use warnings;
2628

@@ -35,6 +37,8 @@ ($A, $B, $k, $base, $callback)
3537

3638
$A = vecmax($A, pn_primorial($k));
3739

40+
my %seen;
41+
3842
sub ($m, $L, $lo, $j) {
3943

4044
my $hi = rootint(divint($B, $m), $j);
@@ -53,8 +57,9 @@ ($A, $B, $k, $base, $callback)
5357
for (my ($q, $v) = ($p, $m * $p) ; $v <= $B ; ($q, $v) = ($q * $p, $v * $p)) {
5458
$v >= $A or next;
5559
$k == 1 and is_prime($v) and next;
56-
($v - 1) % znorder($base, $q) == 0 or next;
57-
$callback->($v);
60+
#($v - 1) % znorder($base, $q) == 0 or next;
61+
powmod($base, $v, $v) == $base or next;
62+
$callback->($v) if !$seen{$v}++;
5863
}
5964
}
6065
return;
@@ -65,14 +70,13 @@ ($A, $B, $k, $base, $callback)
6570
$t += $L while ($t < $lo);
6671

6772
for (my $p = $t ; $p <= $hi ; $p += $L) {
68-
if (is_prime($p) and $base % $p != 0) {
69-
for (my ($q, $v) = ($p, $m * $p) ; $v <= $B ; ($q, $v) = ($q * $p, $v * $p)) {
70-
$v >= $A or next;
71-
$k == 1 and is_prime($v) and next;
72-
($v - 1) % $L == 0 or next;
73-
($v - 1) % znorder($base, $q) == 0 or next;
74-
$callback->($v);
75-
}
73+
if (is_prime_power($p) and gcd($m, $p) == 1 and gcd($base, $p) == 1) {
74+
my $v = $m * $p;
75+
$v >= $A or next;
76+
$k == 1 and is_prime($v) and next;
77+
#($v - 1) % znorder($base, $p) == 0 or next;
78+
powmod($base, $v, $v) == $base or next;
79+
$callback->($v) if !$seen{$v}++;
7680
}
7781
}
7882

Math/even_squarefree_fermat_pseudoprimes_in_range.pl

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@
1616
# PARI/GP program (in range) (version 2):
1717
# even_squarefree_fermat(A, B, k, base=2) = A=max(A, vecprod(primes(k))); (f(m, l, lo, k) = my(list=List()); my(hi=sqrtnint(B\m, k)); if(k==1, forprime(p=max(lo, ceil(A/m)), hi, if(base%p != 0, my(t=m*p); if((t-1)%l == 0 && (t-1)%znorder(Mod(base, p)) == 0, listput(list, t)))), forprime(p=lo, hi, if(base%p != 0, my(z=znorder(Mod(base, p))); if(gcd(m, z) == 1, list=concat(list, f(m*p, lcm(l,z), p+1, k-1)))))); list); vecsort(Vec(f(2, 1, 2, k-1)));
1818

19+
# FIXME: it may not generate all the terms for bases > 2.
20+
1921
use 5.020;
2022
use warnings;
2123

Math/fermat_pseudoprimes_in_range.pl

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ ($A, $B, $k, $base, $callback)
3030

3131
$A = vecmax($A, pn_primorial($k));
3232

33+
my %seen;
34+
3335
sub ($m, $L, $lo, $j) {
3436

3537
my $hi = rootint(divint($B, $m), $j);
@@ -49,7 +51,8 @@ ($A, $B, $k, $base, $callback)
4951
$v >= $A or next;
5052
$k == 1 and is_prime($v) and next;
5153
($v - 1) % znorder($base, $q) == 0 or next;
52-
$callback->($v);
54+
#powmod($base, $v-1, $v) == 1 or next;
55+
$callback->($v) if !$seen{$v}++;
5356
}
5457
}
5558
return;
@@ -60,14 +63,14 @@ ($A, $B, $k, $base, $callback)
6063
$t += $L while ($t < $lo);
6164

6265
for (my $p = $t ; $p <= $hi ; $p += $L) {
63-
if (is_prime($p) and $base % $p != 0) {
64-
for (my ($q, $v) = ($p, $m * $p) ; $v <= $B ; ($q, $v) = ($q * $p, $v * $p)) {
65-
$v >= $A or next;
66-
$k == 1 and is_prime($v) and next;
67-
($v - 1) % $L == 0 or next;
68-
($v - 1) % znorder($base, $q) == 0 or next;
69-
$callback->($v);
70-
}
66+
if (is_prime_power($p) and gcd($m, $p) == 1 and gcd($base, $p) == 1) {
67+
68+
my $v = $m * $p;
69+
$v >= $A or next;
70+
$k == 1 and is_prime($v) and next;
71+
($v - 1) % znorder($base, $p) == 0 or next;
72+
#powmod($base, $v-1, $v) == 1 or next;
73+
$callback->($v) if !$seen{$v}++;
7174
}
7275
}
7376

@@ -102,5 +105,25 @@ ($A, $B, $k, $base, $callback)
102105

103106
say join(', ', sort { $a <=> $b } @arr);
104107

108+
# Run some tests
109+
110+
if (0) { # true to run some tests
111+
foreach my $k (1 .. 5) {
112+
113+
my $lo = pn_primorial($k);
114+
my $hi = mulint($lo, 1000);
115+
my $omega_primes = omega_primes($k, $lo, $hi);
116+
117+
foreach my $base (2 .. 100) {
118+
my @this = grep { is_pseudoprime($_, $base) and !is_prime($_) } @$omega_primes;
119+
my @that;
120+
fermat_pseudoprimes_in_range($lo, $hi, $k, $base, sub ($n) { push @that, $n });
121+
@that = sort { $a <=> $b } @that;
122+
join(' ', @this) eq join(' ', @that)
123+
or die "Error for k = $k and base = $base with hi = $hi\n(@this) != (@that)";
124+
}
125+
}
126+
}
127+
105128
__END__
106129
91, 121, 286, 671, 703, 949, 1105, 1541, 1729, 1891, 2465, 2665, 2701, 2821, 3281, 3367, 3751, 4961, 5551, 6601, 7381, 8401, 8911, 10585, 11011, 12403, 14383, 15203, 15457, 15841, 16471, 16531, 18721, 19345, 23521, 24046, 24661, 24727, 28009, 29161, 29341, 30857, 31621, 31697, 32791, 38503, 41041, 44287, 46657, 46999, 47197, 49051, 49141, 50881, 52633, 53131, 55261, 55969, 63139, 63973, 65485, 68887, 72041, 74593, 75361, 76627, 79003, 82513, 83333, 83665, 87913, 88561, 88573, 88831, 90751, 93961, 96139, 97567

Math/fermat_pseudoprimes_in_range_mpz.pl

Lines changed: 30 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ ($A, $B, $k, $base, $callback)
3535
my $v = Math::GMPz::Rmpz_init();
3636
my $w = Math::GMPz::Rmpz_init();
3737

38+
my %seen;
39+
3840
sub ($m, $L, $lo, $j) {
3941

4042
Math::GMPz::Rmpz_tdiv_q($u, $B, $m);
@@ -63,24 +65,18 @@ ($A, $B, $k, $base, $callback)
6365
$t += $L while ($t < $lo);
6466

6567
for (my $p = $t ; $p <= $hi ; $p += $L) {
66-
if (is_prime($p) and $base % $p != 0) {
68+
if (is_prime_power($p) and Math::GMPz::Rmpz_gcd_ui($Math::GMPz::NULL, $m, $p) == 1 and gcd($base, $p) == 1) {
6769

68-
Math::GMPz::Rmpz_set_ui($u, $p);
6970
Math::GMPz::Rmpz_mul_ui($v, $m, $p);
7071

71-
while (Math::GMPz::Rmpz_cmp($v, $B) <= 0) {
72-
if ($k == 1 and is_prime($v)) {
73-
## ok
74-
}
75-
elsif (Math::GMPz::Rmpz_cmp($v, $A) >= 0) {
76-
Math::GMPz::Rmpz_sub_ui($w, $v, 1);
77-
if ((ref($L) ? Math::GMPz::Rmpz_divisible_p($w, $L) : Math::GMPz::Rmpz_divisible_ui_p($w, $L))
78-
and Math::GMPz::Rmpz_divisible_ui_p($w, znorder($base, $u))) {
79-
$callback->(Math::GMPz::Rmpz_init_set($v));
80-
}
72+
if ($k == 1 and is_prime($p) and Math::GMPz::Rmpz_cmp_ui($m, 1) == 0) {
73+
## ok
74+
}
75+
elsif (Math::GMPz::Rmpz_cmp($v, $A) >= 0) {
76+
Math::GMPz::Rmpz_sub_ui($w, $v, 1);
77+
if (Math::GMPz::Rmpz_divisible_ui_p($w, znorder($base, $p))) {
78+
$callback->(Math::GMPz::Rmpz_init_set($v)) if !$seen{Math::GMPz::Rmpz_get_str($v, 10)}++;
8179
}
82-
Math::GMPz::Rmpz_mul_ui($u, $u, $p);
83-
Math::GMPz::Rmpz_mul_ui($v, $v, $p);
8480
}
8581
}
8682
}
@@ -126,5 +122,25 @@ ($A, $B, $k, $base, $callback)
126122

127123
say join(', ', sort { $a <=> $b } @arr);
128124

125+
# Run some tests
126+
127+
if (0) { # true to run some tests
128+
foreach my $k (1 .. 5) {
129+
130+
my $lo = pn_primorial($k);
131+
my $hi = mulint($lo, 1000);
132+
my $omega_primes = omega_primes($k, $lo, $hi);
133+
134+
foreach my $base (2 .. 100) {
135+
my @this = grep { is_pseudoprime($_, $base) and !is_prime($_) } @$omega_primes;
136+
my @that;
137+
fermat_pseudoprimes_in_range($lo, $hi, $k, $base, sub ($n) { push @that, $n });
138+
@that = sort { $a <=> $b } @that;
139+
join(' ', @this) eq join(' ', @that)
140+
or die "Error for k = $k and base = $base with hi = $hi\n(@this) != (@that)";
141+
}
142+
}
143+
}
144+
129145
__END__
130146
91, 121, 286, 671, 703, 949, 1105, 1541, 1729, 1891, 2465, 2665, 2701, 2821, 3281, 3367, 3751, 4961, 5551, 6601, 7381, 8401, 8911, 10585, 11011, 12403, 14383, 15203, 15457, 15841, 16471, 16531, 18721, 19345, 23521, 24046, 24661, 24727, 28009, 29161, 29341, 30857, 31621, 31697, 32791, 38503, 41041, 44287, 46657, 46999, 47197, 49051, 49141, 50881, 52633, 53131, 55261, 55969, 63139, 63973, 65485, 68887, 72041, 74593, 75361, 76627, 79003, 82513, 83333, 83665, 87913, 88561, 88573, 88831, 90751, 93961, 96139, 97567

Math/squarefree_fermat_pseudoprimes_in_range.pl

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,5 +83,25 @@ ($A, $B, $k, $base, $callback)
8383

8484
say join(', ', sort { $a <=> $b } @arr);
8585

86+
# Run some tests
87+
88+
if (0) { # true to run some tests
89+
foreach my $k (2 .. 6) {
90+
91+
my $lo = pn_primorial($k);
92+
my $hi = mulint($lo, 1000);
93+
my @omega_primes = grep { is_square_free($_) } @{omega_primes($k, $lo, $hi)};
94+
95+
foreach my $base (2 .. 100) {
96+
my @this = grep { is_pseudoprime($_, $base) } @omega_primes;
97+
my @that;
98+
squarefree_fermat_pseudoprimes_in_range($lo, $hi, $k, $base, sub ($n) { push @that, $n });
99+
@that = sort { $a <=> $b } @that;
100+
join(' ', @this) eq join(' ', @that)
101+
or die "Error for k = $k and base = $base with hi = $hi\n(@this) != (@that)";
102+
}
103+
}
104+
}
105+
86106
__END__
87107
825265, 1050985, 1275681, 2113665, 2503501, 2615977, 2882265, 3370641, 3755521, 4670029, 4698001, 4895065, 5034601, 6242685, 6973057, 7428421, 8322945, 9223401, 9224391, 9890881, 10877581, 12067705, 12945745, 13757653, 13823601, 13992265, 16778881, 17698241, 18007345, 18162001, 18779761, 19092921, 22203181, 22269745, 23386441, 25266745, 25831585, 26553241, 27218269, 27336673, 27736345, 28175001, 28787185, 31146661, 32368609, 32428045, 32756581, 34111441, 34386121, 35428141, 36121345, 36168265, 36507801, 37167361, 37695505, 37938901, 38790753, 40280065, 40886241, 41298985, 41341321, 41424801, 41471521, 42689305, 43136821, 46282405, 47006785, 49084321, 49430305, 51396865, 52018341, 52452905, 53661945, 54177949, 54215161, 54651961, 55035001, 55329985, 58708761, 59586241, 60761701, 61679905, 63337393, 63560685, 64567405, 64685545, 67371265, 67994641, 68830021, 69331969, 71804161, 72135505, 72192021, 72348409, 73346365, 73988641, 74165065, 75151441, 76595761, 77442905, 78397705, 80787421, 83058481, 84028407, 84234745, 85875361, 86968981, 88407361, 88466521, 88689601, 89816545, 89915365, 92027001, 92343745, 92974921, 93614521, 93839201, 93869665, 96259681, 96386865, 96653985, 98124481, 98756281, 99551881

Math/strong_fermat_pseudoprimes_in_range.pl

Lines changed: 32 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ ($A, $B, $k, $base, $callback)
3131
$A = vecmax($A, pn_primorial($k));
3232
$A > $B and return;
3333

34+
my %seen;
35+
3436
my $generator = sub ($m, $L, $lo, $j, $k_exp, $congr) {
3537

3638
my $hi = rootint(divint($B, $m), $j);
@@ -54,7 +56,7 @@ ($A, $B, $k, $base, $callback)
5456
$v >= $A or next;
5557
$k == 1 and is_prime($v) and next;
5658
($v - 1) % znorder($base, $q) == 0 or next;
57-
$callback->($v);
59+
$callback->($v) if !$seen{$v}++;
5860
}
5961
}
6062
return;
@@ -65,19 +67,17 @@ ($A, $B, $k, $base, $callback)
6567
$t += $L while ($t < $lo);
6668

6769
for (my $p = $t ; $p <= $hi ; $p += $L) {
68-
if (is_prime($p) and $base % $p != 0) {
6970

70-
my $val = valuation($p - 1, 2);
71-
$val > $k_exp or next;
72-
powmod($base, ($p - 1) >> ($val - $k_exp), $p) == ($congr % $p) or next;
71+
my $val = valuation($p - 1, 2);
72+
$val > $k_exp or next;
73+
powmod($base, ($p - 1) >> ($val - $k_exp), $p) == ($congr % $p) or next;
7374

74-
for (my ($q, $v) = ($p, $m * $p) ; $v <= $B ; ($q, $v) = ($q * $p, $v * $p)) {
75-
$v >= $A or next;
76-
$k == 1 and is_prime($v) and next;
77-
($v - 1) % $L == 0 or next;
78-
($v - 1) % znorder($base, $q) == 0 or next;
79-
$callback->($v);
80-
}
75+
if (is_prime_power($p) and gcd($m, $p) == 1 and gcd($base, $p) == 1) {
76+
my $v = $m * $p;
77+
$v >= $A or next;
78+
$k == 1 and is_prime($v) and next;
79+
($v - 1) % znorder($base, $p) == 0 or next;
80+
$callback->($v) if !$seen{$v}++;
8181
}
8282
}
8383

@@ -123,5 +123,25 @@ ($A, $B, $k, $base, $callback)
123123

124124
say join(', ', sort { $a <=> $b } @arr);
125125

126+
# Run some tests
127+
128+
if (0) { # true to run some tests
129+
foreach my $k (1 .. 5) {
130+
131+
my $lo = pn_primorial($k);
132+
my $hi = mulint($lo, 10000);
133+
my $omega_primes = omega_primes($k, $lo, $hi);
134+
135+
foreach my $base (2 .. 100) {
136+
my @this = grep { is_strong_pseudoprime($_, $base) and !is_prime($_) } @$omega_primes;
137+
my @that;
138+
strong_fermat_pseudoprimes_in_range($lo, $hi, $k, $base, sub ($n) { push @that, $n });
139+
@that = sort { $a <=> $b } @that;
140+
join(' ', @this) eq join(' ', @that)
141+
or die "Error for k = $k and base = $base with hi = $hi\n(@this) != (@that)";
142+
}
143+
}
144+
}
145+
126146
__END__
127147
121, 703, 1891, 3281, 8401, 8911, 10585, 12403, 16531, 18721, 19345, 23521, 31621, 44287, 47197, 55969, 63139, 74593, 79003, 82513, 87913, 88573, 97567

Math/strong_fermat_pseudoprimes_in_range_mpz.pl

Lines changed: 32 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,8 @@ ($A, $B, $k, $base, $callback)
3333

3434
my $u = Math::GMPz::Rmpz_init();
3535
my $v = Math::GMPz::Rmpz_init();
36-
my $w = Math::GMPz::Rmpz_init();
36+
37+
my %seen;
3738

3839
my $generator = sub ($m, $L, $lo, $j, $k_exp, $congr) {
3940

@@ -48,22 +49,6 @@ ($A, $B, $k, $base, $callback)
4849

4950
if ($j == 1) {
5051

51-
Math::GMPz::Rmpz_cdiv_q($u, $A, $m);
52-
53-
if (Math::GMPz::Rmpz_fits_ulong_p($u)) {
54-
$lo = vecmax($lo, Math::GMPz::Rmpz_get_ui($u));
55-
}
56-
elsif (Math::GMPz::Rmpz_cmp_ui($u, $lo) > 0) {
57-
if (Math::GMPz::Rmpz_cmp_ui($u, $hi) > 0) {
58-
return;
59-
}
60-
$lo = Math::GMPz::Rmpz_get_ui($u);
61-
}
62-
63-
if ($lo > $hi) {
64-
return;
65-
}
66-
6752
Math::GMPz::Rmpz_invert($v, $m, $L);
6853

6954
if (Math::GMPz::Rmpz_cmp_ui($v, $hi) > 0) {
@@ -79,28 +64,22 @@ ($A, $B, $k, $base, $callback)
7964
$t += $L while ($t < $lo);
8065

8166
for (my $p = $t ; $p <= $hi ; $p += $L) {
82-
if (is_prime($p) and $base % $p != 0) {
67+
68+
if (is_prime_power($p) and Math::GMPz::Rmpz_gcd_ui($Math::GMPz::NULL, $m, $p) == 1 and gcd($base, $p) == 1) {
8369

8470
my $val = valuation($p - 1, 2);
8571
$val > $k_exp or next;
8672
powmod($base, ($p - 1) >> ($val - $k_exp), $p) == ($congr % $p) or next;
8773

88-
Math::GMPz::Rmpz_set_ui($u, $p);
89-
Math::GMPz::Rmpz_mul_ui($v, $m, $p);
90-
91-
while (Math::GMPz::Rmpz_cmp($v, $B) <= 0) {
92-
if ($k == 1 and is_prime($v)) {
93-
## ok
94-
}
95-
else {
96-
Math::GMPz::Rmpz_sub_ui($w, $v, 1);
97-
if ((ref($L) ? Math::GMPz::Rmpz_divisible_p($w, $L) : Math::GMPz::Rmpz_divisible_ui_p($w, $L))
98-
and Math::GMPz::Rmpz_divisible_ui_p($w, znorder($base, $u))) {
99-
$callback->(Math::GMPz::Rmpz_init_set($v));
100-
}
74+
if ($k == 1 and is_prime($p) and Math::GMPz::Rmpz_cmp_ui($m, 1) == 0) {
75+
## ok
76+
}
77+
else {
78+
Math::GMPz::Rmpz_mul_ui($v, $m, $p);
79+
Math::GMPz::Rmpz_sub_ui($u, $v, 1);
80+
if (Math::GMPz::Rmpz_divisible_ui_p($u, znorder($base, $p))) {
81+
$callback->(Math::GMPz::Rmpz_init_set($v)) if !$seen{Math::GMPz::Rmpz_get_str($v, 10)}++;
10182
}
102-
Math::GMPz::Rmpz_mul_ui($u, $u, $p);
103-
Math::GMPz::Rmpz_mul_ui($v, $v, $p);
10483
}
10584
}
10685
}
@@ -157,5 +136,25 @@ ($A, $B, $k, $base, $callback)
157136

158137
say join(', ', sort { $a <=> $b } @arr);
159138

139+
# Run some tests
140+
141+
if (0) { # true to run some tests
142+
foreach my $k (1 .. 5) {
143+
144+
my $lo = pn_primorial($k);
145+
my $hi = mulint($lo, 10000);
146+
my $omega_primes = omega_primes($k, $lo, $hi);
147+
148+
foreach my $base (2 .. 100) {
149+
my @this = grep { is_strong_pseudoprime($_, $base) and !is_prime($_) } @$omega_primes;
150+
my @that;
151+
strong_fermat_pseudoprimes_in_range($lo, $hi, $k, $base, sub ($n) { push @that, $n });
152+
@that = sort { $a <=> $b } @that;
153+
join(' ', @this) eq join(' ', @that)
154+
or die "Error for k = $k and base = $base with hi = $hi\n(@this) != (@that)";
155+
}
156+
}
157+
}
158+
160159
__END__
161160
121, 703, 1891, 3281, 8401, 8911, 10585, 12403, 16531, 18721, 19345, 23521, 31621, 44287, 47197, 55969, 63139, 74593, 79003, 82513, 87913, 88573, 97567

0 commit comments

Comments
 (0)