algorithms.c: Add missing guard for `del' to property `set' functions.
[catacomb-python] / pgen.c
1 /* -*-c-*-
2 *
3 * Prime number generation
4 *
5 * (c) 2005 Straylight/Edgeware
6 */
7
8 /*----- Licensing notice --------------------------------------------------*
9 *
10 * This file is part of the Python interface to Catacomb.
11 *
12 * Catacomb/Python is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
16 *
17 * Catacomb/Python is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with Catacomb/Python; if not, write to the Free Software Foundation,
24 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25 */
26
27 /*----- Header files ------------------------------------------------------*/
28
29 #include "catacomb-python.h"
30
31 /*----- Filters -----------------------------------------------------------*/
32
33 PyTypeObject *pfilt_pytype;
34
35 static PyObject *pfilt_pywrap(pfilt *f)
36 {
37 pfilt_pyobj *o = 0;
38 o = PyObject_New(pfilt_pyobj, pfilt_pytype);
39 o->f = *f;
40 o->st = pfilt_step(f, 0);
41 return ((PyObject *)o);
42 }
43
44 static PyObject *pfilt_pymake(PyTypeObject *ty, PyObject *xobj)
45 {
46 mp *x = 0;
47 pfilt_pyobj *o = 0;
48
49 if (PFILT_PYCHECK(xobj)) RETURN_OBJ(xobj);
50 if ((x = getmp(xobj)) == 0) goto end;
51 o = (pfilt_pyobj *)ty->tp_alloc(ty, 0);
52 o->st = pfilt_create(&o->f, x);
53 end:
54 mp_drop(x);
55 return ((PyObject *)o);
56 }
57
58 static PyObject *pfilt_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
59 {
60 char *kwlist[] = { "x", 0 };
61 PyObject *xobj;
62
63 if (!PyArg_ParseTupleAndKeywords(arg, kw, "O:new", kwlist, &xobj))
64 return (0);
65 return (pfilt_pymake(ty, xobj));
66 }
67
68 static void pfilt_pydealloc(PyObject *me)
69 { pfilt_destroy(PFILT_F(me)); FREEOBJ(me); }
70
71 static PyObject *pfmeth_step(PyObject *me, PyObject *arg)
72 {
73 mpw x;
74
75 if (!PyArg_ParseTuple(arg, "O&:step", convmpw, &x)) return (0);
76 PFILT_ST(me) = pfilt_step(PFILT_F(me), x);
77 RETURN_ME;
78 }
79
80 static PyObject *pfmeth_muladd(PyObject *me, PyObject *arg)
81 {
82 mpw m, a;
83 pfilt_pyobj *o = 0;
84
85 if (!PyArg_ParseTuple(arg, "O&O&:muladd", convmpw, &m, convmpw, &a))
86 return (0);
87 o = PyObject_New(pfilt_pyobj, pfilt_pytype);
88 o->st = pfilt_muladd(&o->f, PFILT_F(me), m, a);
89 return ((PyObject *)o);
90 }
91
92 static CONVFUNC(pfilt, pfilt *, PFILT_F)
93
94 static PyObject *pfmeth_jump(PyObject *me, PyObject *arg)
95 {
96 pfilt *f;
97
98 if (!PyArg_ParseTuple(arg, "O&:jump", convpfilt, &f)) return (0);
99 PFILT_ST(me) = pfilt_jump(PFILT_F(me), f);
100 RETURN_ME;
101 }
102
103 static PyObject *meth__PrimeFilter_smallfactor(PyObject *me, PyObject *arg)
104 {
105 mp *x = 0;
106 PyObject *rc = 0;
107
108 if (!PyArg_ParseTuple(arg, "OO&:smallfactor", &me, convmp, &x)) goto end;
109 rc = PyInt_FromLong(pfilt_smallfactor(x));
110 end:
111 mp_drop(x);
112 return (rc);
113 }
114
115 static int pfilt_pynonzerop(PyObject *me)
116 { return (PFILT_ST(me) != PGEN_FAIL); }
117
118 static PyObject *pfilt_pyint(PyObject *me)
119 {
120 long l;
121 PyObject *rc = 0;
122
123 if (!mp_tolong_checked(PFILT_F(me)->m, &l, 0)) rc = PyInt_FromLong(l);
124 else rc = mp_topylong(PFILT_F(me)->m);
125 return (rc);
126 }
127
128 static PyObject *pfilt_pylong(PyObject *me)
129 { return (mp_topylong(PFILT_F(me)->m)); }
130
131 static PyObject *pfget_x(PyObject *me, void *hunoz)
132 { return (mp_pywrap(MP_COPY(PFILT_F(me)->m))); }
133
134 static PyObject *pfget_status(PyObject *me, void *hunoz)
135 { return (PyInt_FromLong(PFILT_ST(me))); }
136
137 static PyGetSetDef pfilt_pygetset[] = {
138 #define GETSETNAME(op, name) pf##op##_##name
139 GET (x, "F.x -> current position of filter")
140 GET (status, "F.status -> primality status of filter")
141 #undef GETSETNAME
142 { 0 }
143 };
144
145 static PyMethodDef pfilt_pymethods[] = {
146 #define METHNAME(name) pfmeth_##name
147 METH (step, "F.step(N)")
148 METH (muladd, "F.muladd(M, A)")
149 METH (jump, "F.jump(FF)")
150 #undef METHNAME
151 { 0 }
152 };
153
154 static PyNumberMethods pfilt_pynumber = {
155 0, /* @nb_add@ */
156 0, /* @nb_subtract@ */
157 0, /* @nb_multiply@ */
158 0, /* @nb_divide@ */
159 0, /* @nb_remainder@ */
160 0, /* @nb_divmod@ */
161 0, /* @nb_power@ */
162 0, /* @nb_negative@ */
163 0, /* @nb_positive@ */
164 0, /* @nb_absolute@ */
165 pfilt_pynonzerop, /* @nb_nonzero@ */
166 0, /* @nb_invert@ */
167 0, /* @nb_lshift@ */
168 0, /* @nb_rshift@ */
169 0, /* @nb_and@ */
170 0, /* @nb_xor@ */
171 0, /* @nb_or@ */
172 0, /* @nb_coerce@ */
173 pfilt_pyint, /* @nb_int@ */
174 pfilt_pylong, /* @nb_long@ */
175 0, /* @nb_float@ */
176 0, /* @nb_oct@ */
177 0, /* @nb_hex@ */
178
179 0, /* @nb_inplace_add@ */
180 0, /* @nb_inplace_subtract@ */
181 0, /* @nb_inplace_multiply@ */
182 0, /* @nb_inplace_divide@ */
183 0, /* @nb_inplace_remainder@ */
184 0, /* @nb_inplace_power@ */
185 0, /* @nb_inplace_lshift@ */
186 0, /* @nb_inplace_rshift@ */
187 0, /* @nb_inplace_and@ */
188 0, /* @nb_inplace_xor@ */
189 0, /* @nb_inplace_or@ */
190
191 0, /* @nb_floor_divide@ */
192 0, /* @nb_true_divide@ */
193 0, /* @nb_inplace_floor_divide@ */
194 0, /* @nb_inplace_true_divide@ */
195 };
196
197 static PyTypeObject pfilt_pytype_skel = {
198 PyObject_HEAD_INIT(0) 0, /* Header */
199 "PrimeFilter", /* @tp_name@ */
200 sizeof(pfilt_pyobj), /* @tp_basicsize@ */
201 0, /* @tp_itemsize@ */
202
203 pfilt_pydealloc, /* @tp_dealloc@ */
204 0, /* @tp_print@ */
205 0, /* @tp_getattr@ */
206 0, /* @tp_setattr@ */
207 0, /* @tp_compare@ */
208 0, /* @tp_repr@ */
209 &pfilt_pynumber, /* @tp_as_number@ */
210 0, /* @tp_as_sequence@ */
211 0, /* @tp_as_mapping@ */
212 0, /* @tp_hash@ */
213 0, /* @tp_call@ */
214 0, /* @tp_str@ */
215 0, /* @tp_getattro@ */
216 0, /* @tp_setattro@ */
217 0, /* @tp_as_buffer@ */
218 Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
219 Py_TPFLAGS_BASETYPE,
220
221 /* @tp_doc@ */
222 "Small-primes filter.",
223
224 0, /* @tp_traverse@ */
225 0, /* @tp_clear@ */
226 0, /* @tp_richcompare@ */
227 0, /* @tp_weaklistoffset@ */
228 0, /* @tp_iter@ */
229 0, /* @tp_iternext@ */
230 pfilt_pymethods, /* @tp_methods@ */
231 0, /* @tp_members@ */
232 pfilt_pygetset, /* @tp_getset@ */
233 0, /* @tp_base@ */
234 0, /* @tp_dict@ */
235 0, /* @tp_descr_get@ */
236 0, /* @tp_descr_set@ */
237 0, /* @tp_dictoffset@ */
238 0, /* @tp_init@ */
239 PyType_GenericAlloc, /* @tp_alloc@ */
240 pfilt_pynew, /* @tp_new@ */
241 0, /* @tp_free@ */
242 0 /* @tp_is_gc@ */
243 };
244
245 /*----- Rabin-Miller testing ----------------------------------------------*/
246
247 typedef struct rabin_pyobj {
248 PyObject_HEAD
249 rabin r;
250 } rabin_pyobj;
251
252 static PyTypeObject *rabin_pytype;
253 #define RABIN_R(o) (&((rabin_pyobj *)(o))->r)
254
255 static PyObject *rabin_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
256 {
257 mp *x = 0;
258 rabin_pyobj *o = 0;
259 char *kwlist[] = { "x", 0 };
260
261 if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&:new", kwlist, convmp, &x))
262 goto end;
263 if (!MP_POSP(x) || MP_EVENP(x)) VALERR("must be positive and odd");
264 o = (rabin_pyobj *)ty->tp_alloc(ty, 0);
265 rabin_create(&o->r, x);
266 end:
267 return ((PyObject *)o);
268 }
269
270 static void rabin_pydealloc(PyObject *me)
271 {
272 rabin_destroy(RABIN_R(me));
273 FREEOBJ(me);
274 }
275
276 static PyObject *rmeth_test(PyObject *me, PyObject *arg)
277 {
278 mp *w = 0;
279 PyObject *rc = 0;
280
281 if (!PyArg_ParseTuple(arg, "O&:test", convmp, &w)) goto end;
282 rc = PyInt_FromLong(rabin_test(RABIN_R(me), w));
283 end:
284 mp_drop(w);
285 return (rc);
286 }
287
288 static PyObject *rmeth_rtest(PyObject *me, PyObject *arg)
289 {
290 mp *w = 0;
291 PyObject *rc = 0;
292
293 if (!PyArg_ParseTuple(arg, "O&:rtest", convmp, &w)) goto end;
294 rc = PyInt_FromLong(rabin_rtest(RABIN_R(me), w));
295 end:
296 mp_drop(w);
297 return (rc);
298 }
299
300 static PyObject *rget_niters(PyObject *me, void *hunoz)
301 { return (PyInt_FromLong(rabin_iters(mp_bits(RABIN_R(me)->mm.m)))); }
302
303 static PyObject *rget_x(PyObject *me, void *hunoz)
304 { return (mp_pywrap(MP_COPY(RABIN_R(me)->mm.m))); }
305
306 static PyObject *meth__RabinMiller_iters(PyObject *me, PyObject *arg)
307 {
308 unsigned n;
309
310 if (!PyArg_ParseTuple(arg, "OO&:iters", &me, convuint, &n)) return (0);
311 return (PyInt_FromLong(rabin_iters(n)));
312 }
313
314 static PyGetSetDef rabin_pygetset[] = {
315 #define GETSETNAME(op, name) r##op##_##name
316 GET (x, "R.x -> number under test")
317 GET (niters, "R.niters -> suggested number of tests")
318 #undef GETSETNAME
319 { 0 }
320 };
321
322 static PyMethodDef rabin_pymethods[] = {
323 #define METHNAME(name) rmeth_##name
324 METH (test, "R.test(W) -> PGST")
325 METH (rtest, "R.rtest(W) -> PGST")
326 #undef METHNAME
327 { 0 }
328 };
329
330 static PyTypeObject rabin_pytype_skel = {
331 PyObject_HEAD_INIT(0) 0, /* Header */
332 "RabinMiller", /* @tp_name@ */
333 sizeof(rabin_pyobj), /* @tp_basicsize@ */
334 0, /* @tp_itemsize@ */
335
336 rabin_pydealloc, /* @tp_dealloc@ */
337 0, /* @tp_print@ */
338 0, /* @tp_getattr@ */
339 0, /* @tp_setattr@ */
340 0, /* @tp_compare@ */
341 0, /* @tp_repr@ */
342 0, /* @tp_as_number@ */
343 0, /* @tp_as_sequence@ */
344 0, /* @tp_as_mapping@ */
345 0, /* @tp_hash@ */
346 0, /* @tp_call@ */
347 0, /* @tp_str@ */
348 0, /* @tp_getattro@ */
349 0, /* @tp_setattro@ */
350 0, /* @tp_as_buffer@ */
351 Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
352 Py_TPFLAGS_BASETYPE,
353
354 /* @tp_doc@ */
355 "Rabin-Miller strong primality test.",
356
357 0, /* @tp_traverse@ */
358 0, /* @tp_clear@ */
359 0, /* @tp_richcompare@ */
360 0, /* @tp_weaklistoffset@ */
361 0, /* @tp_iter@ */
362 0, /* @tp_iternext@ */
363 rabin_pymethods, /* @tp_methods@ */
364 0, /* @tp_members@ */
365 rabin_pygetset, /* @tp_getset@ */
366 0, /* @tp_base@ */
367 0, /* @tp_dict@ */
368 0, /* @tp_descr_get@ */
369 0, /* @tp_descr_set@ */
370 0, /* @tp_dictoffset@ */
371 0, /* @tp_init@ */
372 PyType_GenericAlloc, /* @tp_alloc@ */
373 rabin_pynew, /* @tp_new@ */
374 0, /* @tp_free@ */
375 0 /* @tp_is_gc@ */
376 };
377
378 /*----- Events ------------------------------------------------------------*/
379
380 typedef struct pgevent_pyobj {
381 PyObject_HEAD
382 PyObject *r;
383 pgen_event *ev;
384 } pgevent_pyobj;
385
386 static PyTypeObject *pgevent_pytype;
387 #define PGEVENT_EV(o) (((pgevent_pyobj *)(o))->ev)
388
389 static PyObject *pgevent_pywrap(pgen_event *ev)
390 {
391 pgevent_pyobj *o = PyObject_New(pgevent_pyobj, pgevent_pytype);
392 o->ev = ev; o->r = 0;
393 return ((PyObject *)o);
394 }
395
396 static CONVFUNC(pgevent, pgen_event *, PGEVENT_EV)
397
398 static void pgevent_kill(PyObject *me)
399 {
400 pgevent_pyobj *ev = (pgevent_pyobj *)me;
401
402 ev->ev = 0;
403 if (ev->r) GRAND_R(ev->r) = 0;
404 }
405
406 static void pgevent_pydealloc(PyObject *me)
407 {
408 pgevent_pyobj *ev = (pgevent_pyobj *)me;
409 if (ev->r) Py_DECREF(ev->r);
410 FREEOBJ(me);
411 }
412
413 #define PGEVENT_CHECK(me) do { \
414 if (!PGEVENT_EV(me)) { \
415 PyErr_SetString(PyExc_ValueError, "event object is no longer valid"); \
416 return (0); \
417 } \
418 } while (0)
419
420 static PyObject *peget_name(PyObject *me, void *hunoz)
421 { PGEVENT_CHECK(me); return (PyString_FromString(PGEVENT_EV(me)->name)); }
422
423 static PyObject *peget_x(PyObject *me, void *hunoz)
424 { PGEVENT_CHECK(me); return (mp_pywrap(MP_COPY(PGEVENT_EV(me)->m))); }
425
426 static PyObject *peget_steps(PyObject *me, void *hunoz)
427 { PGEVENT_CHECK(me); return (PyInt_FromLong(PGEVENT_EV(me)->steps)); }
428
429 static PyObject *peget_tests(PyObject *me, void *hunoz)
430 { PGEVENT_CHECK(me); return (PyInt_FromLong(PGEVENT_EV(me)->tests)); }
431
432 static PyObject *peget_rng(PyObject *me, void *hunoz)
433 {
434 pgevent_pyobj *ev = (pgevent_pyobj *)me;
435
436 PGEVENT_CHECK(me);
437 if (!ev->r) ev->r = grand_pywrap(ev->ev->r, 0);
438 Py_INCREF(ev->r); return ((PyObject *)ev->r);
439 }
440
441 static int peset_x(PyObject *me, PyObject *xobj, void *hunoz)
442 {
443 mp *x = 0;
444 pgen_event *ev = PGEVENT_EV(me);
445 int rc = -1;
446 if (!xobj) NIERR("__del__");
447 PGEVENT_CHECK(me);
448 if ((x = getmp(xobj)) == 0) goto end;
449 mp_drop(ev->m);
450 ev->m = MP_COPY(x);
451 rc = 0;
452 end:
453 mp_drop(x);
454 return (rc);
455 }
456
457 static PyGetSetDef pgevent_pygetset[] = {
458 #define GETSETNAME(op, name) pe##op##_##name
459 GET (name, "EV.name -> value being generated")
460 GETSET(x, "EV.x -> value under test")
461 GET (steps, "EV.steps -> number of steps left")
462 GET (tests, "EV.tests -> tests before passing")
463 GET (rng, "EV.rng -> (noncrypto) random number generator")
464 #undef GETSETNAME
465 { 0 }
466 };
467
468 static PyTypeObject pgevent_pytype_skel = {
469 PyObject_HEAD_INIT(0) 0, /* Header */
470 "PrimeGenEvent", /* @tp_name@ */
471 sizeof(pgevent_pyobj), /* @tp_basicsize@ */
472 0, /* @tp_itemsize@ */
473
474 pgevent_pydealloc, /* @tp_dealloc@ */
475 0, /* @tp_print@ */
476 0, /* @tp_getattr@ */
477 0, /* @tp_setattr@ */
478 0, /* @tp_compare@ */
479 0, /* @tp_repr@ */
480 0, /* @tp_as_number@ */
481 0, /* @tp_as_sequence@ */
482 0, /* @tp_as_mapping@ */
483 0, /* @tp_hash@ */
484 0, /* @tp_call@ */
485 0, /* @tp_str@ */
486 0, /* @tp_getattro@ */
487 0, /* @tp_setattro@ */
488 0, /* @tp_as_buffer@ */
489 Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
490 Py_TPFLAGS_BASETYPE,
491
492 /* @tp_doc@ */
493 "Prime-generation event.",
494
495 0, /* @tp_traverse@ */
496 0, /* @tp_clear@ */
497 0, /* @tp_richcompare@ */
498 0, /* @tp_weaklistoffset@ */
499 0, /* @tp_iter@ */
500 0, /* @tp_iternext@ */
501 0, /* @tp_methods@ */
502 0, /* @tp_members@ */
503 pgevent_pygetset, /* @tp_getset@ */
504 0, /* @tp_base@ */
505 0, /* @tp_dict@ */
506 0, /* @tp_descr_get@ */
507 0, /* @tp_descr_set@ */
508 0, /* @tp_dictoffset@ */
509 0, /* @tp_init@ */
510 PyType_GenericAlloc, /* @tp_alloc@ */
511 abstract_pynew, /* @tp_new@ */
512 0, /* @tp_free@ */
513 0 /* @tp_is_gc@ */
514 };
515
516 /*----- Event handlers ----------------------------------------------------*/
517
518 PyTypeObject *pgev_pytype;
519
520 typedef struct pgstep_pyobj {
521 PGEV_HEAD
522 pgen_filterctx f;
523 } pgstep_pyobj;
524
525 static PyTypeObject *pgstep_pytype;
526 #define PGSTEP_STEP(o) (((pgstep_pyobj *)(o))->f.step)
527
528 typedef struct pgjump_pyobj {
529 PGEV_HEAD
530 PyObject *fobj;
531 pgen_jumpctx j;
532 } pgjump_pyobj;
533
534 static PyTypeObject *pgjump_pytype;
535 #define PGJUMP_FOBJ(o) (((pgjump_pyobj *)(o))->fobj)
536 #define PGJUMP_J(o) (&((pgjump_pyobj *)(o))->j)
537
538 typedef struct pgtest_pyobj {
539 PGEV_HEAD
540 rabin r;
541 } pgtest_pyobj;
542
543 static PyTypeObject *pgtest_pytype;
544
545 static int pgev_python(int rq, pgen_event *ev, void *p)
546 {
547 pypgev *pg = p;
548 PyObject *pyev = 0;
549 PyObject *rc = 0;
550 int st = PGEN_ABORT;
551 long l;
552 char *meth[] = {
553 "pg_abort", "pg_done", "pg_begin", "pg_try", "pg_fail", "pg_pass"
554 };
555
556 rq++;
557 if (rq > N(meth)) SYSERR("event code out of range");
558 pyev = pgevent_pywrap(ev);
559 if ((rc = PyObject_CallMethod(pg->obj, meth[rq], "(O)", pyev)) == 0)
560 goto end;
561 if (rc == Py_None)
562 st = PGEN_TRY;
563 else if ((l = PyInt_AsLong(rc)) == -1 && PyErr_Occurred())
564 goto end;
565 else if (l < PGEN_ABORT || l > PGEN_PASS)
566 VALERR("return code out of range");
567 else
568 st = l;
569 end:
570 if (PyErr_Occurred())
571 stash_exception(pg->exc, "exception from `pgen' handler");
572 if (pyev) {
573 pgevent_kill(pyev);
574 Py_DECREF(pyev);
575 }
576 Py_XDECREF(rc);
577 return (st);
578 }
579
580 static PyObject *pgev_pywrap(const pgev *pg)
581 {
582 pgev_pyobj *o;
583
584 o = PyObject_New(pgev_pyobj, pgev_pytype);
585 o->pg = *pg;
586 return ((PyObject *)o);
587 }
588
589 int convpgev(PyObject *o, void *p)
590 {
591 pypgev *pg = p;
592
593 if (PGEV_PYCHECK(o))
594 pg->ev = *PGEV_PG(o);
595 else {
596 pg->ev.proc = pgev_python;
597 pg->ev.ctx = pg;
598 pg->obj = o; Py_INCREF(o);
599 }
600 return (1);
601 }
602
603 void droppgev(pypgev *pg)
604 {
605 if (pg->ev.proc == pgev_python)
606 { assert(pg->ev.ctx == pg); Py_DECREF(pg->obj); }
607 }
608
609 static PyObject *pgmeth_common(PyObject *me, PyObject *arg, int rq)
610 {
611 pgen_event *ev;
612 pgev *pg = PGEV_PG(me);
613 PyObject *rc = 0;
614
615 if (!PyArg_ParseTuple(arg, "O&", convpgevent, &ev)) goto end;
616 rc = PyInt_FromLong(!pg->proc ? rq : pg->proc(rq, ev, pg->ctx));
617 end:
618 return (rc);
619 }
620
621 #define PGMETH(lc, uc) \
622 static PyObject *pgmeth_pg_##lc(PyObject *me, PyObject *arg) \
623 { return pgmeth_common(me, arg, PGEN_##uc); }
624 PGMETH(abort, ABORT)
625 PGMETH(done, DONE)
626 PGMETH(begin, BEGIN)
627 PGMETH(try, TRY)
628 PGMETH(pass, PASS)
629 PGMETH(fail, FAIL)
630 #undef PGMETH
631
632 static PyObject *pgev_stdev(pgen_proc *proc)
633 { pgev pg; pg.proc = proc; pg.ctx = 0; return (pgev_pywrap(&pg)); }
634
635 static PyMethodDef pgev_pymethods[] = {
636 #define METHNAME(name) pgmeth_##name
637 METH (pg_abort, "E.pg_abort(EV) -> PGRC -- prime generation aborted")
638 METH (pg_done, "E.pg_done(EV) -> PGRC -- prime generation finished")
639 METH (pg_begin, "E.pg_begin(EV) -> PGRC -- commence stepping/testing")
640 METH (pg_try, "E.pg_try(EV) -> PGRC -- found new candidate")
641 METH (pg_pass, "E.pg_pass(EV) -> PGRC -- passed primality test")
642 METH (pg_fail, "E.pg_fail(EV) -> PGRC -- failed primality test")
643 #undef METHNAME
644 { 0 }
645 };
646
647 static PyTypeObject pgev_pytype_skel = {
648 PyObject_HEAD_INIT(0) 0, /* Header */
649 "PrimeGenBuiltinHandler", /* @tp_name@ */
650 sizeof(pgev_pyobj), /* @tp_basicsize@ */
651 0, /* @tp_itemsize@ */
652
653 0, /* @tp_dealloc@ */
654 0, /* @tp_print@ */
655 0, /* @tp_getattr@ */
656 0, /* @tp_setattr@ */
657 0, /* @tp_compare@ */
658 0, /* @tp_repr@ */
659 0, /* @tp_as_number@ */
660 0, /* @tp_as_sequence@ */
661 0, /* @tp_as_mapping@ */
662 0, /* @tp_hash@ */
663 0, /* @tp_call@ */
664 0, /* @tp_str@ */
665 0, /* @tp_getattro@ */
666 0, /* @tp_setattro@ */
667 0, /* @tp_as_buffer@ */
668 Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
669 Py_TPFLAGS_BASETYPE,
670
671 /* @tp_doc@ */
672 "Built-in prime-generation event handler, base class.",
673
674 0, /* @tp_traverse@ */
675 0, /* @tp_clear@ */
676 0, /* @tp_richcompare@ */
677 0, /* @tp_weaklistoffset@ */
678 0, /* @tp_iter@ */
679 0, /* @tp_iternext@ */
680 pgev_pymethods, /* @tp_methods@ */
681 0, /* @tp_members@ */
682 0, /* @tp_getset@ */
683 0, /* @tp_base@ */
684 0, /* @tp_dict@ */
685 0, /* @tp_descr_get@ */
686 0, /* @tp_descr_set@ */
687 0, /* @tp_dictoffset@ */
688 0, /* @tp_init@ */
689 PyType_GenericAlloc, /* @tp_alloc@ */
690 abstract_pynew, /* @tp_new@ */
691 0, /* @tp_free@ */
692 0 /* @tp_is_gc@ */
693 };
694
695 static PyObject *pgstep_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
696 {
697 mpw s;
698 pgstep_pyobj *rc = 0;
699 char *kwlist[] = { "step", 0 };
700
701 if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&:new", kwlist, convmpw, &s))
702 goto end;
703 rc = (pgstep_pyobj *)ty->tp_alloc(ty, 0);
704 rc->f.step = s;
705 rc->pg.proc = pgen_filter;
706 rc->pg.ctx = &rc->f;
707 end:
708 return ((PyObject *)rc);
709 }
710
711 static PyObject *psget_step(PyObject *me, void *hunoz)
712 { return (PyInt_FromLong(PGSTEP_STEP(me))); }
713
714 static PyGetSetDef pgstep_pygetset[] = {
715 #define GETSETNAME(op, name) ps##op##_##name
716 GET (step, "S.step -> step size for the stepper")
717 #undef GETSETNAME
718 { 0 }
719 };
720
721 static PyTypeObject pgstep_pytype_skel = {
722 PyObject_HEAD_INIT(0) 0, /* Header */
723 "PrimeGenStepper", /* @tp_name@ */
724 sizeof(pgstep_pyobj), /* @tp_basicsize@ */
725 0, /* @tp_itemsize@ */
726
727 0, /* @tp_dealloc@ */
728 0, /* @tp_print@ */
729 0, /* @tp_getattr@ */
730 0, /* @tp_setattr@ */
731 0, /* @tp_compare@ */
732 0, /* @tp_repr@ */
733 0, /* @tp_as_number@ */
734 0, /* @tp_as_sequence@ */
735 0, /* @tp_as_mapping@ */
736 0, /* @tp_hash@ */
737 0, /* @tp_call@ */
738 0, /* @tp_str@ */
739 0, /* @tp_getattro@ */
740 0, /* @tp_setattro@ */
741 0, /* @tp_as_buffer@ */
742 Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
743 Py_TPFLAGS_BASETYPE,
744
745 /* @tp_doc@ */
746 "Simple prime-number stepper with small-factors filter.",
747
748 0, /* @tp_traverse@ */
749 0, /* @tp_clear@ */
750 0, /* @tp_richcompare@ */
751 0, /* @tp_weaklistoffset@ */
752 0, /* @tp_iter@ */
753 0, /* @tp_iternext@ */
754 0, /* @tp_methods@ */
755 0, /* @tp_members@ */
756 pgstep_pygetset, /* @tp_getset@ */
757 0, /* @tp_base@ */
758 0, /* @tp_dict@ */
759 0, /* @tp_descr_get@ */
760 0, /* @tp_descr_set@ */
761 0, /* @tp_dictoffset@ */
762 0, /* @tp_init@ */
763 PyType_GenericAlloc, /* @tp_alloc@ */
764 pgstep_pynew, /* @tp_new@ */
765 0, /* @tp_free@ */
766 0 /* @tp_is_gc@ */
767 };
768
769 static PyObject *pgjump_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
770 {
771 PyObject *o, *fobj;
772 pgjump_pyobj *rc = 0;
773 char *kwlist[] = { "jump", 0 };
774
775 if (!PyArg_ParseTupleAndKeywords(arg, kw, "O:new", kwlist, &o) ||
776 (fobj = pfilt_pymake(pfilt_pytype, o)) == 0)
777 goto end;
778 rc = (pgjump_pyobj *)ty->tp_alloc(ty, 0);
779 rc->fobj = fobj;
780 rc->j.j = PFILT_F(fobj);
781 rc->pg.proc = pgen_jump;
782 rc->pg.ctx = &rc->j;
783 end:
784 return ((PyObject *)rc);
785 }
786
787 static void pgjump_pydealloc(PyObject *me)
788 {
789 Py_DECREF(PGJUMP_FOBJ(me));
790 FREEOBJ(me);
791 }
792
793 static PyObject *pjget_jump(PyObject *me, void *hunoz)
794 { RETURN_OBJ(PGJUMP_FOBJ(me)); }
795
796 static PyGetSetDef pgjump_pygetset[] = {
797 #define GETSETNAME(op, name) pj##op##_##name
798 GET (jump, "S.jump -> jump size for the stepper")
799 #undef GETSETNAME
800 { 0 }
801 };
802
803 static PyTypeObject pgjump_pytype_skel = {
804 PyObject_HEAD_INIT(0) 0, /* Header */
805 "PrimeGenJumper", /* @tp_name@ */
806 sizeof(pgjump_pyobj), /* @tp_basicsize@ */
807 0, /* @tp_itemsize@ */
808
809 pgjump_pydealloc, /* @tp_dealloc@ */
810 0, /* @tp_print@ */
811 0, /* @tp_getattr@ */
812 0, /* @tp_setattr@ */
813 0, /* @tp_compare@ */
814 0, /* @tp_repr@ */
815 0, /* @tp_as_number@ */
816 0, /* @tp_as_sequence@ */
817 0, /* @tp_as_mapping@ */
818 0, /* @tp_hash@ */
819 0, /* @tp_call@ */
820 0, /* @tp_str@ */
821 0, /* @tp_getattro@ */
822 0, /* @tp_setattro@ */
823 0, /* @tp_as_buffer@ */
824 Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
825 Py_TPFLAGS_BASETYPE,
826
827 /* @tp_doc@ */
828 "Stepper for larger steps, with small-factors filter.",
829
830 0, /* @tp_traverse@ */
831 0, /* @tp_clear@ */
832 0, /* @tp_richcompare@ */
833 0, /* @tp_weaklistoffset@ */
834 0, /* @tp_iter@ */
835 0, /* @tp_iternext@ */
836 0, /* @tp_methods@ */
837 0, /* @tp_members@ */
838 pgjump_pygetset, /* @tp_getset@ */
839 0, /* @tp_base@ */
840 0, /* @tp_dict@ */
841 0, /* @tp_descr_get@ */
842 0, /* @tp_descr_set@ */
843 0, /* @tp_dictoffset@ */
844 0, /* @tp_init@ */
845 PyType_GenericAlloc, /* @tp_alloc@ */
846 pgjump_pynew, /* @tp_new@ */
847 0, /* @tp_free@ */
848 0 /* @tp_is_gc@ */
849 };
850
851 static PyObject *pgtest_pynew(PyTypeObject *ty, PyObject *arg, PyObject *kw)
852 {
853 pgtest_pyobj *rc = 0;
854 char *kwlist[] = { 0 };
855
856 if (!PyArg_ParseTupleAndKeywords(arg, kw, ":new", kwlist)) goto end;
857 rc = (pgtest_pyobj *)ty->tp_alloc(ty, 0);
858 rc->pg.proc = pgen_test;
859 rc->pg.ctx = &rc->r;
860 end:
861 return ((PyObject *)rc);
862 }
863
864 static PyTypeObject pgtest_pytype_skel = {
865 PyObject_HEAD_INIT(0) 0, /* Header */
866 "PrimeGenTester", /* @tp_name@ */
867 sizeof(pgtest_pyobj), /* @tp_basicsize@ */
868 0, /* @tp_itemsize@ */
869
870 0, /* @tp_dealloc@ */
871 0, /* @tp_print@ */
872 0, /* @tp_getattr@ */
873 0, /* @tp_setattr@ */
874 0, /* @tp_compare@ */
875 0, /* @tp_repr@ */
876 0, /* @tp_as_number@ */
877 0, /* @tp_as_sequence@ */
878 0, /* @tp_as_mapping@ */
879 0, /* @tp_hash@ */
880 0, /* @tp_call@ */
881 0, /* @tp_str@ */
882 0, /* @tp_getattro@ */
883 0, /* @tp_setattro@ */
884 0, /* @tp_as_buffer@ */
885 Py_TPFLAGS_DEFAULT | /* @tp_flags@ */
886 Py_TPFLAGS_BASETYPE,
887
888 /* @tp_doc@ */
889 "Rabin-Miller tester.",
890
891 0, /* @tp_traverse@ */
892 0, /* @tp_clear@ */
893 0, /* @tp_richcompare@ */
894 0, /* @tp_weaklistoffset@ */
895 0, /* @tp_iter@ */
896 0, /* @tp_iternext@ */
897 0, /* @tp_methods@ */
898 0, /* @tp_members@ */
899 0, /* @tp_getset@ */
900 0, /* @tp_base@ */
901 0, /* @tp_dict@ */
902 0, /* @tp_descr_get@ */
903 0, /* @tp_descr_set@ */
904 0, /* @tp_dictoffset@ */
905 0, /* @tp_init@ */
906 PyType_GenericAlloc, /* @tp_alloc@ */
907 pgtest_pynew, /* @tp_new@ */
908 0, /* @tp_free@ */
909 0 /* @tp_is_gc@ */
910 };
911
912 /*----- Prime generation functions ----------------------------------------*/
913
914 void pgenerr(struct excinfo *exc)
915 {
916 if (exc->ty) RESTORE_EXCINFO(exc);
917 else PyErr_SetString(PyExc_ValueError, "prime generation failed");
918 }
919
920 static PyObject *meth_pgen(PyObject *me, PyObject *arg, PyObject *kw)
921 {
922 mp *x = 0;
923 mp *r = 0;
924 PyObject *rc = 0;
925 char *p = "p";
926 pgen_filterctx fc = { 2 };
927 rabin tc;
928 struct excinfo exc = EXCINFO_INIT;
929 pypgev step = { { 0 } }, test = { { 0 } }, evt = { { 0 } };
930 unsigned nsteps = 0, ntests = 0;
931 char *kwlist[] = { "start", "name", "stepper", "tester", "event",
932 "nsteps", "ntests", 0 };
933
934 step.exc = &exc; step.ev.proc = pgen_filter; step.ev.ctx = &fc;
935 test.exc = &exc; test.ev.proc = pgen_test; test.ev.ctx = &tc;
936 evt.exc = &exc;
937 if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&|sO&O&O&O&O&:pgen", kwlist,
938 convmp, &x, &p, convpgev, &step,
939 convpgev, &test, convpgev, &evt,
940 convuint, &nsteps, convuint, &ntests))
941 goto end;
942 if (!ntests) ntests = rabin_iters(mp_bits(x));
943 if ((r = pgen(p, MP_NEW, x, evt.ev.proc, evt.ev.ctx,
944 nsteps, step.ev.proc, step.ev.ctx,
945 ntests, test.ev.proc, test.ev.ctx)) == 0)
946 PGENERR(&exc);
947 rc = mp_pywrap(r); r = 0;
948 end:
949 mp_drop(r); mp_drop(x);
950 droppgev(&step); droppgev(&test); droppgev(&evt);
951 return (rc);
952 }
953
954 static PyObject *meth_strongprime_setup(PyObject *me,
955 PyObject *arg, PyObject *kw)
956 {
957 mp *x = 0;
958 pfilt f;
959 grand *r = &rand_global;
960 unsigned nbits;
961 char *name = "p";
962 unsigned n = 0;
963 struct excinfo exc = EXCINFO_INIT;
964 pypgev evt = { { 0 } };
965 PyObject *rc = 0;
966 char *kwlist[] = { "nbits", "name", "event", "rng", "nsteps", 0 };
967
968 evt.exc = &exc;
969 if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&|sO&O&O&", kwlist,
970 convuint, &nbits, &name,
971 convpgev, &evt, convgrand, &r,
972 convuint, &n))
973 goto end;
974 if ((x = strongprime_setup(name, MP_NEW, &f, nbits,
975 r, n, evt.ev.proc, evt.ev.ctx)) == 0)
976 PGENERR(&exc);
977 rc = Py_BuildValue("(NN)", mp_pywrap(x), pfilt_pywrap(&f));
978 x = 0;
979 end:
980 mp_drop(x);
981 droppgev(&evt);
982 return (rc);
983 }
984
985 static PyObject *meth_strongprime(PyObject *me, PyObject *arg, PyObject *kw)
986 {
987 mp *x = 0;
988 grand *r = &rand_global;
989 unsigned nbits;
990 char *name = "p";
991 unsigned n = 0;
992 struct excinfo exc = EXCINFO_INIT;
993 pypgev evt = { { 0 } };
994 PyObject *rc = 0;
995 char *kwlist[] = { "nbits", "name", "event", "rng", "nsteps", 0 };
996
997 evt.exc = &exc;
998 if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&|sO&O&O&", kwlist,
999 convuint, &nbits, &name,
1000 convpgev, &evt, convgrand, &r,
1001 convuint, &n))
1002 goto end;
1003 if ((x = strongprime(name, MP_NEW, nbits,
1004 r, n, evt.ev.proc, evt.ev.ctx)) == 0)
1005 PGENERR(&exc);
1006 rc = mp_pywrap(x);
1007 x = 0;
1008 end:
1009 mp_drop(x);
1010 droppgev(&evt);
1011 return (rc);
1012 }
1013
1014 static PyObject *meth_limlee(PyObject *me, PyObject *arg, PyObject *kw)
1015 {
1016 char *p = "p";
1017 struct excinfo exc = EXCINFO_INIT;
1018 pypgev ie = { { 0 } }, oe = { { 0 } };
1019 unsigned ql, pl;
1020 grand *r = &rand_global;
1021 unsigned on = 0;
1022 size_t i, nf = 0;
1023 PyObject *rc = 0, *vec;
1024 char *kwlist[] = { "pbits", "qbits", "name", "event", "ievent",
1025 "rng", "nsteps", 0 };
1026 mp *x = 0, **v = 0;
1027
1028 ie.exc = oe.exc = &exc;
1029 if (!PyArg_ParseTupleAndKeywords(arg, kw, "O&O&|sO&O&O&O&:limlee", kwlist,
1030 convuint, &pl, convuint, &ql,
1031 &p, convpgev, &oe, convpgev, &ie,
1032 convgrand, &r, convuint, &on))
1033 goto end;
1034 if ((x = limlee(p, MP_NEW, MP_NEW, ql, pl, r, on,
1035 oe.ev.proc, oe.ev.ctx, ie.ev.proc, ie.ev.ctx,
1036 &nf, &v)) == 0)
1037 PGENERR(&exc);;
1038 vec = PyList_New(nf);
1039 for (i = 0; i < nf; i++)
1040 PyList_SetItem(vec, i, mp_pywrap(v[i]));
1041 xfree(v);
1042 rc = Py_BuildValue("(NN)", mp_pywrap(x), vec);
1043 end:
1044 droppgev(&oe); droppgev(&ie);
1045 return (rc);
1046 }
1047
1048 /*----- Global stuff ------------------------------------------------------*/
1049
1050 static PyMethodDef methods[] = {
1051 #define METHNAME(name) meth_##name
1052 METH (_PrimeFilter_smallfactor, "smallfactor(X) -> PGRC")
1053 METH (_RabinMiller_iters, "iters(NBITS) -> NITERS")
1054 KWMETH(pgen, "\
1055 pgen(START, [name = 'p'[, [stepper = PrimeGenStepper(2)],\n\
1056 [tester = PrimeGenTester()], [event = pgen_nullev],\n\
1057 [nsteps = 0], [ntests = RabinMiller.iters(START.nbits)]) -> P")
1058 KWMETH(strongprime_setup, "\
1059 strongprime_setup(NBITS, [name = 'p'], [event = pgen_nullev],\n\
1060 [rng = rand], [nsteps = 0]) -> (START, JUMP)")
1061 KWMETH(strongprime, "\
1062 strongprime(NBITS, [name = 'p'], [event = pgen_nullev],\n\
1063 [rng = rand], [nsteps = 0]) -> P")
1064 KWMETH(limlee, "\
1065 limlee(PBITS, QBITS, [name = 'p'], [event = pgen_nullev],\n\
1066 [ievent = pgen_nullev], [rng = rand], [nsteps = 0]) -> (P, [Q, ...])")
1067 #undef METHNAME
1068 { 0 }
1069 };
1070
1071 void pgen_pyinit(void)
1072 {
1073 INITTYPE(pfilt, root);
1074 INITTYPE(rabin, root);
1075 INITTYPE(pgevent, root);
1076 INITTYPE(pgev, root);
1077 INITTYPE(pgstep, pgev);
1078 INITTYPE(pgjump, pgev);
1079 INITTYPE(pgtest, pgev);
1080 addmethods(methods);
1081 }
1082
1083 static PyObject *obj;
1084
1085 void pgen_pyinsert(PyObject *mod)
1086 {
1087 INSERT("PrimeFilter", pfilt_pytype);
1088 INSERT("RabinMiller", rabin_pytype);
1089 INSERT("PrimeGenEvent", pgevent_pytype);
1090 INSERT("PrimeGenBuiltinHandler", pgev_pytype);
1091 INSERT("PrimeGenStepper", pgstep_pytype);
1092 INSERT("PrimeGenJumper", pgjump_pytype);
1093 INSERT("PrimeGenTester", pgtest_pytype);
1094 INSERT("pgen_nullev", obj = pgev_stdev(0));
1095 INSERT("pgen_stdev", pgev_stdev(pgen_ev));
1096 INSERT("pgen_spinev", pgev_stdev(pgen_evspin));
1097 INSERT("pgen_subev", pgev_stdev(pgen_subev));
1098 }
1099
1100 /*----- That's all, folks -------------------------------------------------*/