]> www.ginac.de Git - cln.git/blob - include/cl_ring.h
Make @exec_prefix@ usable in shell scripts.
[cln.git] / include / cl_ring.h
1 // Ring operations.
2
3 #ifndef _CL_RING_H
4 #define _CL_RING_H
5
6 #include "cl_object.h"
7 #include "cl_malloc.h"
8 #include "cl_proplist.h"
9 #include "cl_number.h"
10 #include "cl_io.h"
11 class cl_I;
12
13 // This file defines the general layout of rings, ring elements, and
14 // operations available on ring elements. Any subclass of `cl_ring'
15 // must implement these operations, with the same memory layout.
16 // (Because generic packages like the polynomial rings access the base
17 // ring's operation vectors through inline functions defined in this file.)
18
19 class cl_heap_ring;
20
21 // Rings are reference counted, but not freed immediately when they aren't
22 // used any more. Hence they inherit from `cl_rcpointer'.
23
24 // Vectors of function pointers are more efficient than virtual member
25 // functions. But it constrains us not to use multiple or virtual inheritance.
26 //
27 // Note! We are passing raw `cl_heap_ring*' pointers to the operations
28 // for efficiency (compared to passing `const cl_ring&', we save a memory
29 // access, and it is easier to cast to a `cl_heap_ring_specialized*').
30 // These raw pointers are meant to be used downward (in the dynamic extent
31 // of the call) only. If you need to save them in a data structure, cast
32 // to `cl_ring'; this will correctly increment the reference count.
33 // (This technique is safe because the inline wrapper functions make sure
34 // that we have a `cl_ring' somewhere containing the pointer, so there
35 // is no danger of dangling pointers.)
36 //
37 // Note! Because the `cl_heap_ring*' -> `cl_ring' conversion increments
38 // the reference count, you have to use the `cl_private_thing' -> `cl_ring'
39 // conversion if the reference count is already incremented.
40
41 class cl_ring : public cl_rcpointer {
42 public:
43         // Constructor. Takes a cl_heap_ring*, increments its refcount.
44         cl_ring (cl_heap_ring* r);
45         // Private constructor. Doesn't increment the refcount.
46         cl_ring (cl_private_thing);
47         // Copy constructor.
48         cl_ring (const cl_ring&);
49         // Assignment operator.
50         cl_ring& operator= (const cl_ring&);
51         // Default constructor.
52         cl_ring ();
53         // Automatic dereferencing.
54         cl_heap_ring* operator-> () const
55         { return (cl_heap_ring*)heappointer; }
56 };
57 CL_DEFINE_COPY_CONSTRUCTOR2(cl_ring,cl_rcpointer)
58 CL_DEFINE_ASSIGNMENT_OPERATOR(cl_ring,cl_ring)
59
60 // Normal constructor for `cl_ring'.
61 inline cl_ring::cl_ring (cl_heap_ring* r)
62 { cl_inc_pointer_refcount((cl_heap*)r); pointer = r; }
63 // Private constructor for `cl_ring'.
64 inline cl_ring::cl_ring (cl_private_thing p)
65 { pointer = p; }
66
67 inline bool operator== (const cl_ring& R1, const cl_ring& R2)
68 { return (R1.pointer == R2.pointer); }
69 inline bool operator!= (const cl_ring& R1, const cl_ring& R2)
70 { return (R1.pointer != R2.pointer); }
71 inline bool operator== (const cl_ring& R1, cl_heap_ring* R2)
72 { return (R1.pointer == R2); }
73 inline bool operator!= (const cl_ring& R1, cl_heap_ring* R2)
74 { return (R1.pointer != R2); }
75
76 // Representation of an element of a ring.
77 //
78 // In order to support true polymorphism (without C++ templates), all
79 // ring elements share the same basic layout:
80 //      cl_ring ring;     // the ring
81 //      cl_gcobject rep;  // representation of the element
82 // The representation of the element depends on the ring, of course,
83 // but we constrain it to be a single pointer into the heap or an immediate
84 // value.
85 //
86 // Any arithmetic operation on a ring R (like +, -, *) must return a value
87 // with ring = R. This is
88 // a. necessary if the computation is to proceed correctly (e.g. in cl_RA,
89 //    ((3/4)*4 mod 3) is 0, simplifying it to ((cl_I)4 mod (cl_I)3) = 1
90 //    wouldn't be correct),
91 // b. possible even if R is an extension ring of some ring R1 (e.g. cl_N
92 //    being an extension ring of cl_R). Automatic retraction from R to R1
93 //    can be done through dynamic typing: An element of R which happens
94 //    to lie in R1 is stored using the internal representation of R1,
95 //    but with ring = R. Elements of R1 and R\R1 can be distinguished
96 //    through rep's type.
97 // c. an advantage for the implementation of polynomials and other
98 //    entities which contain many elements of the same ring. They need
99 //    to store only the elements' representations, and a single pointer
100 //    to the ring.
101 //
102 // The ring operations exist in two versions:
103 // - Low-level version, which only operates on the representation.
104 // - High-level version, which operates on full cl_ring_elements.
105 // We make this distinction for performance: Multiplication of polynomials
106 // over Z/nZ, operating on the high-level operations, spends 40% of its
107 // computing time with packing and unpacking of cl_ring_elements.
108 // The low-level versions have an underscore prepended and are unsafe.
109
110 class _cl_ring_element {
111 public:
112         cl_gcobject rep;        // representation of the element
113         // Default constructor.
114         _cl_ring_element ();
115 public: /* ugh */
116         // Constructor.
117         _cl_ring_element (const cl_heap_ring* R, const cl_gcobject& r) : rep (as_cl_private_thing(r)) { (void)R; }
118         _cl_ring_element (const cl_ring& R, const cl_gcobject& r) : rep (as_cl_private_thing(r)) { (void)R; }
119 public: // Ability to place an object at a given address.
120         void* operator new (size_t size) { return cl_malloc_hook(size); }
121         void* operator new (size_t size, _cl_ring_element* ptr) { (void)size; return ptr; }
122         void operator delete (void* ptr) { cl_free_hook(ptr); }
123 };
124
125 class cl_ring_element : public _cl_ring_element {
126 protected:
127         cl_ring _ring;                  // ring
128 public:
129         const cl_ring& ring () const { return _ring; }
130         // Default constructor.
131         cl_ring_element ();
132 public: /* ugh */
133         // Constructor.
134         cl_ring_element (const cl_ring& R, const cl_gcobject& r) : _cl_ring_element (R,r), _ring (R) {}
135         cl_ring_element (const cl_ring& R, const _cl_ring_element& r) : _cl_ring_element (r), _ring (R) {}
136 public: // Debugging output.
137         void debug_print () const;
138         // Ability to place an object at a given address.
139         void* operator new (size_t size) { return cl_malloc_hook(size); }
140         void* operator new (size_t size, cl_ring_element* ptr) { (void)size; return ptr; }
141         void operator delete (void* ptr) { cl_free_hook(ptr); }
142 };
143
144 // The ring operations are encoded as vectors of function pointers. You
145 // can add more operations to the end of each vector or add new vectors,
146 // but you must not reorder the operations nor reorder the vectors nor
147 // change the functions' signatures incompatibly.
148
149 // There should ideally be a template class for each vector, but unfortunately
150 // you lose the ability to initialize the vector using "= { ... }" syntax
151 // when you subclass it.
152
153 struct _cl_ring_setops {
154         // print
155         void (* fprint) (cl_heap_ring* R, cl_ostream stream, const _cl_ring_element& x);
156         // equality
157         cl_boolean (* equal) (cl_heap_ring* R, const _cl_ring_element& x, const _cl_ring_element& y);
158         // ...
159 };
160 struct _cl_ring_addops {
161         // 0
162         const _cl_ring_element (* zero) (cl_heap_ring* R);
163         cl_boolean (* zerop) (cl_heap_ring* R, const _cl_ring_element& x);
164         // x+y
165         const _cl_ring_element (* plus) (cl_heap_ring* R, const _cl_ring_element& x, const _cl_ring_element& y);
166         // x-y
167         const _cl_ring_element (* minus) (cl_heap_ring* R, const _cl_ring_element& x, const _cl_ring_element& y);
168         // -x
169         const _cl_ring_element (* uminus) (cl_heap_ring* R, const _cl_ring_element& x);
170         // ...
171 };
172 struct _cl_ring_mulops {
173         // 1
174         const _cl_ring_element (* one) (cl_heap_ring* R);
175         // canonical homomorphism
176         const _cl_ring_element (* canonhom) (cl_heap_ring* R, const cl_I& x);
177         // x*y
178         const _cl_ring_element (* mul) (cl_heap_ring* R, const _cl_ring_element& x, const _cl_ring_element& y);
179         // x^2
180         const _cl_ring_element (* square) (cl_heap_ring* R, const _cl_ring_element& x);
181         // x^y, y Integer >0
182         const _cl_ring_element (* expt_pos) (cl_heap_ring* R, const _cl_ring_element& x, const cl_I& y);
183         // ...
184 };
185 #if defined(__GNUC__) && (__GNUC__ == 2) && (__GNUC_MINOR__ < 8) // workaround two g++-2.7.0 bugs
186   #define cl_ring_setops  _cl_ring_setops
187   #define cl_ring_addops  _cl_ring_addops
188   #define cl_ring_mulops  _cl_ring_mulops
189 #else
190   typedef const _cl_ring_setops  cl_ring_setops;
191   typedef const _cl_ring_addops  cl_ring_addops;
192   typedef const _cl_ring_mulops  cl_ring_mulops;
193 #endif
194
195 // Representation of a ring in memory.
196
197 class cl_heap_ring : public cl_heap {
198 public:
199         // Allocation.
200         void* operator new (size_t size) { return cl_malloc_hook(size); }
201         // Deallocation.
202         void operator delete (void* ptr) { cl_free_hook(ptr); }
203 private:
204         cl_property_list properties;
205 protected:
206         cl_ring_setops* setops;
207         cl_ring_addops* addops;
208         cl_ring_mulops* mulops;
209 public:
210         // More information comes here.
211         // ...
212 public:
213         // Low-level operations.
214         void _fprint (cl_ostream stream, const _cl_ring_element& x)
215                 { setops->fprint(this,stream,x); }
216         cl_boolean _equal (const _cl_ring_element& x, const _cl_ring_element& y)
217                 { return setops->equal(this,x,y); }
218         const _cl_ring_element _zero ()
219                 { return addops->zero(this); }
220         cl_boolean _zerop (const _cl_ring_element& x)
221                 { return addops->zerop(this,x); }
222         const _cl_ring_element _plus (const _cl_ring_element& x, const _cl_ring_element& y)
223                 { return addops->plus(this,x,y); }
224         const _cl_ring_element _minus (const _cl_ring_element& x, const _cl_ring_element& y)
225                 { return addops->minus(this,x,y); }
226         const _cl_ring_element _uminus (const _cl_ring_element& x)
227                 { return addops->uminus(this,x); }
228         const _cl_ring_element _one ()
229                 { return mulops->one(this); }
230         const _cl_ring_element _canonhom (const cl_I& x)
231                 { return mulops->canonhom(this,x); }
232         const _cl_ring_element _mul (const _cl_ring_element& x, const _cl_ring_element& y)
233                 { return mulops->mul(this,x,y); }
234         const _cl_ring_element _square (const _cl_ring_element& x)
235                 { return mulops->square(this,x); }
236         const _cl_ring_element _expt_pos (const _cl_ring_element& x, const cl_I& y)
237                 { return mulops->expt_pos(this,x,y); }
238         // High-level operations.
239         void fprint (cl_ostream stream, const cl_ring_element& x)
240         {
241                 if (!(x.ring() == this)) cl_abort();
242                 _fprint(stream,x);
243         }
244         cl_boolean equal (const cl_ring_element& x, const cl_ring_element& y)
245         {
246                 if (!(x.ring() == this)) cl_abort();
247                 if (!(y.ring() == this)) cl_abort();
248                 return _equal(x,y);
249         }
250         const cl_ring_element zero ()
251         {
252                 return cl_ring_element(this,_zero());
253         }
254         cl_boolean zerop (const cl_ring_element& x)
255         {
256                 if (!(x.ring() == this)) cl_abort();
257                 return _zerop(x);
258         }
259         const cl_ring_element plus (const cl_ring_element& x, const cl_ring_element& y)
260         {
261                 if (!(x.ring() == this)) cl_abort();
262                 if (!(y.ring() == this)) cl_abort();
263                 return cl_ring_element(this,_plus(x,y));
264         }
265         const cl_ring_element minus (const cl_ring_element& x, const cl_ring_element& y)
266         {
267                 if (!(x.ring() == this)) cl_abort();
268                 if (!(y.ring() == this)) cl_abort();
269                 return cl_ring_element(this,_minus(x,y));
270         }
271         const cl_ring_element uminus (const cl_ring_element& x)
272         {
273                 if (!(x.ring() == this)) cl_abort();
274                 return cl_ring_element(this,_uminus(x));
275         }
276         const cl_ring_element one ()
277         {
278                 return cl_ring_element(this,_one());
279         }
280         const cl_ring_element canonhom (const cl_I& x)
281         {
282                 return cl_ring_element(this,_canonhom(x));
283         }
284         const cl_ring_element mul (const cl_ring_element& x, const cl_ring_element& y)
285         {
286                 if (!(x.ring() == this)) cl_abort();
287                 if (!(y.ring() == this)) cl_abort();
288                 return cl_ring_element(this,_mul(x,y));
289         }
290         const cl_ring_element square (const cl_ring_element& x)
291         {
292                 if (!(x.ring() == this)) cl_abort();
293                 return cl_ring_element(this,_square(x));
294         }
295         const cl_ring_element expt_pos (const cl_ring_element& x, const cl_I& y)
296         {
297                 if (!(x.ring() == this)) cl_abort();
298                 return cl_ring_element(this,_expt_pos(x,y));
299         }
300         // Property operations.
301         cl_property* get_property (const cl_symbol& key)
302                 { return properties.get_property(key); }
303         void add_property (cl_property* new_property)
304                 { properties.add_property(new_property); }
305 // Constructor.
306         cl_heap_ring (cl_ring_setops* setopv, cl_ring_addops* addopv, cl_ring_mulops* mulopv)
307                 : setops (setopv), addops (addopv), mulops (mulopv)
308                 { refcount = 0; } // will be incremented by the `cl_ring' constructor
309 };
310 #define SUBCLASS_cl_heap_ring() \
311 public:                                                                   \
312         /* Allocation. */                                                 \
313         void* operator new (size_t size) { return cl_malloc_hook(size); } \
314         /* Deallocation. */                                               \
315         void operator delete (void* ptr) { cl_free_hook(ptr); }
316
317 // Operations on ring elements.
318
319 // Output.
320 inline void fprint (cl_ostream stream, const cl_ring_element& x)
321         { x.ring()->fprint(stream,x); }
322 CL_DEFINE_PRINT_OPERATOR(cl_ring_element)
323
324 // Add.
325 inline const cl_ring_element operator+ (const cl_ring_element& x, const cl_ring_element& y)
326         { return x.ring()->plus(x,y); }
327
328 // Negate.
329 inline const cl_ring_element operator- (const cl_ring_element& x)
330         { return x.ring()->uminus(x); }
331
332 // Subtract.
333 inline const cl_ring_element operator- (const cl_ring_element& x, const cl_ring_element& y)
334         { return x.ring()->minus(x,y); }
335
336 // Equality.
337 inline bool operator== (const cl_ring_element& x, const cl_ring_element& y)
338         { return x.ring()->equal(x,y); }
339 inline bool operator!= (const cl_ring_element& x, const cl_ring_element& y)
340         { return !x.ring()->equal(x,y); }
341
342 // Compare against 0.
343 inline cl_boolean zerop (const cl_ring_element& x)
344         { return x.ring()->zerop(x); }
345
346 // Multiply.
347 inline const cl_ring_element operator* (const cl_ring_element& x, const cl_ring_element& y)
348         { return x.ring()->mul(x,y); }
349
350 // Squaring.
351 inline const cl_ring_element square (const cl_ring_element& x)
352         { return x.ring()->square(x); }
353
354 // Exponentiation x^y, where y > 0.
355 inline const cl_ring_element expt_pos (const cl_ring_element& x, const cl_I& y)
356         { return x.ring()->expt_pos(x,y); }
357
358 // Scalar multiplication.
359 // [Is this operation worth being specially optimized for the case of
360 // polynomials?? Polynomials have a faster scalar multiplication.
361 // We should use it.??]
362 inline const cl_ring_element operator* (const cl_I& x, const cl_ring_element& y)
363         { return y.ring()->mul(y.ring()->canonhom(x),y); }
364 inline const cl_ring_element operator* (const cl_ring_element& x, const cl_I& y)
365         { return x.ring()->mul(x.ring()->canonhom(y),x); }
366
367
368 // Ring of uninitialized elements.
369 // Any operation results in a run-time error.
370
371 extern const cl_ring cl_no_ring;
372 extern cl_class cl_class_no_ring;
373 CL_REQUIRE(cl_no_ring)
374
375 inline cl_ring::cl_ring ()
376         : cl_rcpointer (as_cl_private_thing(cl_no_ring)) {}
377 inline _cl_ring_element::_cl_ring_element ()
378         : rep ((cl_private_thing) cl_combine(cl_FN_tag,0)) {}
379 inline cl_ring_element::cl_ring_element ()
380         : _cl_ring_element (), _ring () {}
381
382
383 // Support for built-in number rings.
384 // Beware, they are not optimally efficient.
385
386 template <class T>
387 struct cl_number_ring_ops {
388         cl_boolean (* contains) (const cl_number&);
389         cl_boolean (* equal) (const T&, const T&);
390         cl_boolean (* zerop) (const T&);
391         const T (* plus) (const T&, const T&);
392         const T (* minus) (const T&, const T&);
393         const T (* uminus) (const T&);
394         const T (* mul) (const T&, const T&);
395         const T (* square) (const T&);
396         const T (* expt_pos) (const T&, const cl_I&);
397 };
398 class cl_heap_number_ring : public cl_heap_ring {
399 public:
400         cl_number_ring_ops<cl_number>* ops;
401         // Constructor.
402         cl_heap_number_ring (cl_ring_setops* setopv, cl_ring_addops* addopv, cl_ring_mulops* mulopv, cl_number_ring_ops<cl_number>* opv)
403                 : cl_heap_ring (setopv,addopv,mulopv), ops (opv) {}
404 };
405
406 class cl_number_ring : public cl_ring {
407 public:
408         cl_number_ring (cl_heap_number_ring* r)
409                 : cl_ring (r) {}
410 };
411
412 template <class T>
413 class cl_specialized_number_ring : public cl_number_ring {
414 public:
415         cl_specialized_number_ring ();
416 };
417
418 // Type test.
419 inline cl_boolean instanceof (const cl_number& x, const cl_number_ring& R)
420 {
421         return ((cl_heap_number_ring*) R.heappointer)->ops->contains(x);
422 }
423
424
425 // Hack section.
426
427 // Conversions to subtypes without checking:
428 // The2(cl_MI)(x) converts x to a cl_MI, without change of representation!
429   #define The(type)  *(const type *) & cl_identity
430   #define The2(type)  *(const type *) & cl_identity2
431 // This inline function is for type checking purposes only.
432   inline const cl_ring& cl_identity (const cl_ring& r) { return r; }
433   inline const cl_ring_element& cl_identity2 (const cl_ring_element& x) { return x; }
434   inline const cl_gcobject& cl_identity (const _cl_ring_element& x) { return x.rep; }
435
436
437 // Debugging support.
438 #ifdef CL_DEBUG
439 extern int cl_ring_debug_module;
440 static void* const cl_ring_debug_dummy[] = { &cl_ring_debug_dummy,
441         &cl_ring_debug_module
442 };
443 #endif
444
445
446 #endif /* _CL_RING_H */