Skip to content

Commit 8104901

Browse files
committed
pc?ul: parallel testing of primes
When we want to know whether all of a set of values are prime, do only minimal checks of each one initially, then do slower checks. Currently this just crudely splits the primality testing into the "primality pretest" and the final BPSW step; consider further splitting up the pretest work.
1 parent 70b1cee commit 8104901

File tree

3 files changed

+142
-37
lines changed

3 files changed

+142
-37
lines changed

coul.c

Lines changed: 94 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,19 @@ static inline bool test_multi_append(mpz_t n, uint vi, uint t, uint e) {
294294
tm->e = e;
295295
return tau_multi_prep(i);
296296
}
297+
/* Note: test_prime_append() steals the input mpz_t */
298+
static inline bool test_prime_append(mpz_t n, uint vi) {
299+
uint i = tm_count++;
300+
t_tm *tm = &taum[i];
301+
mpz_swap(tm->n, n);
302+
tm->vi = vi;
303+
tm->t = 2;
304+
tm->e = 1;
305+
return tau_prime_prep(i);
306+
}
307+
static inline uint test_prime_run(void) {
308+
return tau_prime_run(tm_count);
309+
}
297310
static inline uint test_multi_run(void) {
298311
return tau_multi_run(tm_count);
299312
}
@@ -1885,6 +1898,29 @@ bool test_zprime(mpz_t qq, mpz_t o, mpz_t ati) {
18851898
return _GMP_is_prob_prime(Z(wv_cand));
18861899
}
18871900

