3 * $Id: pgen.c,v 1.5 2000/06/17 11:52:36 mdw Exp $
5 * Prime generation glue
7 * (c) 1999 Straylight/Edgeware
10 /*----- Licensing notice --------------------------------------------------*
12 * This file is part of Catacomb.
14 * Catacomb is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU Library General Public License as
16 * published by the Free Software Foundation; either version 2 of the
17 * License, or (at your option) any later version.
19 * Catacomb is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU Library General Public License for more details.
24 * You should have received a copy of the GNU Library General Public
25 * License along with Catacomb; if not, write to the Free
26 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
30 /*----- Revision history --------------------------------------------------*
33 * Revision 1.5 2000/06/17 11:52:36 mdw
34 * Signal a pgen abort if the jump and base share a common factor.
36 * Revision 1.4 1999/12/22 16:01:11 mdw
37 * Same file, completely different code. Main interface for new prime-
42 /*----- Header files ------------------------------------------------------*/
57 /*----- Standard prime filter ---------------------------------------------*/
59 /* --- @pgen_filter@ --- */
61 int pgen_filter(int rq, pgen_event *ev, void *p)
63 pgen_filterctx *f = p;
68 rc = pfilt_create(&f->f, ev->m);
73 if (!((f->step | f->f.m->v[0]) & 1))
74 rc = pfilt_step(&f->f, 1);
76 rc = pfilt_step(&f->f, f->step);
83 while (rc == PGEN_FAIL)
84 rc = pfilt_step(&f->f, f->step);
85 ev->m = MP_COPY(f->f.m);
89 /* --- @pgen_jump@ --- *
91 * Similar to the standard @pgen_filter@, but jumps in large steps rather
95 int pgen_jump(int rq, pgen_event *ev, void *p)
103 mp_gcd(&g, 0, 0, ev->m, f->j->m);
104 if (MP_CMP(g, >, MP_ONE)) {
109 rc = pfilt_create(&f->f, ev->m);
114 rc = pfilt_jump(&f->f, f->j);
117 pfilt_destroy(&f->f);
121 while (rc == PGEN_FAIL)
122 rc = pfilt_jump(&f->f, f->j);
123 ev->m = MP_COPY(f->f.m);
127 /*----- Standard prime test -----------------------------------------------*/
129 /* --- @pgen_test@ --- */
131 int pgen_test(int rq, pgen_event *ev, void *p)
138 rabin_create(r, ev->m);
142 mp *a = mprand_range(MP_NEW, ev->m, ev->r, 0);
143 rc = rabin_test(r, a);
155 /*----- The main driver ---------------------------------------------------*/
159 * Arguments: @const char *name@ = name of the value being searched for
160 * @mp *d@ = destination for the result integer
161 * @mp *m@ = start value to pass to stepper
162 * @pgen_proc *event@ = event handler function
163 * @void *ectx@ = context argument for event andler
164 * @unsigned steps@ = number of steps to take in search
165 * @pgen_proc *step@ = stepper function to use
166 * @void *sctx@ = context argument for stepper
167 * @unsigned tests@ = number of tests to make
168 * @pgen_proc *test@ = tester function to use
169 * @void *tctx@ = context argument for tester
171 * Returns: Pointer to final result, or null.
173 * Use: A generalized prime-number search skeleton. Yes, that's a
174 * scary number of arguments.
177 mp *pgen(const char *name, mp *d, mp *m, pgen_proc *event, void *ectx,
178 unsigned steps, pgen_proc *step, void *sctx,
179 unsigned tests, pgen_proc *test, void *tctx)
186 /* --- Set up the initial event block --- */
195 ev.r = fibrand_create(0);
197 /* --- Tell the event handler we're under way --- */
199 if (event && event(PGEN_BEGIN, &ev, ectx) == PGEN_ABORT)
202 /* --- Set up for the initial call --- */
204 proc = step; ctx = sctx; rq = PGEN_BEGIN;
206 /* --- Enter the great maelstrom of state transitions --- */
220 /* --- Call the procedure and decide what to do next --- */
222 rc = proc(rq, &ev, ctx);
229 proc = test; ctx = tctx;
234 act |= A_TEST | A_EVENT;
238 proc = test; ctx = tctx;
245 act |= A_ENDTEST | A_EVENT;
246 proc = step; ctx = sctx;
251 act |= A_EVENT | A_DONE | A_ENDSTEP;
256 act |= A_EVENT | A_DONE;
257 if (proc == test || rq == PGEN_TRY)
259 if (proc == test && rq == PGEN_BEGIN)
263 assert(((void)"Invalid response from function", 0));
267 /* --- If decrementing counters is requested, do that --- */
269 if ((act & A_STEP) && steps) {
272 act |= A_EVENT | A_ENDSTEP | A_DONE;
278 if ((act & A_TEST) && tests) {
281 act |= A_ENDTEST | A_ENDSTEP | A_DONE;
286 /* --- Report an event if so directed --- */
288 if ((act & A_EVENT) && event && event(rc, &ev, ectx) == PGEN_ABORT) {
290 if (!(act & A_DONE)) {
291 act |= A_ENDSTEP | A_DONE;
297 /* --- Close down tester and stepper functions --- */
300 test(PGEN_DONE, &ev, tctx);
302 step(PGEN_DONE, &ev, sctx);
304 /* --- Stop the entire test if necessary --- */
310 /* --- Tidy up and return --- */
312 if (rc == PGEN_ABORT) {
316 ev.r->ops->destroy(ev.r);
323 /*----- Test rig ----------------------------------------------------------*/
327 #include <mLib/testrig.h>
329 static int verify(dstr *v)
331 mp *m = *(mp **)v[0].buf;
332 mp *q = *(mp **)v[1].buf;
340 p = pgen("p", MP_NEW, m, pgen_evspin, 0, 0, pgen_filter, &pf,
341 rabin_iters(mp_bits(m)), pgen_test, &r);
342 if (!p || MP_CMP(p, !=, q)) {
343 fputs("\n*** pgen failed", stderr);
344 fputs("\nm = ", stderr); mp_writefile(m, stderr, 10);
345 fputs("\np = ", stderr); mp_writefile(p, stderr, 10);
346 fputs("\nq = ", stderr); mp_writefile(q, stderr, 10);
355 assert(mparena_count(MPARENA_GLOBAL) == 0);
359 static test_chunk tests[] = {
360 { "pgen", verify, { &type_mp, &type_mp, 0 } },
364 int main(int argc, char *argv[])
367 test_run(argc, argv, tests, SRCDIR "/tests/pgen");
372 /*----- That's all, folks -------------------------------------------------*/