Initial git import
[sxemacs] / modules / ase / ase-resclass.c
1 /*** ase-resclass.c -- Residue Class Rings for SXEmacs
2  *
3  * Copyright (C) 2006 - 2008 Sebastian Freundt
4  *
5  * Author:  Sebastian Freundt <hroptatyr@sxemacs.org>
6  *
7  * This file is part of SXEmacs.
8  * 
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  *
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  *
20  * 3. Neither the name of the author nor the names of any contributors
21  *    may be used to endorse or promote products derived from this
22  *    software without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR
25  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
26  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27  * DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
29  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
30  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
31  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
32  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
33  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
34  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35  *
36  ***/
37
38 /* Synched up with: Not in FSF. */
39
40 #include "config.h"
41 #include "sxemacs.h"
42 #include "ent/ent.h"
43 #include "ase-resclass.h"
44
45 #define EMOD_ASE_DEBUG_RESC(args...)    EMOD_ASE_DEBUG("[RESC]: " args)
46
47 PROVIDE(ase_resclass);
48 REQUIRE(ase_resclass, "ase");
49
50 Lisp_Object Qase_resclass;
51 Lisp_Object Qase_resc_rng, Qase_resc_rng_p, Qase_resc_elm, Qase_resc_elm_p;
52 static int sane_small;
53
54 #if 0
55 static ase_nullary_operation_f Qase_resclass_zero, Qase_resclass_one;
56 #endif
57
58 \f
59 static inline int
60 _resc_rng_buffer_size(ase_resc_rng_t a)
61 {
62         /* returns a sane size for buffer allocation */
63 #if defined HAVE_MPZ && (defined WITH_GMP || defined WITH_MP)
64         if (ase_resc_rng_smallp(a))
65                 return sane_small;
66         else
67                 return (mpz_sizeinbase(ase_resc_rng_ring(a), 10) + 7) & -3;
68 #else
69         return sane_small;
70 #endif
71 }
72
73 static inline void
74 _ase_resc_rng_to_string(char *buf, int len, ase_resc_rng_t a)
75 {
76         if (ase_resc_rng_smallp(a))
77                 snprintf(buf, len, "%ld", a->small_ring);
78         else
79                 resc_rng_to_string(buf, len, ase_resc_rng_ring(a));
80         return;
81 }
82
83 void
84 _ase_resc_rng_prnt(ase_resc_rng_t a, Lisp_Object pcf)
85 {
86         int sane_sz = sizeof(char)*_resc_rng_buffer_size(a);
87         char *fstr = alloca(sane_sz);
88         _ase_resc_rng_to_string(fstr, sane_sz, a);
89         write_c_string("Z/", pcf);
90         write_c_string(fstr, pcf);
91         write_c_string("Z", pcf);
92         return;
93 }
94
95 static void
96 ase_resc_rng_prnt(Lisp_Object obj, Lisp_Object pcf, int unused)
97 {
98         EMOD_ASE_DEBUG_RESC("i:0x%016lx@0x%016lx (rc:%d)\n",
99                             (long unsigned int)(XASE_RESC_RNG(obj)),
100                             (long unsigned int)obj, 1);
101         write_c_string("#<", pcf);
102         print_internal(XDYNACAT_TYPE(obj), pcf, unused);
103         write_c_string(" ", pcf);
104         _ase_resc_rng_prnt(XASE_RESC_RNG(obj), pcf);
105         if (XASE_RESC_RNG_SMALLP(obj))
106                 write_c_string(", small", pcf);
107         write_c_string(">", pcf);
108 }
109
110 static inline int
111 _resc_elm_buffer_size(ase_resc_elm_t a)
112 {
113         /* returns a sane size for buffer allocation */
114 #if defined HAVE_MPZ && (defined WITH_GMP || defined WITH_MP)
115         if (ase_resc_rng_smallp(a))
116                 return sane_small;
117         else
118                 return (mpz_sizeinbase(ase_resc_elm_data(a), 10) + 7) & -3;
119 #else
120         return sane_small;
121 #endif
122 }
123
124 static inline void
125 _ase_resc_elm_to_string(char *buf, int len, ase_resc_elm_t a)
126 {
127         if (ase_resc_elm_smallp(a))
128                 snprintf(buf, len, "%ld", a->small_data);
129         else
130                 resc_elm_to_string(buf, len, ase_resc_elm_data(a));
131         return;
132 }
133
134 void
135 _ase_resc_elm_prnt(ase_resc_elm_t a, Lisp_Object pcf)
136 {
137         int sane_sz_rng = sizeof(char)*_resc_rng_buffer_size(
138                 XASE_RESC_RNG(ase_resc_elm_ring(a)));
139         int sane_sz_elm = sizeof(char)*_resc_elm_buffer_size(a);
140         char *rng_str = alloca(sane_sz_rng);
141         char *elm_str = alloca(sane_sz_elm);
142
143         _ase_resc_rng_to_string(rng_str, sane_sz_rng,
144                                 XASE_RESC_RNG(ase_resc_elm_ring(a)));
145         _ase_resc_elm_to_string(elm_str, sane_sz_elm, a);
146
147         write_c_string(elm_str, pcf);
148         write_c_string("+", pcf);
149         write_c_string(rng_str, pcf);
150         write_c_string("Z", pcf);
151         return;
152 }
153
154 static void
155 ase_resc_elm_prnt(Lisp_Object obj, Lisp_Object pcf, int unused)
156 {
157         EMOD_ASE_DEBUG_RESC("i:0x%016lx@0x%016lx (rc:%d)\n",
158                             (long unsigned int)(XASE_RESC_ELM(obj)),
159                             (long unsigned int)obj, 1);
160         write_c_string("#<", pcf);
161         print_internal(XDYNACAT_TYPE(obj), pcf, unused);
162         write_c_string(" ", pcf);
163         _ase_resc_elm_prnt(XASE_RESC_ELM(obj), pcf);
164         if (XASE_RESC_ELM_SMALLP(obj))
165                 write_c_string(", small", pcf);
166         write_c_string(">", pcf);
167 }
168
169 /* stuff for the dynacat, markers */
170 static inline void
171 _ase_resc_rng_mark(ase_resc_rng_t a)
172 {
173         if (a == NULL)
174                 return;
175         return;
176 }
177
178 static void
179 ase_resc_rng_mark(Lisp_Object obj)
180 {
181         EMOD_ASE_DEBUG_RESC("i:0x%016lx@0x%016lx (rc:%d) shall be marked...\n",
182                             (long unsigned int)(XASE_RESC_RNG(obj)),
183                             (long unsigned int)obj, 1);
184         _ase_resc_rng_mark(XASE_RESC_RNG(obj));
185         return;
186 }
187
188 static inline void
189 _ase_resc_elm_mark(ase_resc_elm_t a)
190 {
191         mark_object(ase_resc_elm_ring(a));
192 }
193
194 static void
195 ase_resc_elm_mark(Lisp_Object obj)
196 {
197         EMOD_ASE_DEBUG_RESC("i:0x%016lx@0x%016lx (rc:%d) shall be marked...\n",
198                             (long unsigned int)(XASE_RESC_ELM(obj)),
199                             (long unsigned int)obj, 1);
200         _ase_resc_elm_mark(XASE_RESC_ELM(obj));
201         return;
202 }
203
204 /* stuff for the dynacat, finalisers */
205 static inline void
206 _ase_resc_rng_fini(ase_resc_rng_t a)
207 {
208         if (!ase_resc_rng_smallp(a))
209                 resc_rng_fini(ase_resc_rng_ring(a));
210         return;
211 }
212
213 static void
214 ase_resc_rng_fini(Lisp_Object obj, int unused)
215 {
216         ase_resc_rng_t a = XASE_RESC_RNG(obj);
217
218         EMOD_ASE_DEBUG_GC("i:0x%016lx@0x%016lx (rc:%d) shall be freed...\n",
219                           (long unsigned int)(a), obj, 1);
220
221         _ase_resc_rng_fini(a);
222         xfree(a);
223         return;
224 }
225
226 static inline void
227 _ase_resc_elm_fini(ase_resc_elm_t a)
228 {
229         if (!ase_resc_elm_smallp(a))
230                 resc_elm_fini(ase_resc_elm_data(a));
231         return;
232 }
233
234 static void
235 ase_resc_elm_fini(Lisp_Object obj, int unused)
236 {
237         ase_resc_elm_t a = XASE_RESC_ELM(obj);
238
239         EMOD_ASE_DEBUG_GC("i:0x%016lx@0x%016lx (rc:%d) shall be freed...\n",
240                           (long unsigned int)(a), obj, 1);
241
242         _ase_resc_elm_fini(a);
243         xfree(a);
244         return;
245 }
246
247 \f
248 static inline Lisp_Object
249 _ase_wrap_resc_rng(ase_resc_rng_t a)
250 {
251         Lisp_Object result;
252
253         result = make_dynacat(a);
254         XDYNACAT(result)->type = Qase_resc_rng;
255
256 #if 0
257         if (a)
258                 ase_interval_incref(a);
259 #endif
260
261         set_dynacat_printer(result, ase_resc_rng_prnt);
262         set_dynacat_marker(result, ase_resc_rng_mark);
263         set_dynacat_finaliser(result, ase_resc_rng_fini);
264         set_dynacat_intprinter(
265                 result, (dynacat_intprinter_f)_ase_resc_rng_prnt);
266
267         EMOD_ASE_DEBUG_RESC("i:0x%016lx (rc:%d) "
268                             "shall be wrapped to 0x%016lx...\n",
269                             (long unsigned int)a, 1,
270                             (long unsigned int)result);
271
272         return result;
273 }
274
275 ase_resc_rng_t
276 _ase_make_resc_rng(Lisp_Object modulus)
277 {
278         ase_resc_rng_t a = xnew(struct ase_resc_rng_s);
279
280         if (INTP(modulus)) {
281                 a->smallp = 1;
282                 a->small_ring = XINT(modulus);
283 #if defined HAVE_MPZ && (defined WITH_GMP || defined WITH_MP)
284         } else if (BIGZP(modulus)) {
285                 a->smallp = 0;
286                 resc_rng_init(ase_resc_rng_ring(a));
287                 resc_rng_set_bigz(ase_resc_rng_ring(a), XBIGZ_DATA(modulus));
288 #endif
289         }
290
291         EMOD_ASE_DEBUG_RESC("i:0x%016lx (rc:0) shall be created...\n",
292                             (long unsigned int)a);
293         return a;
294 }
295
296 /* specialised versions for the lisp reader */
297 static inline ase_resc_rng_t
298 __ase_make_resc_rng_eint(EMACS_INT modulus)
299 {
300         ase_resc_rng_t a = xnew(struct ase_resc_rng_s);
301
302         a->smallp = 1;
303         a->small_ring = modulus;
304         EMOD_ASE_DEBUG_RESC("i:0x%016lx (rc:0) shall be created...\n",
305                             (long unsigned int)a);
306         return a;
307 }
308 #if defined HAVE_MPZ && (defined WITH_GMP || defined WITH_MP)
309 static inline ase_resc_rng_t
310 __ase_make_resc_rng_bigz(resc_rng modulus)
311 {
312         ase_resc_rng_t a = xnew(struct ase_resc_rng_s);
313
314         a->smallp = 0;
315         *a->ring = *modulus;
316         EMOD_ASE_DEBUG_RESC("i:0x%016lx (rc:0) shall be created...\n",
317                             (long unsigned int)a);
318         return a;
319 }
320 #endif
321
322 Lisp_Object
323 ase_make_resc_rng(Lisp_Object modulus)
324 {
325         ase_resc_rng_t a = NULL;
326         Lisp_Object result = Qnil;
327
328         a = _ase_make_resc_rng(modulus);
329         XSETASE_RESC_RNG(result, a);
330
331         return result;
332 }
333
334 Lisp_Object
335 _ase_wrap_resc_elm(ase_resc_elm_t a)
336 {
337         Lisp_Object result;
338
339         result = make_dynacat(a);
340         XDYNACAT(result)->type = Qase_resc_elm;
341
342 #if 0
343         if (a)
344                 ase_interval_incref(a);
345 #endif
346
347         set_dynacat_printer(result, ase_resc_elm_prnt);
348         set_dynacat_marker(result, ase_resc_elm_mark);
349         set_dynacat_finaliser(result, ase_resc_elm_fini);
350         set_dynacat_intprinter(
351                 result, (dynacat_intprinter_f)_ase_resc_elm_prnt);
352
353         EMOD_ASE_DEBUG_RESC("i:0x%016lx (rc:%d) "
354                             "shall be wrapped to 0x%016lx...\n",
355                             (long unsigned int)a, 1,
356                             (long unsigned int)result);
357
358         return result;
359 }
360
361 static inline void
362 _ase_resc_elm_canonicalise_small(ase_resc_elm_t a)
363 {
364         if ((a->small_data = a->small_data %
365              XASE_RESC_RNG(ase_resc_elm_ring(a))->small_ring) < 0)
366                 a->small_data +=
367                         XASE_RESC_RNG(ase_resc_elm_ring(a))->small_ring;
368 }
369
370 #if defined HAVE_MPZ && (defined WITH_GMP || defined WITH_MP)
371 static void
372 _ase_resc_elm_canonicalise_big(ase_resc_elm_t a)
373 {
374         bigz_mod(ase_resc_elm_data(a), ase_resc_elm_data(a),
375                  XASE_RESC_RNG_RING(ase_resc_elm_ring(a)));
376 }
377 #endif
378
379 static inline void
380 _ase_resc_elm_canonicalise(ase_resc_elm_t a)
381 {
382 #if defined HAVE_MPZ && (defined WITH_GMP || defined WITH_MP)
383         if (LIKELY(ase_resc_elm_smallp(a))) {
384                 _ase_resc_elm_canonicalise_small(a);
385         } else {
386                 _ase_resc_elm_canonicalise_big(a);
387         }
388 #else
389         ase_resc_elm_sdata(a) =
390                 ase_resc_elm_sdata(a) %
391                 XASE_RESC_RNG_SRING(ase_resc_elm_ring(a));
392 #endif
393         return;
394 }
395
396 ase_resc_elm_t
397 _ase_make_resc_elm(Lisp_Object class, Lisp_Object ring)
398 {
399         ase_resc_elm_t a = xnew(struct ase_resc_elm_s);
400
401         ase_resc_elm_ring(a) = ring;
402
403         if (!(a->smallp = XASE_RESC_RNG(ring)->smallp)) {
404                 resc_elm_init(ase_resc_elm_data(a));
405         }
406
407         EMOD_ASE_DEBUG_RESC("i:0x%016lx (rc:0) shall be created...\n",
408                             (long unsigned int)a);
409
410         if (INTP(class) && a->smallp) {
411                 a->small_data = XINT(class);
412         } else if (INTP(class)) {
413                 resc_elm_set_eint(ase_resc_elm_data(a), XINT(class));
414 #if defined HAVE_MPZ && (defined WITH_GMP || defined WITH_MP)
415         } else if (BIGZP(class) && a->smallp) {
416                 Lisp_Object newcl = _ent_binop(
417                         ASE_BINARY_OP_MOD,
418                         BIGZ_T, class,
419                         INT_T, make_int(XASE_RESC_RNG(ring)->small_ring));
420                 a->small_data = XINT(newcl);
421                 return a;
422         } else if (BIGZP(class)) {
423                 resc_elm_set_bigz(ase_resc_elm_data(a),
424                                   XBIGZ_DATA(class));
425 #endif
426         }
427
428         _ase_resc_elm_canonicalise(a);
429         return a;
430 }
431
432 /* specialised versions for the lisp reader */
433 static ase_resc_elm_t
434 __ase_make_resc_elm_eint(EMACS_INT class)
435 {
436         ase_resc_elm_t a = xnew(struct ase_resc_elm_s);
437
438         a->smallp = 1;
439         a->small_data = class;
440         EMOD_ASE_DEBUG_RESC("i:%p (rc:0) shall be created...\n", a);
441         return a;
442 }
443 #if defined HAVE_MPZ && (defined WITH_GMP || defined WITH_MP)
444 static ase_resc_elm_t
445 __ase_make_resc_elm_bigz(resc_elm class)
446 {
447         ase_resc_elm_t a = xnew(struct ase_resc_elm_s);
448
449         a->smallp = 0;
450         *a->data = *class;
451         EMOD_ASE_DEBUG_RESC("i:%p (rc:0) shall be created...\n", a);
452         return a;
453 }
454 #endif
455
456 Lisp_Object
457 ase_make_resc_elm(Lisp_Object class, Lisp_Object ring)
458 {
459         ase_resc_elm_t a = NULL;
460         Lisp_Object result = Qnil;
461
462         a = _ase_make_resc_elm(class, ring);
463         XSETASE_RESC_ELM(result, a);
464
465         return result;
466 }
467
468 \f
469 /* basic functions */
470 /* read a resclass off the wire */
471 /* the next 4 funs are hooked in the lisp reader (lread.c) */
472 static Lisp_Object
473 ase_resc_rng_from_string(char *cp)
474 {
475         ase_resc_rng_t r = NULL;
476         char *start, *tail;
477         char tmp;
478         EMACS_INT small_ring;
479
480         /* Jump over Z */
481         cp++;
482         /* Jump over / */
483         cp++;
484
485         start = cp;
486
487         while ((*cp >= '0' && *cp <= '9'))
488                 cp++;
489
490         /* MPZ cannot read numbers with characters after them.
491          * See limitations of GMP-MPZ strings
492          */
493         tmp = (Bufbyte)*cp;
494         *cp = '\0';
495         errno = 0;
496         small_ring = strtol(start, &tail, 10);
497         if (errno == 0) {
498                 r = __ase_make_resc_rng_eint(small_ring);
499 #if defined HAVE_MPZ && (defined WITH_GMP || defined WITH_MP)
500         } else if (errno == ERANGE) {
501                 resc_rng ring;
502                 resc_rng_init(ring);
503                 resc_rng_set_string(ring, start);
504                 r = __ase_make_resc_rng_bigz(ring);
505 #endif
506         } else {
507                 /* panic */
508         }
509         *cp = tmp;
510
511         /* generate and return the ring */
512         return _ase_wrap_resc_rng(r);
513 }
514
515 static Lisp_Object
516 ase_resc_elm_from_string(char *cp)
517 {
518         ase_resc_elm_t e = NULL;
519         ase_resc_rng_t r = NULL;
520         char *start, *tail;
521         char tmp;
522         EMACS_INT small_ring;
523         EMACS_INT small_elm;
524
525         /* MPZ bigz_set_string has no effect
526          * with initial + sign */
527         if (*cp == '+')
528                 cp++;
529
530         start = cp;
531
532         if (*cp == '-') {
533                 /* jump over a leading minus */
534                 cp++;
535         }
536                 
537         while ((*cp >= '0' && *cp <= '9'))
538                 cp++;
539
540         /* MPZ cannot read numbers with characters after them.
541          * See limitations of GMP-MPZ strings
542          */
543         tmp = *cp;
544         *cp = '\0';
545         errno = 0;
546         small_elm = strtol(start, &tail, 10);
547         if (errno == 0) {
548                 e = __ase_make_resc_elm_eint(small_elm);
549 #if defined HAVE_MPZ && (defined WITH_GMP || defined WITH_MP)
550         } else if (errno == ERANGE) {
551                 resc_elm elm;
552                 resc_elm_init(elm);
553                 resc_elm_set_string(elm, start);
554                 e = __ase_make_resc_elm_bigz(elm);
555 #endif
556         } else {
557                 /* panic */
558         }
559         *cp = tmp;
560
561         /* read the modulus */
562         if (*cp == '+')
563                 cp++;
564         start = cp;
565         while ((*cp >= '0' && *cp <= '9'))
566                 cp++;
567         tmp = *cp;
568         *cp = '\0';
569         errno = 0;
570         small_ring = strtol(start, &tail, 10);
571         if (errno == 0) {
572                 r = __ase_make_resc_rng_eint(small_ring);
573 #if defined HAVE_MPZ && (defined WITH_GMP || defined WITH_MP)
574         } else if (errno == ERANGE) {
575                 resc_rng ring;
576                 resc_rng_init(ring);
577                 resc_rng_set_string(ring, start);
578                 r = __ase_make_resc_rng_bigz(ring);
579 #endif
580         } else {
581                 /* panic */
582         }
583         *cp = tmp;
584
585         /* now we have 4 possibilites: */
586         if (e->smallp && r->smallp) {
587                 e->ring = _ase_wrap_resc_rng(r);
588                 _ase_resc_elm_canonicalise_small(e);
589                 return _ase_wrap_resc_elm(e);
590 #if defined HAVE_MPZ && (defined WITH_GMP || defined WITH_MP)
591         } else if (e->smallp) {
592                 /* the class is small, the ring is not,
593                  * thus we have to promote the class now */
594                 resc_elm_init(ase_resc_elm_data(e));
595                 resc_elm_set_eint(ase_resc_elm_data(e), e->small_data);
596                 e->smallp = 0;
597                 e->ring = _ase_wrap_resc_rng(r);
598                 _ase_resc_elm_canonicalise_big(e);
599                 return _ase_wrap_resc_elm(e);
600         } else if (r->smallp) {
601                 /* we're in deep shit, the class is bigz, the ring is small
602                  * and to make it worse, we can't use the ENT mod table */
603                 bigz_set_long(ent_scratch_bigz, r->small_ring);
604                 bigz_mod(ent_scratch_bigz,
605                          ase_resc_elm_data(e), ent_scratch_bigz);
606                 /* now ent_scratch_bigz should fit into a long */
607                 e->small_data = bigz_to_long(ent_scratch_bigz);
608                 e->smallp = 1;
609                 /* finish the temporarily assigned big data slot */
610                 resc_elm_fini(ase_resc_elm_data(e));
611                 e->ring = _ase_wrap_resc_rng(r);
612                 /* no need to canonicalise */
613                 return _ase_wrap_resc_elm(e);
614         } else {
615                 /* phew, finally an easy case */
616                 e->ring = _ase_wrap_resc_rng(r);
617                 _ase_resc_elm_canonicalise_big(e);
618                 return _ase_wrap_resc_elm(e);
619 #endif
620         }
621         return Qnil;
622 }
623
624 #define LEAD_INT 1
625 #define DOT_CHAR 2
626 #define TRAIL_INT 4
627 #define E_CHAR 8
628 #define EXP_INT 16
629 /* for complex numbers */
630 #define INTERMEDIATE_UNARY_SYMBOL 32
631 #define LEAD_INT2 64
632 #define DOT_CHAR2 128
633 #define TRAIL_INT2 256
634 #define E_CHAR2 512
635 #define EXP_INT2 1024
636 #define I_CHAR 2048
637 #define LEAD_Z 2
638 #define Z_CHAR 4096
639
640 static int
641 ase_resc_rng_string_p(const char *cp)
642 {
643         int state;
644         const Bufbyte *ucp = (const Bufbyte *)cp;
645
646
647         /* parse the residue class */
648         state = 0;
649         if (*ucp++ == 'Z' && *ucp++ == '/')
650                 state |= LEAD_Z;
651
652         /* check if we had a int number until here */
653         if (!(state == (LEAD_Z)))
654                 return 0;
655
656         /* now look for the modulus */
657         state = 0;
658         if (*ucp >= '1' && *ucp <= '9') {
659                 state |= LEAD_INT2;
660                 while (*ucp >= '0' && *ucp <= '9')
661                         ucp++;
662         }
663         if (*ucp == 'Z') {
664                 state |= Z_CHAR;
665                 ucp++;
666         }
667         return (((*ucp == 0) || (*ucp == ' ') || (*ucp == '\t') ||
668                  (*ucp == '\n') || (*ucp == '\r') || (*ucp == '\f')) &&
669                 (state == (LEAD_INT2 | Z_CHAR)));
670 }
671
672 static int
673 ase_resc_elm_string_p(const char *cp)
674 {
675         int state;
676         const Bufbyte *ucp = (const Bufbyte *)cp;
677
678
679         /* parse the residue class */
680         state = 0;
681         if (*ucp == '+' || *ucp == '-')
682                 ucp++;
683
684         if (*ucp >= '0' && *ucp <= '9') {
685                 state |= LEAD_INT;
686                 while (*ucp >= '0' && *ucp <= '9')
687                         ucp++;
688         }
689
690         /* check if we had a int number until here */
691         if (!(state == (LEAD_INT)))
692                 return 0;
693
694         /* now look for the residue class ring */
695         state = 0;
696         if (*ucp == '+') {
697                 state |= INTERMEDIATE_UNARY_SYMBOL;
698                 ucp++;
699         }
700
701         if (*ucp >= '1' && *ucp <= '9') {
702                 state |= LEAD_INT2;
703                 while (*ucp >= '0' && *ucp <= '9')
704                         ucp++;
705         }
706         if (*ucp == 'Z') {
707                 state |= Z_CHAR;
708                 ucp++;
709         }
710         return (((*ucp == 0) || (*ucp == ' ') || (*ucp == '\t') ||
711                  (*ucp == '\n') || (*ucp == '\r') || (*ucp == '\f')) &&
712                 (state == (INTERMEDIATE_UNARY_SYMBOL | LEAD_INT2 | Z_CHAR)));
713 }
714
715 \f
716 #if 0
717 static Lisp_Object
718 ent_intersection_factor_module(Lisp_Object *l, Lisp_Object *r)
719 {
720         Lisp_Object result_ring;
721
722         /* return a resulting ring by intersection of the rings in l and r and
723          * coerce l and r to that ring.
724          */
725
726         if (!bigz_eql(XRESC_RNG_DATA(XRESC_ELM_RING(*l)),
727                       XRESC_RNG_DATA(XRESC_ELM_RING(*r)))) {
728
729                 /* find a ring by intersection */
730                 bigz_lcm(ent_scratch_bigz,
731                          XRESC_RNG_DATA(XRESC_ELM_RING(*l)),
732                          XRESC_RNG_DATA(XRESC_ELM_RING(*r)));
733                 result_ring = make_resc_rng_bz(ent_scratch_bigz);
734
735                 /* coerce the left ring element to the lcm-ring */
736                 bigz_div(ent_scratch_bigz,
737                          XRESC_RNG_DATA(result_ring),
738                          XRESC_RNG_DATA(XRESC_ELM_RING(*l)));
739                 bigz_mul(ent_scratch_bigz,
740                          XRESC_ELM_DATA(*l),
741                          ent_scratch_bigz);
742                 *l = make_resc_elm_bz(ent_scratch_bigz, result_ring);
743
744                 /* coerce the right ring element to the lcm-ring */
745                 bigz_div(ent_scratch_bigz,
746                          XRESC_RNG_DATA(result_ring),
747                          XRESC_RNG_DATA(XRESC_ELM_RING(*r)));
748                 bigz_mul(ent_scratch_bigz,
749                          XRESC_ELM_DATA(*r),
750                          ent_scratch_bigz);
751                 *r = make_resc_elm_bz(ent_scratch_bigz, result_ring);
752
753         } else
754                 result_ring = XRESC_ELM_RING(*l);
755
756         return result_ring;
757 }
758 #endif
759
760 static int
761 ase_resclass_check_rings(Lisp_Object l, Lisp_Object r)
762 {
763         if (XASE_RESC_ELM_SMALLP(l) ^ XASE_RESC_ELM_SMALLP(r)) {
764         domain_error:
765                 Fsignal(Qdomain_error, list2(
766                                 XASE_RESC_ELM_RING(l), XASE_RESC_ELM_RING(r)));
767                 return 0;
768         } else if (XASE_RESC_ELM_SMALLP(l) &&
769                    XASE_RESC_RNG_SRING(XASE_RESC_ELM_RING(l)) ==
770                    XASE_RESC_RNG_SRING(XASE_RESC_ELM_RING(r))) {
771                 return 1;
772 #if defined HAVE_MPZ && (defined WITH_GMP || defined WITH_MP)
773         } else if (!XASE_RESC_ELM_SMALLP(l) &&
774                    bigz_eql(XASE_RESC_RNG_RING(XASE_RESC_ELM_RING(l)),
775                             XASE_RESC_RNG_RING(XASE_RESC_ELM_RING(r)))) {
776                 return 1;
777 #endif
778         }
779         goto domain_error;
780         return 0;
781 }
782
783 static inline Lisp_Object
784 ase_resclass_sum_small(Lisp_Object l, Lisp_Object r, Lisp_Object result_ring)
785 {
786         EMACS_INT sum =
787                 XASE_RESC_ELM(l)->small_data + XASE_RESC_ELM(r)->small_data;
788         return ase_make_resc_elm(make_int(sum), result_ring);
789 }
790
791 #if defined HAVE_MPZ && (defined WITH_GMP || defined WITH_MP)
792 static inline Lisp_Object
793 ase_resclass_sum_big(Lisp_Object l, Lisp_Object r, Lisp_Object result_ring)
794 {
795         ase_resc_elm_t e = NULL;
796         bigz_add(ent_scratch_bigz,
797                  XASE_RESC_ELM_DATA(l), XASE_RESC_ELM_DATA(r));
798         e = __ase_make_resc_elm_bigz(ent_scratch_bigz);
799         e->smallp = 0;
800         e->ring = result_ring;
801         _ase_resc_elm_canonicalise_big(e);
802         return _ase_wrap_resc_elm(e);
803 }
804 #endif
805
806 static Lisp_Object
807 ase_resclass_sum(Lisp_Object l, Lisp_Object r)
808 {
809         ase_resclass_check_rings(l, r);
810
811 #if 0
812         result_ring = ent_intersection_factor_module(&l, &r);
813 #endif
814
815         if (XASE_RESC_ELM_SMALLP(l) && XASE_RESC_ELM_SMALLP(r)) {
816                 return ase_resclass_sum_small(l, r, XASE_RESC_ELM_RING(l));
817         } else {
818 #if defined HAVE_MPZ && (defined WITH_GMP || defined WITH_MP)
819                 return ase_resclass_sum_big(l, r, XASE_RESC_ELM_RING(l));
820 #endif
821         }
822         return Qnil;
823 }
824
825
826 static inline Lisp_Object
827 ase_resclass_sum_intg_small(
828         Lisp_Object l, Lisp_Object intg, Lisp_Object result_ring)
829 {
830         if (INTP(intg)) {
831                 EMACS_INT sum =
832                         XASE_RESC_ELM(l)->small_data + XINT(intg);
833                 return ase_make_resc_elm(make_int(sum), result_ring);
834 #if defined HAVE_MPZ && (defined WITH_GMP || defined WITH_MP)
835         } else if (BIGZP(intg)) {
836                 EMACS_INT sum;
837                 bigz_set_long(ent_scratch_bigz,
838                               XASE_RESC_RNG(XASE_RESC_ELM_RING(l))->small_ring);
839                 bigz_mod(ent_scratch_bigz, XBIGZ_DATA(intg), ent_scratch_bigz);
840                 sum = XASE_RESC_ELM(l)->small_data +
841                         bigz_to_long(ent_scratch_bigz);
842                 return ase_make_resc_elm(make_int(sum), result_ring);
843 #endif
844         }
845         return Qnil;
846 }
847
848 #if defined HAVE_MPZ && (defined WITH_GMP || defined WITH_MP)
849 static inline Lisp_Object
850 ase_resclass_sum_intg_big(
851         Lisp_Object l, Lisp_Object intg, Lisp_Object result_ring)
852 {
853         if (INTP(intg)) {
854                 ase_resc_elm_t e = NULL;
855                 bigz_set_long(ent_scratch_bigz, XINT(intg));
856                 bigz_add(ent_scratch_bigz,
857                          XASE_RESC_ELM_DATA(l), ent_scratch_bigz);
858                 e = __ase_make_resc_elm_bigz(ent_scratch_bigz);
859                 e->smallp = 0;
860                 e->ring = result_ring;
861                 _ase_resc_elm_canonicalise_big(e);
862                 return _ase_wrap_resc_elm(e);
863         } else if (BIGZP(intg)) {
864                 ase_resc_elm_t e = NULL;
865                 bigz_add(ent_scratch_bigz,
866                          XASE_RESC_ELM_DATA(l), XBIGZ_DATA(intg));
867                 e = __ase_make_resc_elm_bigz(ent_scratch_bigz);
868                 e->smallp = 0;
869                 e->ring = result_ring;
870                 _ase_resc_elm_canonicalise_big(e);
871                 return _ase_wrap_resc_elm(e);
872         }
873         return Qnil;
874 }
875 #endif
876
877 static Lisp_Object
878 ase_resclass_sum_intg(Lisp_Object l, Lisp_Object r)
879 {
880         if (INTEGERP(l) && XASE_RESC_ELM_SMALLP(r)) {
881                 return ase_resclass_sum_intg_small(
882                         r, l, XASE_RESC_ELM_RING(r));
883         } else if (INTEGERP(r) && XASE_RESC_ELM_SMALLP(l)) {
884                 return ase_resclass_sum_intg_small(
885                         l, r, XASE_RESC_ELM_RING(l));
886 #if defined HAVE_MPZ && (defined WITH_GMP || defined WITH_MP)
887         } else if (INTEGERP(l)) {
888                 return ase_resclass_sum_intg_big(
889                         r, l, XASE_RESC_ELM_RING(r));
890         } else if (INTEGERP(r)) {
891                 return ase_resclass_sum_intg_big(
892                         l, r, XASE_RESC_ELM_RING(l));
893 #endif
894         }
895         return Qnil;
896 }
897
898
899 static inline Lisp_Object
900 ase_resclass_diff_small(Lisp_Object l, Lisp_Object r, Lisp_Object result_ring)
901 {
902         EMACS_INT diff =
903                 XASE_RESC_ELM(l)->small_data - XASE_RESC_ELM(r)->small_data;
904         return ase_make_resc_elm(make_int(diff), result_ring);
905 }
906
907 #if defined HAVE_MPZ && (defined WITH_GMP || defined WITH_MP)
908 static inline Lisp_Object
909 ase_resclass_diff_big(Lisp_Object l, Lisp_Object r, Lisp_Object result_ring)
910 {
911         ase_resc_elm_t e = NULL;
912         bigz_sub(ent_scratch_bigz,
913                  XASE_RESC_ELM_DATA(l), XASE_RESC_ELM_DATA(r));
914         e = __ase_make_resc_elm_bigz(ent_scratch_bigz);
915         e->smallp = 0;
916         e->ring = result_ring;
917         _ase_resc_elm_canonicalise_big(e);
918         return _ase_wrap_resc_elm(e);
919 }
920 #endif
921
922 static Lisp_Object
923 ase_resclass_diff(Lisp_Object l, Lisp_Object r)
924 {
925         ase_resclass_check_rings(l, r);
926
927 #if 0
928         result_ring = ent_intersection_factor_module(&l, &r);
929 #endif
930
931         if (XASE_RESC_ELM_SMALLP(l) && XASE_RESC_ELM_SMALLP(r)) {
932                 return ase_resclass_diff_small(l, r, XASE_RESC_ELM_RING(l));
933         } else {
934 #if defined HAVE_MPZ && (defined WITH_GMP || defined WITH_MP)
935                 return ase_resclass_diff_big(l, r, XASE_RESC_ELM_RING(l));
936 #endif
937         }
938         return Qnil;
939 }
940
941
942 static inline Lisp_Object
943 ase_resclass_diff_intg_small(
944         Lisp_Object l, Lisp_Object intg, Lisp_Object result_ring)
945 {
946         if (INTP(intg)) {
947                 EMACS_INT diff =
948                         XASE_RESC_ELM(l)->small_data - XINT(intg);
949                 return ase_make_resc_elm(make_int(diff), result_ring);
950 #if defined HAVE_MPZ && (defined WITH_GMP || defined WITH_MP)
951         } else if (BIGZP(intg)) {
952                 EMACS_INT diff;
953                 bigz_set_long(ent_scratch_bigz,
954                               XASE_RESC_RNG(XASE_RESC_ELM_RING(l))->small_ring);
955                 bigz_mod(ent_scratch_bigz, XBIGZ_DATA(intg), ent_scratch_bigz);
956                 diff = XASE_RESC_ELM(l)->small_data -
957                         bigz_to_long(ent_scratch_bigz);
958                 return ase_make_resc_elm(make_int(diff), result_ring);
959 #endif
960         }
961         return Qnil;
962 }
963
964 #if defined HAVE_MPZ && (defined WITH_GMP || defined WITH_MP)
965 static inline Lisp_Object
966 ase_resclass_diff_intg_big(
967         Lisp_Object l, Lisp_Object intg, Lisp_Object result_ring)
968 {
969         if (INTP(intg)) {
970                 ase_resc_elm_t e = NULL;
971                 bigz_set_long(ent_scratch_bigz, XINT(intg));
972                 bigz_sub(ent_scratch_bigz,
973                          XASE_RESC_ELM_DATA(l), ent_scratch_bigz);
974                 e = __ase_make_resc_elm_bigz(ent_scratch_bigz);
975                 e->smallp = 0;
976                 e->ring = result_ring;
977                 _ase_resc_elm_canonicalise_big(e);
978                 return _ase_wrap_resc_elm(e);
979         } else if (BIGZP(intg)) {
980                 ase_resc_elm_t e = NULL;
981                 bigz_sub(ent_scratch_bigz,
982                          XASE_RESC_ELM_DATA(l), XBIGZ_DATA(intg));
983                 e = __ase_make_resc_elm_bigz(ent_scratch_bigz);
984                 e->smallp = 0;
985                 e->ring = result_ring;
986                 _ase_resc_elm_canonicalise_big(e);
987                 return _ase_wrap_resc_elm(e);
988         }
989         return Qnil;
990 }
991 #endif
992
993 static Lisp_Object
994 ase_resclass_diff_intg(Lisp_Object l, Lisp_Object r)
995 {
996         if (XASE_RESC_ELM_SMALLP(l)) {
997                 return ase_resclass_diff_intg_small(
998                         l, r, XASE_RESC_ELM_RING(l));
999 #if defined HAVE_MPZ && (defined WITH_GMP || defined WITH_MP)
1000         } else {
1001                 return ase_resclass_diff_intg_big(
1002                         l, r, XASE_RESC_ELM_RING(l));
1003 #endif
1004         }
1005         return Qnil;
1006 }
1007
1008
1009 static inline Lisp_Object
1010 ase_resclass_prod_small(Lisp_Object l, Lisp_Object r, Lisp_Object result_ring)
1011 {
1012         EMACS_INT prod =
1013                 XASE_RESC_ELM(l)->small_data * XASE_RESC_ELM(r)->small_data;
1014         return ase_make_resc_elm(make_int(prod), result_ring);
1015 }
1016
1017 #if defined HAVE_MPZ && (defined WITH_GMP || defined WITH_MP)
1018 static inline Lisp_Object
1019 ase_resclass_prod_big(Lisp_Object l, Lisp_Object r, Lisp_Object result_ring)
1020 {
1021         ase_resc_elm_t e = NULL;
1022         bigz_mul(ent_scratch_bigz,
1023                  XASE_RESC_ELM_DATA(l), XASE_RESC_ELM_DATA(r));
1024         e = __ase_make_resc_elm_bigz(ent_scratch_bigz);
1025         e->smallp = 0;
1026         e->ring = result_ring;
1027         _ase_resc_elm_canonicalise_big(e);
1028         return _ase_wrap_resc_elm(e);
1029 }
1030 #endif
1031
1032 static Lisp_Object
1033 ase_resclass_prod(Lisp_Object l, Lisp_Object r)
1034 {
1035         ase_resclass_check_rings(l, r);
1036
1037 #if 0
1038         result_ring = ent_intersection_factor_module(&l, &r);
1039 #endif
1040
1041         if (XASE_RESC_ELM_SMALLP(l) && XASE_RESC_ELM_SMALLP(r)) {
1042                 return ase_resclass_prod_small(l, r, XASE_RESC_ELM_RING(l));
1043         } else {
1044 #if defined HAVE_MPZ && (defined WITH_GMP || defined WITH_MP)
1045                 return ase_resclass_prod_big(l, r, XASE_RESC_ELM_RING(l));
1046 #endif
1047         }
1048         return Qnil;
1049 }
1050
1051 static inline Lisp_Object
1052 ase_resclass_prod_intg_small(
1053         Lisp_Object l, Lisp_Object intg, Lisp_Object result_ring)
1054 {
1055         if (INTP(intg)) {
1056                 EMACS_INT prod =
1057                         XASE_RESC_ELM(l)->small_data * XINT(intg);
1058                 return ase_make_resc_elm(make_int(prod), result_ring);
1059 #if defined HAVE_MPZ && (defined WITH_GMP || defined WITH_MP)
1060         } else if (BIGZP(intg)) {
1061                 EMACS_INT prod;
1062                 bigz_set_long(ent_scratch_bigz,
1063                               XASE_RESC_RNG(XASE_RESC_ELM_RING(l))->small_ring);
1064                 bigz_mod(ent_scratch_bigz, XBIGZ_DATA(intg), ent_scratch_bigz);
1065                 prod = XASE_RESC_ELM(l)->small_data *
1066                         bigz_to_long(ent_scratch_bigz);
1067                 return ase_make_resc_elm(make_int(prod), result_ring);
1068 #endif
1069         }
1070         return Qnil;
1071 }
1072
1073 #if defined HAVE_MPZ && (defined WITH_GMP || defined WITH_MP)
1074 static inline Lisp_Object
1075 ase_resclass_prod_intg_big(
1076         Lisp_Object l, Lisp_Object intg, Lisp_Object result_ring)
1077 {
1078         if (INTP(intg)) {
1079                 ase_resc_elm_t e = NULL;
1080                 bigz_set_long(ent_scratch_bigz, XINT(intg));
1081                 bigz_mul(ent_scratch_bigz,
1082                          XASE_RESC_ELM_DATA(l), ent_scratch_bigz);
1083                 e = __ase_make_resc_elm_bigz(ent_scratch_bigz);
1084                 e->smallp = 0;
1085                 e->ring = result_ring;
1086                 _ase_resc_elm_canonicalise_big(e);
1087                 return _ase_wrap_resc_elm(e);
1088         } else if (BIGZP(intg)) {
1089                 ase_resc_elm_t e = NULL;
1090                 bigz_mul(ent_scratch_bigz,
1091                          XASE_RESC_ELM_DATA(l), XBIGZ_DATA(intg));
1092                 e = __ase_make_resc_elm_bigz(ent_scratch_bigz);
1093                 e->smallp = 0;
1094                 e->ring = result_ring;
1095                 _ase_resc_elm_canonicalise_big(e);
1096                 return _ase_wrap_resc_elm(e);
1097         }
1098         return Qnil;
1099 }
1100 #endif
1101
1102 static Lisp_Object
1103 ase_resclass_prod_intg(Lisp_Object l, Lisp_Object r)
1104 {
1105         if (INTEGERP(l) && XASE_RESC_ELM_SMALLP(r)) {
1106                 return ase_resclass_prod_intg_small(
1107                         r, l, XASE_RESC_ELM_RING(r));
1108         } else if (INTEGERP(r) && XASE_RESC_ELM_SMALLP(l)) {
1109                 return ase_resclass_prod_intg_small(
1110                         l, r, XASE_RESC_ELM_RING(l));
1111 #if defined HAVE_MPZ && (defined WITH_GMP || defined WITH_MP)
1112         } else if (INTEGERP(l)) {
1113                 return ase_resclass_prod_intg_big(
1114                         r, l, XASE_RESC_ELM_RING(r));
1115         } else if (INTEGERP(r)) {
1116                 return ase_resclass_prod_intg_big(
1117                         l, r, XASE_RESC_ELM_RING(l));
1118 #endif
1119         }
1120         return Qnil;
1121 }
1122
1123
1124 static Lisp_Object
1125 ase_resclass_div(Lisp_Object l, Lisp_Object r)
1126 {
1127         ase_object_type_t idx = ase_optable_index_typesym(Qase_resc_elm);
1128         Lisp_Object inv = _ent_unop(ASE_UNARY_OP_INV, idx, r);
1129         Lisp_Object mul = _ent_binop(ASE_BINARY_OP_PROD, idx, l, idx, inv);
1130         return mul;
1131 }
1132
1133 static Lisp_Object
1134 ase_resclass_div_INT_T(Lisp_Object l, Lisp_Object r)
1135 {
1136         ase_object_type_t idx = ase_optable_index_typesym(Qase_resc_elm);
1137         Lisp_Object inv = _ent_unop(ASE_UNARY_OP_INV, idx, l);
1138         Lisp_Object mul = _ent_binop(ASE_BINARY_OP_PROD, idx, inv, INT_T, r);
1139         return mul;
1140 }
1141
1142 static Lisp_Object
1143 ase_resclass_INT_T_div(Lisp_Object l, Lisp_Object r)
1144 {
1145         ase_object_type_t idx = ase_optable_index_typesym(Qase_resc_elm);
1146         Lisp_Object inv = _ent_unop(ASE_UNARY_OP_INV, idx, r);
1147         Lisp_Object mul = _ent_binop(ASE_BINARY_OP_PROD, idx, l, INT_T, inv);
1148         return mul;
1149 }
1150
1151 static Lisp_Object
1152 ase_resclass_div_BIGZ_T(Lisp_Object l, Lisp_Object r)
1153 {
1154         ase_object_type_t idx = ase_optable_index_typesym(Qase_resc_elm);
1155         Lisp_Object inv = _ent_unop(ASE_UNARY_OP_INV, idx, l);
1156         Lisp_Object mul = _ent_binop(ASE_BINARY_OP_PROD, idx, inv, BIGZ_T, r);
1157         return mul;
1158 }
1159
1160 static Lisp_Object
1161 ase_resclass_BIGZ_T_div(Lisp_Object l, Lisp_Object r)
1162 {
1163         ase_object_type_t idx = ase_optable_index_typesym(Qase_resc_elm);
1164         Lisp_Object inv = _ent_unop(ASE_UNARY_OP_INV, idx, r);
1165         Lisp_Object mul = _ent_binop(ASE_BINARY_OP_PROD, idx, l, BIGZ_T, inv);
1166         return mul;
1167 }
1168
1169 #if defined HAVE_MPZ && (defined WITH_GMP || defined WITH_MP)
1170 static Lisp_Object
1171 ase_resclass_pow(Lisp_Object l, Lisp_Object r)
1172 {
1173         Lisp_Object rng = XASE_RESC_ELM_RING(l);
1174         bigz expo;
1175
1176         bigz_init(expo);
1177         if (INTP(r)) {
1178                 bigz_set_long(expo, ent_int(r));
1179         } else if (BIGZP(r)) {
1180                 bigz_set(expo, XBIGZ_DATA(r));
1181         } else {
1182                 Fsignal(Qoperation_error, r);
1183         }
1184
1185         if (XASE_RESC_ELM_SMALLP(l)) {
1186                 long res = 0;
1187                 bigz tmp;
1188
1189                 bigz_init(tmp);
1190                 bigz_set_long(tmp, XASE_RESC_RNG_SRING(rng));
1191                 bigz_set_long(ent_scratch_bigz, XASE_RESC_ELM_SDATA(l));
1192                 mpz_powm(ent_scratch_bigz, ent_scratch_bigz, expo, tmp);
1193                 res = bigz_to_long(ent_scratch_bigz);
1194                 bigz_fini(tmp);
1195                 bigz_fini(expo);
1196                 return ase_make_resc_elm(make_int(res), rng);
1197         } else {
1198                 ase_resc_elm_t e = NULL;
1199                 mpz_powm(ent_scratch_bigz, XASE_RESC_ELM_DATA(l),
1200                          expo, XASE_RESC_RNG_RING(l));
1201                 e = __ase_make_resc_elm_bigz(ent_scratch_bigz);
1202                 e->smallp = 0;
1203                 e->ring = XASE_RESC_ELM_RING(l);
1204                 _ase_resc_elm_canonicalise_big(e);
1205                 bigz_fini(expo);
1206                 return _ase_wrap_resc_elm(e);
1207         }
1208         bigz_fini(expo);
1209         return Qnil;
1210 }
1211 #endif
1212
1213 static Lisp_Object
1214 ase_resclass_neg(Lisp_Object l)
1215 {
1216         Lisp_Object rng = XASE_RESC_ELM_RING(l);
1217         if (XASE_RESC_ELM_SMALLP(l)) {
1218                 EMACS_INT sum =
1219                         XASE_RESC_RNG_SRING(rng) - XASE_RESC_ELM_SDATA(l);
1220                 return ase_make_resc_elm(make_int(sum), rng);
1221 #if defined HAVE_MPZ && (defined WITH_GMP || defined WITH_MP)
1222         } else {
1223                 ase_resc_elm_t e = NULL;
1224                 bigz_set(ent_scratch_bigz, XASE_RESC_RNG_RING(rng));
1225                 bigz_sub(ent_scratch_bigz,
1226                          ent_scratch_bigz, XASE_RESC_ELM_DATA(l));
1227                 e = __ase_make_resc_elm_bigz(ent_scratch_bigz);
1228                 e->smallp = 0;
1229                 e->ring = rng;
1230                 _ase_resc_elm_canonicalise_big(e);
1231                 return _ase_wrap_resc_elm(e);
1232 #endif
1233         }
1234         return Qnil;
1235 }
1236
1237 #if defined HAVE_MPZ && (defined WITH_GMP || defined WITH_MP)
1238 static Lisp_Object
1239 ase_resclass_inv(Lisp_Object r)
1240 {
1241         Lisp_Object rng = XASE_RESC_ELM_RING(r);
1242         int state = 0;
1243
1244
1245         if (XASE_RESC_ELM_SMALLP(r)) {
1246                 bigz tmp;
1247                 bigz_init(tmp);
1248                 bigz_set_long(tmp, XASE_RESC_ELM_SDATA(r));
1249                 bigz_set_long(ent_scratch_bigz, XASE_RESC_RNG_SRING(rng));
1250                 state = mpz_invert(ent_scratch_bigz, tmp, ent_scratch_bigz);
1251                 bigz_fini(tmp);
1252         } else {
1253                 state = mpz_invert(ent_scratch_bigz,
1254                                    XASE_RESC_ELM_DATA(r),
1255                                    XASE_RESC_RNG_RING(rng));
1256         }
1257
1258         if (!state) {
1259                 error("cannot operate on zero divisor");
1260                 return Qzero;
1261         }
1262
1263         if (XASE_RESC_ELM_SMALLP(r)) {
1264                 return ase_make_resc_elm(
1265                         make_int(bigz_to_long(ent_scratch_bigz)), rng);
1266         } else {
1267                 ase_resc_elm_t e = __ase_make_resc_elm_bigz(ent_scratch_bigz);
1268                 e->smallp = 0;
1269                 e->ring = rng;
1270                 _ase_resc_elm_canonicalise_big(e);
1271                 return _ase_wrap_resc_elm(e);
1272         }
1273         return Qnil;
1274 }
1275 #endif
1276
1277 /* relations */
1278 static int
1279 ase_resclass_eq(Lisp_Object l, Lisp_Object r)
1280 {
1281         ase_resclass_check_rings(l, r);
1282
1283         if (XASE_RESC_ELM_SMALLP(l)) {
1284                 return (XASE_RESC_ELM_SDATA(l) == XASE_RESC_ELM_SDATA(r));
1285 #if defined HAVE_MPZ && (defined WITH_GMP || defined WITH_MP)
1286         } else if (!XASE_RESC_ELM_SMALLP(l)) {
1287                 return bigz_eql(XASE_RESC_ELM_DATA(l), XASE_RESC_ELM_DATA(r));
1288 #endif
1289         }
1290         return 0;
1291 }
1292
1293 static int
1294 ase_resclass_ne(Lisp_Object l, Lisp_Object r)
1295 {
1296         ase_resclass_check_rings(l, r);
1297
1298         if (XASE_RESC_ELM_SMALLP(l)) {
1299                 return (XASE_RESC_ELM_SDATA(l) != XASE_RESC_ELM_SDATA(r));
1300 #if defined HAVE_MPZ && (defined WITH_GMP || defined WITH_MP)
1301         } else if (!XASE_RESC_ELM_SMALLP(l)) {
1302                 return !bigz_eql(XASE_RESC_ELM_DATA(l), XASE_RESC_ELM_DATA(r));
1303 #endif
1304         }
1305         return 1;
1306 }
1307
1308 static int
1309 ase_resclass_zerop(Lisp_Object elm)
1310 {
1311         if (XASE_RESC_ELM_SMALLP(elm)) {
1312                 return (XASE_RESC_ELM_SDATA(elm) == 0);
1313 #if defined HAVE_MPZ && (defined WITH_GMP || defined WITH_MP)
1314         } else if (!XASE_RESC_ELM_SMALLP(elm)) {
1315 #               define __d      XASE_RESC_ELM_DATA(elm)
1316                 return (bigz_fits_long_p(__d) && bigz_to_long(__d) == 0);
1317 #               undef __d
1318 #endif
1319         }
1320         return 0;
1321 }
1322
1323 static int
1324 ase_resclass_onep(Lisp_Object elm)
1325 {
1326         if (XASE_RESC_ELM_SMALLP(elm)) {
1327                 return (XASE_RESC_ELM_SDATA(elm) == 1);
1328 #if defined HAVE_MPZ && (defined WITH_GMP || defined WITH_MP)
1329         } else if (!XASE_RESC_ELM_SMALLP(elm)) {
1330 #               define __d      XASE_RESC_ELM_DATA(elm)
1331                 return (bigz_fits_long_p(__d) && bigz_to_long(__d) == 1);
1332 #               undef __d
1333 #endif
1334         }
1335         return 0;
1336 }
1337
1338 #if defined HAVE_MPZ && (defined WITH_GMP || defined WITH_MP)
1339 static int
1340 ase_resclass_unitp(Lisp_Object elm)
1341 {
1342         Lisp_Object rng = XASE_RESC_ELM_RING(elm);
1343         int state = 0;
1344
1345
1346         if (XASE_RESC_ELM_SMALLP(elm)) {
1347                 bigz tmp;
1348                 bigz_set_long(tmp, XASE_RESC_ELM_SDATA(elm));
1349                 bigz_set_long(ent_scratch_bigz, XASE_RESC_RNG_SRING(rng));
1350                 state = mpz_invert(ent_scratch_bigz, tmp, ent_scratch_bigz);
1351                 bigz_init(tmp);
1352         } else {
1353                 state = mpz_invert(ent_scratch_bigz,
1354                                    XASE_RESC_ELM_DATA(elm),
1355                                    XASE_RESC_RNG_RING(rng));
1356         }
1357         return state;
1358 }
1359 #endif
1360
1361 \f
1362 #if defined HAVE_MPZ && (defined WITH_GMP || defined WITH_MP)
1363 static Lisp_Object
1364 ase_resclass_lift_to_BIGZ_T(Lisp_Object number, ent_lift_args_t UNUSED(la))
1365 {
1366         if (XASE_RESC_ELM_SMALLP(number)) {
1367                 make_bigz(XASE_RESC_ELM_SDATA(number));
1368         } else {
1369                 return make_bigz_bz(XASE_RESC_ELM_DATA(number));
1370         }
1371         return Qnil;
1372 }
1373 #endif
1374
1375 static Lisp_Object
1376 ase_resclass_lift_to_INT_T(Lisp_Object number, ent_lift_args_t UNUSED(la))
1377 {
1378         if (XASE_RESC_ELM_SMALLP(number)) {
1379                 return make_int(XASE_RESC_ELM_SDATA(number));
1380 #if defined HAVE_MPZ && (defined WITH_GMP || defined WITH_MP)
1381         } else {
1382                 return make_int(bigz_to_long(XASE_RESC_ELM_DATA(number)));
1383 #endif
1384         }
1385         return Qnil;
1386 }
1387
1388 #ifdef HAVE_FPFLOAT
1389 static Lisp_Object
1390 ase_resclass_lift_to_FLOAT_T(Lisp_Object number, ent_lift_args_t UNUSED(la))
1391 {
1392         if (XASE_RESC_ELM_SMALLP(number)) {
1393                 return make_float(XASE_RESC_ELM_SDATA(number));
1394 #if defined HAVE_MPZ && (defined WITH_GMP || defined WITH_MP)
1395         } else {
1396                 return make_float(bigz_to_fpfloat(XASE_RESC_ELM_DATA(number)));
1397 #endif
1398         }
1399         return Qnil;
1400 }
1401 #endif
1402
1403 \f
1404 static inline void
1405 ent_resclass_nullary_optable_init(void)
1406 {
1407         ent_nullop_register(ASE_NULLARY_OP_ZERO, INDEF_T, Qzero);
1408         ent_nullop_register(ASE_NULLARY_OP_ONE, INDEF_T, Qone);
1409 }
1410
1411 static inline void
1412 ent_resclass_unary_optable_init(void)
1413 {
1414         ase_object_type_t idx = ase_optable_index_typesym(Qase_resc_elm);
1415         ent_unop_register(ASE_UNARY_OP_NEG, idx, ase_resclass_neg);
1416 #if defined HAVE_MPZ && (defined WITH_GMP || defined WITH_MP)
1417         ent_unop_register(ASE_UNARY_OP_INV, idx, ase_resclass_inv);
1418 #endif
1419 }
1420
1421 static inline void
1422 ent_resclass_binary_optable_init(void)
1423 {
1424         ase_object_type_t idx = ase_optable_index_typesym(Qase_resc_elm);
1425
1426         ent_binop_register(ASE_BINARY_OP_SUM,
1427                            idx, idx, ase_resclass_sum);
1428         ent_binop_register(ASE_BINARY_OP_SUM,
1429                            idx, INT_T, ase_resclass_sum_intg);
1430         ent_binop_register(ASE_BINARY_OP_SUM,
1431                            INT_T, idx, ase_resclass_sum_intg);
1432         ent_binop_register(ASE_BINARY_OP_SUM,
1433                            idx, BIGZ_T, ase_resclass_sum_intg);
1434         ent_binop_register(ASE_BINARY_OP_SUM,
1435                            BIGZ_T, idx, ase_resclass_sum_intg);
1436
1437         ent_binop_register(ASE_BINARY_OP_DIFF,
1438                            idx, idx, ase_resclass_diff);
1439         ent_binop_register(ASE_BINARY_OP_DIFF,
1440                            idx, INT_T, ase_resclass_diff_intg);
1441         ent_binop_register(ASE_BINARY_OP_DIFF,
1442                            idx, BIGZ_T, ase_resclass_diff_intg);
1443
1444         ent_binop_register(ASE_BINARY_OP_PROD,
1445                            idx, idx, ase_resclass_prod);
1446         ent_binop_register(ASE_BINARY_OP_PROD,
1447                            idx, INT_T, ase_resclass_prod_intg);
1448         ent_binop_register(ASE_BINARY_OP_PROD,
1449                            INT_T, idx, ase_resclass_prod_intg);
1450         ent_binop_register(ASE_BINARY_OP_PROD,
1451                            idx, BIGZ_T, ase_resclass_prod_intg);
1452         ent_binop_register(ASE_BINARY_OP_PROD,
1453                            BIGZ_T, idx, ase_resclass_prod_intg);
1454
1455         ent_binop_register(ASE_BINARY_OP_DIV,
1456                            idx, idx, ase_resclass_div);
1457         ent_binop_register(ASE_BINARY_OP_QUO,
1458                            idx, idx, ase_resclass_div);
1459         ent_binop_register(ASE_BINARY_OP_DIV,
1460                            idx, INT_T, ase_resclass_div_INT_T);
1461         ent_binop_register(ASE_BINARY_OP_QUO,
1462                            idx, INT_T, ase_resclass_div_INT_T);
1463         ent_binop_register(ASE_BINARY_OP_DIV,
1464                            INT_T, idx, ase_resclass_INT_T_div);
1465         ent_binop_register(ASE_BINARY_OP_QUO,
1466                            INT_T, idx, ase_resclass_INT_T_div);
1467         ent_binop_register(ASE_BINARY_OP_DIV,
1468                            idx, BIGZ_T, ase_resclass_div_BIGZ_T);
1469         ent_binop_register(ASE_BINARY_OP_QUO,
1470                            idx, BIGZ_T, ase_resclass_div_BIGZ_T);
1471         ent_binop_register(ASE_BINARY_OP_DIV,
1472                            BIGZ_T, idx, ase_resclass_BIGZ_T_div);
1473         ent_binop_register(ASE_BINARY_OP_QUO,
1474                            BIGZ_T, idx, ase_resclass_BIGZ_T_div);
1475
1476 #if defined HAVE_MPZ && (defined WITH_GMP || defined WITH_MP)
1477         ent_binop_register(ASE_BINARY_OP_POW,
1478                            idx, INT_T, ase_resclass_pow);
1479         ent_binop_register(ASE_BINARY_OP_POW,
1480                            idx, BIGZ_T, ase_resclass_pow);
1481 #endif
1482 }
1483
1484 static inline void
1485 ent_resclass_unary_reltable_init(void)
1486 {
1487         ase_object_type_t idx = ase_optable_index_typesym(Qase_resc_elm);
1488         ent_unrel_register(ASE_UNARY_REL_ZEROP, idx, ase_resclass_zerop);
1489         ent_unrel_register(ASE_UNARY_REL_ONEP, idx, ase_resclass_onep);
1490 #if defined HAVE_MPZ && (defined WITH_GMP || defined WITH_MP)
1491         ent_unrel_register(ASE_UNARY_REL_UNITP, idx, ase_resclass_unitp);
1492 #endif
1493 }
1494
1495 static inline void
1496 ent_resclass_binary_reltable_init(void)
1497 {
1498         ase_object_type_t idx = ase_optable_index_typesym(Qase_resc_elm);
1499         ent_binrel_register(ASE_BINARY_REL_EQUALP,
1500                             idx, idx, ase_resclass_eq);
1501         ent_binrel_register(ASE_BINARY_REL_NEQP,
1502                             idx, idx, ase_resclass_ne);
1503 }
1504
1505 static inline void
1506 ent_resclass_lifttable_init(void)
1507 {
1508         ase_object_type_t idx = ase_optable_index_typesym(Qase_resc_elm);
1509         ent_lift_register(idx, INT_T, ase_resclass_lift_to_INT_T);
1510 #if defined HAVE_MPZ && (defined WITH_GMP || defined WITH_MP)
1511         ent_lift_register(idx, BIGZ_T, ase_resclass_lift_to_BIGZ_T);
1512 #endif
1513 #ifdef HAVE_FPFLOAT
1514         ent_lift_register(idx, FLOAT_T, ase_resclass_lift_to_FLOAT_T);
1515 #endif
1516 }
1517
1518 \f
1519 /* ###autoload */
1520 DEFUN("make-residue-class-ring", Fmake_residue_class_ring, 1, 1, 0, /*
1521 Return a residue class ring of size MODULUS (>= 2).
1522 */
1523        (modulus))
1524 {
1525         CHECK_INTEGER(modulus);
1526         if (NILP(Fnonnegativep(modulus)))
1527                 error("cannot create ring with negative modulus");
1528         if (ent_unrel_zerop(modulus))
1529                 error("cannot create ring of size 0");
1530         if (ent_unrel_onep(modulus))
1531                 error("ring is identical to Z");
1532
1533         return ase_make_resc_rng(modulus);
1534 }
1535
1536 /* ###autoload */
1537 DEFUN("make-residue-class", Fmake_residue_class, 2, 2, 0, /*
1538 Return the residue class of ELEMENT in RING.
1539 */
1540       (element, ring))
1541 {
1542         CHECK_ASE_RESC_RNG(ring);
1543         CHECK_INTEGER(element);
1544
1545         return ase_make_resc_elm(element, ring);
1546 }
1547
1548 /* ###autoload */
1549 DEFUN("residue-class-ring", Fresidue_class_ring, 1, 1, 0, /*
1550 Return the parental residue class ring (the world) of RESCLASS.
1551 */
1552       (resclass))
1553 {
1554         CHECK_ASE_RESC_ELM(resclass);
1555
1556         return XASE_RESC_ELM_RING(resclass);
1557 }
1558
1559 #if 0
1560 /* ###autoload */
1561 D3FUN("residue-class-modulus", Fresidue_class_modulus, 1, 1, 0, /*
1562 Return the modulus of the residue class ring RING-OR-ELEMENT,
1563 or the modulus of a residue class, respectively.
1564                                                                 */
1565        (ring_or_element))
1566 {
1567         Lisp_Object rng;
1568
1569         if (!ASE_RESC_ELM_P(ring_or_element) &&
1570             !ASE_RESC_RNG_P(ring_or_element)) {
1571                 return wrong_type_argument(Qase_resc_elm_p, ring_or_element);
1572         }
1573
1574         if (ASE_RESC_ELM_P(ring_or_element))
1575                 rng = XASE_RESC_ELM_RING(ring_or_element);
1576         else if (ASE_RESC_RNG_P(ring_or_element))
1577                 rng = ring_or_element;
1578         else
1579                 return Qzero;
1580
1581         return make_bigz_bz(XASE_RESC_RNG_RING(rng));
1582 }
1583
1584 /* ###autoload */
1585 D3FUN("residue-class-representant", Fresidue_class_representant, 1, 1, 0, /*
1586 Return the representant of the residue class ELEMENT lifted 
1587 to the ring of rational integers.
1588                                                                           */
1589        (element))
1590 {
1591         CHECK_ASE_RESC_ELM(element);
1592
1593         return make_bigz_bz(XASE_RESC_ELM_DATA(element));
1594 }
1595 #endif
1596
1597 /* ###autoload */
1598 DEFUN ("residue-class-ring-p", Fresidue_class_ring_p, 1, 1, 0, /*
1599 Return t if OBJECT is a residue class ring, nil otherwise.
1600 */
1601        (object))
1602 {
1603         return ASE_RESC_RNG_P(object) ? Qt : Qnil;
1604 }
1605
1606 /* ###autoload */
1607 DEFUN ("residue-class-p", Fresidue_class_p, 1, 1, 0, /*
1608 Return t if OBJECT is a residue class, nil otherwise.
1609 */
1610        (object))
1611 {
1612         return ASE_RESC_ELM_P(object) ? Qt : Qnil;
1613 }
1614
1615 /* from number-to-string */
1616 #ifdef HAVE_RESCLASS
1617         if (RESC_ELMP(number)) {
1618                 char *estr = (char*)resc_elm_to_string(
1619                         XRESC_ELM_DATA(number), 10);
1620                 char *rstr = (char*)resc_rng_to_string(
1621                         XRESC_RNG_DATA(XRESC_ELM_RING(number)), 10);
1622                 int elen = strlen(estr);
1623                 int rlen = strlen(rstr);
1624                 Lisp_Object result;
1625
1626                 XREALLOC_ARRAY(estr, char, elen+1+rlen+1 + 1);
1627                 strncat(estr, "+", 1);
1628                 strncat(estr, rstr, rlen);
1629                 strncat(estr, "Z", 1);
1630                 result = build_string(estr);
1631                 free(estr);
1632                 free(rstr);
1633                 return result;
1634         }
1635 #endif
1636
1637 /* from zero-divisor-p */
1638 #ifdef HAVE_RESCLASS
1639         case RESC_ELM_T: {
1640                 bigz bz;
1641
1642                 bigz_init(bz);
1643                 if (mpz_invert(bz, XRESC_ELM_DATA(number),
1644                                XRESC_RNG_DATA(XRESC_ELM_RING(number))))
1645                         result = Qnil;
1646                 else
1647                         result = Qt;
1648
1649                 bigz_fini(bz);
1650                 break;
1651         }
1652 #endif
1653
1654 \f
1655 /* initialiser code */
1656 #define EMODNAME        ase_resclass
1657
1658 static inline void
1659 ase_resclass_binary_optable_init(void)
1660 {
1661         ent_resclass_nullary_optable_init();
1662         ent_resclass_unary_optable_init();
1663         ent_resclass_binary_optable_init();
1664         ent_resclass_unary_reltable_init();
1665         ent_resclass_binary_reltable_init();
1666         ent_resclass_lifttable_init();
1667 }
1668
1669 void
1670 EMOD_PUBINIT(void)
1671 {
1672         DEFSUBR(Fmake_residue_class_ring);
1673         DEFSUBR(Fmake_residue_class);
1674         DEFSUBR(Fresidue_class_ring);
1675 #if 0
1676         DEFSUBR(Fresidue_class_modulus);
1677         DEFSUBR(Fresidue_class_representant);
1678 #endif
1679         DEFSUBR(Fresidue_class_ring_p);
1680         DEFSUBR(Fresidue_class_p);
1681
1682         DEFSYMBOL(Qase_resclass);
1683         DEFASETYPE_WITH_OPS(Qase_resc_rng, "ase:residue-class-ring");
1684         defsymbol(&Qase_resc_rng_p, "ase:residue-class-ring-p");
1685         DEFASETYPE_WITH_OPS(Qase_resc_elm, "ase:residue-class");
1686         defsymbol(&Qase_resc_elm_p, "ase:residue-class-p");
1687
1688         ase_resclass_binary_optable_init();
1689
1690         Fprovide(Qase_resclass);
1691         Fprovide(intern("resclass"));
1692
1693         EMOD_PUBREINIT();
1694 }
1695
1696 void
1697 EMOD_PUBREINIT(void)
1698 {
1699         sane_small = (snprintf(NULL, 0, "%ld", EMACS_INT_MAX) + 7) & -3;
1700         /* defined in lread.c, declared in ent.h */
1701         ase_resc_rng_pred_f = ase_resc_rng_string_p;
1702         ase_resc_rng_f = ase_resc_rng_from_string;
1703         ase_resc_elm_pred_f = ase_resc_elm_string_p;
1704         ase_resc_elm_f = ase_resc_elm_from_string;
1705 }
1706
1707 void
1708 EMOD_PUBDEINIT(void)
1709 {
1710         Frevoke(Qase_resclass);
1711         Frevoke(intern("resclass"));
1712 }
1713
1714 /* ent-resclass.c ends here */