1901+
bool test_1primes(uint *need, uint nc) {
1902+
uint good = 0;
1903+
test_multi_reset();
1904+
for (uint i = 0; i < nc; ++i) {
1905+
uint vi = need[i];
1906+
mpz_set(Z(temp), wv_o[vi]);
1907+
if (!test_prime_append(Z(temp), vi)) {
1908+
TRACK_BAD(good, vi);
1909+
return 0;
1910+
}
1911+
#ifdef TRACK_STATS
1912+
if (taum[tm_count - 1].state == 0)
1913+
++good;
1914+
#endif
1915+
}
1916+
uint remain = test_prime_run();
1917+
if (remain) {
1918+
TRACK_BAD(nc - remain, taum[0].vi);
1919+
return 0;
1920+
}
1921+
return 1;
1922+
}
1923+
18881924
bool test_1multi(uint *need, uint nc, uint *t) {
18891925
uint good = 0;
18901926
test_multi_reset();
@@ -1905,6 +1941,54 @@ bool test_1multi(uint *need, uint nc, uint *t) {
19051941
return remain ? 0 : 1;
19061942
}
19071943

1944+
bool test_primes(uint *need, uint nc, ulong ati) {
1945+
uint good = 0;
1946+
test_multi_reset();
1947+
for (uint i = 0; i < nc; ++i) {
1948+
uint vi = need[i];
1949+
mpz_mul_ui(Z(temp), wv_qq[vi], ati);
1950+
mpz_add(Z(temp), Z(temp), wv_o[vi]);
1951+
if (!test_prime_append(Z(temp), vi)) {
1952+
TRACK_BAD(good, vi);
1953+
return 0;
1954+
}
1955+
#ifdef TRACK_STATS
1956+
if (taum[tm_count - 1].state == 0)
1957+
++good;
1958+
#endif
1959+
}
1960+
uint remain = test_prime_run();
1961+
if (remain) {
1962+
TRACK_BAD(nc - remain, taum[0].vi);
1963+
return 0;
1964+
}
1965+
return 1;
1966+
}
1967+
1968+
bool test_zprimes(uint *need, uint nc, mpz_t ati) {
1969+
uint good = 0;
1970+
test_multi_reset();
1971+
for (uint i = 0; i < nc; ++i) {
1972+
uint vi = need[i];
1973+
mpz_mul(Z(temp), wv_qq[vi], ati);
1974+
mpz_add(Z(temp), Z(temp), wv_o[vi]);
1975+
if (!test_prime_append(Z(temp), vi)) {
1976+
TRACK_BAD(good, vi);
1977+
return 0;
1978+
}
1979+
#ifdef TRACK_STATS
1980+
if (taum[tm_count - 1].state == 0)
1981+
++good;
1982+
#endif
1983+
}
1984+
uint remain = test_prime_run();
1985+
if (remain) {
1986+
TRACK_BAD(nc - remain, taum[0].vi);
1987+
return 0;
1988+
}
1989+
return 1;
1990+
}
1991+
19081992
bool test_multi(uint *need, uint nc, ulong ati, uint *t) {
19091993
uint good = 0;
19101994
test_multi_reset();
@@ -2171,15 +2255,8 @@ void walk_v(t_level *cur_level, mpz_t start) {
21712255
goto next_pell;
21722256
}
21732257

2174-
for (uint i = 0; i < npc; ++i) {
2175-
uint vi = need_prime[i];
2176-
if (!test_zprime(wv_qq[vi], wv_o[vi], Z(wv_ati))) {
2177-
TRACK_BAD(nqc + i, need_prime[i]);
2178-
goto next_pell;
2179-
} else {
2180-
TRACK_GOOD(nqc + i, need_prime[i]);
2181-
}
2182-
}
2258+
if (!test_zprimes(need_prime, npc, Z(wv_ati)))
2259+
goto next_pell;
21832260
/* TODO: bail and print somewhere here if 'opt_print' */
21842261
if (!test_zmulti(need_other, noc, Z(wv_ati), t))
21852262
goto next_pell;
@@ -2291,15 +2368,8 @@ void walk_v(t_level *cur_level, mpz_t start) {
22912368
goto next_sqati;
22922369
}
22932370

2294-
for (uint i = 0; i < npc; ++i) {
2295-
uint vi = need_prime[i];
2296-
if (!test_zprime(wv_qq[vi], wv_o[vi], Z(wv_ati))) {
2297-
TRACK_BAD(1 + i, need_prime[i]);
2298-
goto next_sqati;
2299-
} else {
2300-
TRACK_GOOD(1 + i, need_prime[i]);
2301-
}
2302-
}
2371+
if (!test_zprimes(need_prime, npc, Z(wv_ati)))
2372+
goto next_sqati;
23032373
/* TODO: bail and print somewhere here if 'opt_print' */
23042374
if (!test_zmulti(need_other, noc, Z(wv_ati), t))
23052375
goto next_sqati;
@@ -2353,15 +2423,8 @@ void walk_v(t_level *cur_level, mpz_t start) {
23532423
fflush(rfp);
23542424
#endif
23552425
/* note: we have no squares */
2356-
for (uint i = 0; i < npc; ++i) {
2357-
uint vi = need_prime[i];
2358-
if (!test_prime(wv_qq[vi], wv_o[vi], ati)) {
2359-
TRACK_BAD(i, need_prime[i]);
2360-
goto next_ati;
2361-
} else {
2362-
TRACK_GOOD(i, need_prime[i]);
2363-
}
2364-
}
2426+
if (!test_primes(need_prime, npc, ati))
2427+
goto next_ati;
23652428
/* TODO: bail and print somewhere here if 'opt_print' */
23662429
if (!test_multi(need_other, noc, ati, t))
23672430
goto next_ati;
@@ -2436,13 +2499,8 @@ void walk_1(t_level *cur_level, uint vi) {
24362499
}
24372500
++countwi;
24382501
TRACK_GOOD(0, vi);
2439-
for (uint i = 0; i < npc; ++i)
2440-
if (!_GMP_is_prob_prime(wv_o[need_prime[i]])) {
2441-
TRACK_BAD(1 + i, need_prime[i]);
2442-
return;
2443-
} else {
2444-
TRACK_GOOD(1 + i, need_prime[i]);
2445-
}
2502+
if (!test_1primes(need_prime, npc))
2503+
return;
24462504
oc_t = t;
24472505
qsort(need_other, noc, sizeof(uint), &other_comparator);
24482506
if (!test_1multi(need_other, noc, t))
@@ -2530,9 +2588,8 @@ void walk_1_set(t_level *cur_level, uint vi, ulong plow, ulong phigh, uint x) {
25302588
mpz_set(wv_o[vj], Z(w1_j));
25312589
}
25322590
++countwi;
2533-
for (uint i = 0; i < npc; ++i)
2534-
if (!_GMP_is_prob_prime(wv_o[need_prime[i]]))
2535-
goto reject_this_one;
2591+
if (!test_1primes(need_prime, npc))
2592+
goto reject_this_one;
25362593
oc_t = t;
25372594
qsort(need_other, noc, sizeof(uint), &other_comparator);
25382595
if (!test_1multi(need_other, noc, t))

coultau.c

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include "coul.h"
44
#include "coultau.h"
55
#include "factor.h"
6+
#include "gmp_main.h"
67
#include "primality.h"
78
#include "utility.h"
89
#include "pbrent63.h"
@@ -641,6 +642,22 @@ static inline bool prep_abort(t_tm *tm, bool result) {
641642
return result;
642643
}
643644

645+
bool tau_prime_prep(uint i) {
646+
/* FIXME: break this out further */
647+
int res = primality_pretest(taum[i].n);
648+
if (res == 0)
649+
return 0;
650+
taum[i].state = (res == 1) ? 1 : 0;
651+
return 1;
652+
}
653+
654+
/* Given taum[i].{n, t, vi, e}, does initial fast tests that may rule
655+
* out the possibility that tau(n^e) == t, and prepares for slower tests.
656+
* Returns 0 if initial tests rule it out, else 1.
657+
* FIXME: external code also wants to know if we have already shown
658+
* tau(n^e) == t; it currently checks taum[i].state == 0, but better
659+
* to expose this in the return value.
660+
*/
644661
bool tau_multi_prep(uint i) {
645662
t_tm *tm = &taum[i];
646663
uint t = tm->t;
@@ -1059,6 +1076,35 @@ uint tau_multi_run(uint count) {
10591076
exit(1);
10601077
}
10611078

1079+
/* Same as tau_multi_run() except that all values are required to be prime.
1080+
* It is the caller's responsibility to ensure the precondition is met.
1081+
*/
1082+
uint tau_prime_run(uint count) {
1083+
uint i = 0;
1084+
/* Shuffle the entries that did not complete by trial division to
1085+
* and order by size */
1086+
for (uint j = 0; j < count; ++j) {
1087+
if (taum[j].state == 0)
1088+
continue;
1089+
if (i < j) {
1090+
mpz_swap(taum[i].n, taum[j].n);
1091+
taum[i].vi = taum[j].vi;
1092+
}
1093+
++i;
1094+
}
1095+
if (i == 0)
1096+
return 0;
1097+
count = i;
1098+
qsort(taum, count, sizeof(t_tm), &taum_comparator);
1099+
for (i = 0; i < count; ++i) {
1100+
if (!_GMP_BPSW(taum[i].n)) {
1101+
taum[0].vi = taum[i].vi;
1102+
return count - i;
1103+
}
1104+
}
1105+
return 0;
1106+
}
1107+
10621108
bool tau_single_try(uint i) {
10631109
t_tm *tm = &taum[i];
10641110
for (uint i = TM_INIT; i < TM_MAX; ++i) {

coultau.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,5 +57,7 @@ extern int is_taux(mpz_t n, uint32_t k, uint32_t x);
5757
extern void alloc_taum(uint size);
5858
extern bool tau_multi_prep(uint i);
5959
extern uint tau_multi_run(uint i);
60+
extern bool tau_prime_prep(uint i);
61+
extern uint tau_prime_run(uint i);
6062

6163
#endif

0 commit comments

Comments
 (0)