Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-19 08:08:32

0001 // Ring operations.
0002 
0003 #ifndef _CL_RING_H
0004 #define _CL_RING_H
0005 
0006 #include "cln/object.h"
0007 #include "cln/malloc.h"
0008 #include "cln/proplist.h"
0009 #include "cln/number.h"
0010 #include "cln/exception.h"
0011 #include "cln/io.h"
0012 
0013 namespace cln {
0014 
0015 class cl_I;
0016 
0017 // This file defines the general layout of rings, ring elements, and
0018 // operations available on ring elements. Any subclass of `cl_ring'
0019 // must implement these operations, with the same memory layout.
0020 // (Because generic packages like the polynomial rings access the base
0021 // ring's operation vectors through inline functions defined in this file.)
0022 
0023 class cl_heap_ring;
0024 
0025 // Rings are reference counted, but not freed immediately when they aren't
0026 // used any more. Hence they inherit from `cl_rcpointer'.
0027 
0028 // Vectors of function pointers are more efficient than virtual member
0029 // functions. But it constrains us not to use multiple or virtual inheritance.
0030 //
0031 // Note! We are passing raw `cl_heap_ring*' pointers to the operations
0032 // for efficiency (compared to passing `const cl_ring&', we save a memory
0033 // access, and it is easier to cast to a `cl_heap_ring_specialized*').
0034 // These raw pointers are meant to be used downward (in the dynamic extent
0035 // of the call) only. If you need to save them in a data structure, cast
0036 // to `cl_ring'; this will correctly increment the reference count.
0037 // (This technique is safe because the inline wrapper functions make sure
0038 // that we have a `cl_ring' somewhere containing the pointer, so there
0039 // is no danger of dangling pointers.)
0040 //
0041 // Note! Because the `cl_heap_ring*' -> `cl_ring' conversion increments
0042 // the reference count, you have to use the `cl_private_thing' -> `cl_ring'
0043 // conversion if the reference count is already incremented.
0044 
0045 class cl_ring : public cl_rcpointer {
0046 public:
0047     // Constructor. Takes a cl_heap_ring*, increments its refcount.
0048     cl_ring (cl_heap_ring* r);
0049     // Private constructor. Doesn't increment the refcount.
0050     cl_ring (cl_private_thing);
0051     // Copy constructor.
0052     cl_ring (const cl_ring&);
0053     // Assignment operator.
0054     cl_ring& operator= (const cl_ring&);
0055     // Default constructor.
0056     cl_ring ();
0057     // Automatic dereferencing.
0058     cl_heap_ring* operator-> () const
0059     { return (cl_heap_ring*)heappointer; }
0060 };
0061 CL_DEFINE_COPY_CONSTRUCTOR2(cl_ring,cl_rcpointer)
0062 CL_DEFINE_ASSIGNMENT_OPERATOR(cl_ring,cl_ring)
0063 
0064 // Normal constructor for `cl_ring'.
0065 inline cl_ring::cl_ring (cl_heap_ring* r)
0066 { cl_inc_pointer_refcount((cl_heap*)r); pointer = r; }
0067 // Private constructor for `cl_ring'.
0068 inline cl_ring::cl_ring (cl_private_thing p)
0069 { pointer = p; }
0070 
0071 inline bool operator== (const cl_ring& R1, const cl_ring& R2)
0072 { return (R1.pointer == R2.pointer); }
0073 inline bool operator!= (const cl_ring& R1, const cl_ring& R2)
0074 { return (R1.pointer != R2.pointer); }
0075 inline bool operator== (const cl_ring& R1, cl_heap_ring* R2)
0076 { return (R1.pointer == R2); }
0077 inline bool operator!= (const cl_ring& R1, cl_heap_ring* R2)
0078 { return (R1.pointer != R2); }
0079 
0080 // Representation of an element of a ring.
0081 //
0082 // In order to support true polymorphism (without C++ templates), all
0083 // ring elements share the same basic layout:
0084 //      cl_ring ring;     // the ring
0085 //      cl_gcobject rep;  // representation of the element
0086 // The representation of the element depends on the ring, of course,
0087 // but we constrain it to be a single pointer into the heap or an immediate
0088 // value.
0089 //
0090 // Any arithmetic operation on a ring R (like +, -, *) must return a value
0091 // with ring = R. This is
0092 // a. necessary if the computation is to proceed correctly (e.g. in cl_RA,
0093 //    ((3/4)*4 mod 3) is 0, simplifying it to ((cl_I)4 mod (cl_I)3) = 1
0094 //    wouldn't be correct),
0095 // b. possible even if R is an extension ring of some ring R1 (e.g. cl_N
0096 //    being an extension ring of cl_R). Automatic retraction from R to R1
0097 //    can be done through dynamic typing: An element of R which happens
0098 //    to lie in R1 is stored using the internal representation of R1,
0099 //    but with ring = R. Elements of R1 and R\R1 can be distinguished
0100 //    through rep's type.
0101 // c. an advantage for the implementation of polynomials and other
0102 //    entities which contain many elements of the same ring. They need
0103 //    to store only the elements' representations, and a single pointer
0104 //    to the ring.
0105 //
0106 // The ring operations exist in two versions:
0107 // - Low-level version, which only operates on the representation.
0108 // - High-level version, which operates on full cl_ring_elements.
0109 // We make this distinction for performance: Multiplication of polynomials
0110 // over Z/nZ, operating on the high-level operations, spends 40% of its
0111 // computing time with packing and unpacking of cl_ring_elements.
0112 // The low-level versions have an underscore prepended and are unsafe.
0113 
0114 class _cl_ring_element {
0115 public:
0116     cl_gcobject rep;    // representation of the element
0117     // Default constructor.
0118     _cl_ring_element ();
0119 public: /* ugh */
0120     // Constructor.
0121     _cl_ring_element (const cl_heap_ring* R, const cl_gcobject& r) : rep (as_cl_private_thing(r)) { (void)R; }
0122     _cl_ring_element (const cl_ring& R, const cl_gcobject& r) : rep (as_cl_private_thing(r)) { (void)R; }
0123 public: // Ability to place an object at a given address.
0124     void* operator new (size_t size) { return malloc_hook(size); }
0125     void* operator new (size_t size, void* ptr) { (void)size; return ptr; }
0126     void operator delete (void* ptr) { free_hook(ptr); }
0127 };
0128 
0129 class cl_ring_element : public _cl_ring_element {
0130 protected:
0131     cl_ring _ring;          // ring
0132 public:
0133     const cl_ring& ring () const { return _ring; }
0134     // Default constructor.
0135     cl_ring_element ();
0136 public: /* ugh */
0137     // Constructor.
0138     cl_ring_element (const cl_ring& R, const cl_gcobject& r) : _cl_ring_element (R,r), _ring (R) {}
0139     cl_ring_element (const cl_ring& R, const _cl_ring_element& r) : _cl_ring_element (r), _ring (R) {}
0140 public: // Debugging output.
0141     void debug_print () const;
0142     // Ability to place an object at a given address.
0143     void* operator new (size_t size) { return malloc_hook(size); }
0144     void* operator new (size_t size, void* ptr) { (void)size; return ptr; }
0145     void operator delete (void* ptr) { free_hook(ptr); }
0146 };
0147 
0148 // The ring operations are encoded as vectors of function pointers. You
0149 // can add more operations to the end of each vector or add new vectors,
0150 // but you must not reorder the operations nor reorder the vectors nor
0151 // change the functions' signatures incompatibly.
0152 
0153 // There should ideally be a template class for each vector, but unfortunately
0154 // you lose the ability to initialize the vector using "= { ... }" syntax
0155 // when you subclass it.
0156 
0157 struct _cl_ring_setops {
0158     // print
0159     void (* fprint) (cl_heap_ring* R, std::ostream& stream, const _cl_ring_element& x);
0160     // equality
0161     bool (* equal) (cl_heap_ring* R, const _cl_ring_element& x, const _cl_ring_element& y);
0162     // ...
0163 };
0164 struct _cl_ring_addops {
0165     // 0
0166     const _cl_ring_element (* zero) (cl_heap_ring* R);
0167     bool (* zerop) (cl_heap_ring* R, const _cl_ring_element& x);
0168     // x+y
0169     const _cl_ring_element (* plus) (cl_heap_ring* R, const _cl_ring_element& x, const _cl_ring_element& y);
0170     // x-y
0171     const _cl_ring_element (* minus) (cl_heap_ring* R, const _cl_ring_element& x, const _cl_ring_element& y);
0172     // -x
0173     const _cl_ring_element (* uminus) (cl_heap_ring* R, const _cl_ring_element& x);
0174     // ...
0175 };
0176 struct _cl_ring_mulops {
0177     // 1
0178     const _cl_ring_element (* one) (cl_heap_ring* R);
0179     // canonical homomorphism
0180     const _cl_ring_element (* canonhom) (cl_heap_ring* R, const cl_I& x);
0181     // x*y
0182     const _cl_ring_element (* mul) (cl_heap_ring* R, const _cl_ring_element& x, const _cl_ring_element& y);
0183     // x^2
0184     const _cl_ring_element (* square) (cl_heap_ring* R, const _cl_ring_element& x);
0185     // x^y, y Integer >0
0186     const _cl_ring_element (* expt_pos) (cl_heap_ring* R, const _cl_ring_element& x, const cl_I& y);
0187     // ...
0188 };
0189   typedef const _cl_ring_setops  cl_ring_setops;
0190   typedef const _cl_ring_addops  cl_ring_addops;
0191   typedef const _cl_ring_mulops  cl_ring_mulops;
0192 
0193 // Representation of a ring in memory.
0194 
0195 class cl_heap_ring : public cl_heap {
0196 public:
0197     // Allocation.
0198     void* operator new (size_t size) { return malloc_hook(size); }
0199     // Deallocation.
0200     void operator delete (void* ptr) { free_hook(ptr); }
0201 private:
0202     cl_property_list properties;
0203 protected:
0204     cl_ring_setops* setops;
0205     cl_ring_addops* addops;
0206     cl_ring_mulops* mulops;
0207 public:
0208     // More information comes here.
0209     // ...
0210 public:
0211     // Low-level operations.
0212     void _fprint (std::ostream& stream, const _cl_ring_element& x)
0213         { setops->fprint(this,stream,x); }
0214     bool _equal (const _cl_ring_element& x, const _cl_ring_element& y)
0215         { return setops->equal(this,x,y); }
0216     const _cl_ring_element _zero ()
0217         { return addops->zero(this); }
0218     bool _zerop (const _cl_ring_element& x)
0219         { return addops->zerop(this,x); }
0220     const _cl_ring_element _plus (const _cl_ring_element& x, const _cl_ring_element& y)
0221         { return addops->plus(this,x,y); }
0222     const _cl_ring_element _minus (const _cl_ring_element& x, const _cl_ring_element& y)
0223         { return addops->minus(this,x,y); }
0224     const _cl_ring_element _uminus (const _cl_ring_element& x)
0225         { return addops->uminus(this,x); }
0226     const _cl_ring_element _one ()
0227         { return mulops->one(this); }
0228     const _cl_ring_element _canonhom (const cl_I& x)
0229         { return mulops->canonhom(this,x); }
0230     const _cl_ring_element _mul (const _cl_ring_element& x, const _cl_ring_element& y)
0231         { return mulops->mul(this,x,y); }
0232     const _cl_ring_element _square (const _cl_ring_element& x)
0233         { return mulops->square(this,x); }
0234     const _cl_ring_element _expt_pos (const _cl_ring_element& x, const cl_I& y)
0235         { return mulops->expt_pos(this,x,y); }
0236     // High-level operations.
0237     void fprint (std::ostream& stream, const cl_ring_element& x)
0238     {
0239         if (!(x.ring() == this)) throw runtime_exception();
0240         _fprint(stream,x);
0241     }
0242     bool equal (const cl_ring_element& x, const cl_ring_element& y)
0243     {
0244         if (!(x.ring() == this)) throw runtime_exception();
0245         if (!(y.ring() == this)) throw runtime_exception();
0246         return _equal(x,y);
0247     }
0248     const cl_ring_element zero ()
0249     {
0250         return cl_ring_element(this,_zero());
0251     }
0252     bool zerop (const cl_ring_element& x)
0253     {
0254         if (!(x.ring() == this)) throw runtime_exception();
0255         return _zerop(x);
0256     }
0257     const cl_ring_element plus (const cl_ring_element& x, const cl_ring_element& y)
0258     {
0259         if (!(x.ring() == this)) throw runtime_exception();
0260         if (!(y.ring() == this)) throw runtime_exception();
0261         return cl_ring_element(this,_plus(x,y));
0262     }
0263     const cl_ring_element minus (const cl_ring_element& x, const cl_ring_element& y)
0264     {
0265         if (!(x.ring() == this)) throw runtime_exception();
0266         if (!(y.ring() == this)) throw runtime_exception();
0267         return cl_ring_element(this,_minus(x,y));
0268     }
0269     const cl_ring_element uminus (const cl_ring_element& x)
0270     {
0271         if (!(x.ring() == this)) throw runtime_exception();
0272         return cl_ring_element(this,_uminus(x));
0273     }
0274     const cl_ring_element one ()
0275     {
0276         return cl_ring_element(this,_one());
0277     }
0278     const cl_ring_element canonhom (const cl_I& x)
0279     {
0280         return cl_ring_element(this,_canonhom(x));
0281     }
0282     const cl_ring_element mul (const cl_ring_element& x, const cl_ring_element& y)
0283     {
0284         if (!(x.ring() == this)) throw runtime_exception();
0285         if (!(y.ring() == this)) throw runtime_exception();
0286         return cl_ring_element(this,_mul(x,y));
0287     }
0288     const cl_ring_element square (const cl_ring_element& x)
0289     {
0290         if (!(x.ring() == this)) throw runtime_exception();
0291         return cl_ring_element(this,_square(x));
0292     }
0293     const cl_ring_element expt_pos (const cl_ring_element& x, const cl_I& y)
0294     {
0295         if (!(x.ring() == this)) throw runtime_exception();
0296         return cl_ring_element(this,_expt_pos(x,y));
0297     }
0298     // Property operations.
0299     cl_property* get_property (const cl_symbol& key)
0300         { return properties.get_property(key); }
0301     void add_property (cl_property* new_property)
0302         { properties.add_property(new_property); }
0303 // Constructor.
0304     cl_heap_ring (cl_ring_setops* setopv, cl_ring_addops* addopv, cl_ring_mulops* mulopv)
0305         : setops (setopv), addops (addopv), mulops (mulopv)
0306         { refcount = 0; } // will be incremented by the `cl_ring' constructor
0307 };
0308 #define SUBCLASS_cl_heap_ring() \
0309 public:                                   \
0310     /* Allocation. */                         \
0311     void* operator new (size_t size) { return malloc_hook(size); } \
0312     /* Deallocation. */                       \
0313     void operator delete (void* ptr) { free_hook(ptr); }
0314 
0315 // Operations on ring elements.
0316 
0317 // Output.
0318 inline void fprint (std::ostream& stream, const cl_ring_element& x)
0319     { x.ring()->fprint(stream,x); }
0320 CL_DEFINE_PRINT_OPERATOR(cl_ring_element)
0321 
0322 // Add.
0323 inline const cl_ring_element operator+ (const cl_ring_element& x, const cl_ring_element& y)
0324     { return x.ring()->plus(x,y); }
0325 
0326 // Negate.
0327 inline const cl_ring_element operator- (const cl_ring_element& x)
0328     { return x.ring()->uminus(x); }
0329 
0330 // Subtract.
0331 inline const cl_ring_element operator- (const cl_ring_element& x, const cl_ring_element& y)
0332     { return x.ring()->minus(x,y); }
0333 
0334 // Equality.
0335 inline bool operator== (const cl_ring_element& x, const cl_ring_element& y)
0336     { return x.ring()->equal(x,y); }
0337 inline bool operator!= (const cl_ring_element& x, const cl_ring_element& y)
0338     { return !x.ring()->equal(x,y); }
0339 
0340 // Compare against 0.
0341 inline bool zerop (const cl_ring_element& x)
0342     { return x.ring()->zerop(x); }
0343 
0344 // Multiply.
0345 inline const cl_ring_element operator* (const cl_ring_element& x, const cl_ring_element& y)
0346     { return x.ring()->mul(x,y); }
0347 
0348 // Squaring.
0349 inline const cl_ring_element square (const cl_ring_element& x)
0350     { return x.ring()->square(x); }
0351 
0352 // Exponentiation x^y, where y > 0.
0353 inline const cl_ring_element expt_pos (const cl_ring_element& x, const cl_I& y)
0354     { return x.ring()->expt_pos(x,y); }
0355 
0356 // Scalar multiplication.
0357 // [Is this operation worth being specially optimized for the case of
0358 // polynomials?? Polynomials have a faster scalar multiplication.
0359 // We should use it.??]
0360 inline const cl_ring_element operator* (const cl_I& x, const cl_ring_element& y)
0361     { return y.ring()->mul(y.ring()->canonhom(x),y); }
0362 inline const cl_ring_element operator* (const cl_ring_element& x, const cl_I& y)
0363     { return x.ring()->mul(x.ring()->canonhom(y),x); }
0364 
0365 
0366 // Ring of uninitialized elements.
0367 // Any operation results in an exception being thrown.
0368 
0369 // Thrown when an attempt is made to perform an operation on an uninitialized ring.
0370 class uninitialized_ring_exception : public runtime_exception {
0371 public:
0372     uninitialized_ring_exception ();
0373 };
0374 
0375 // Thrown when a ring element is uninitialized.
0376 class uninitialized_exception : public runtime_exception {
0377 public:
0378     explicit uninitialized_exception (const _cl_ring_element& obj);
0379     uninitialized_exception (const _cl_ring_element& obj_x, const _cl_ring_element& obj_y);
0380 };
0381 
0382 extern const cl_ring cl_no_ring;
0383 extern cl_class cl_class_no_ring;
0384 
0385 class cl_no_ring_init_helper
0386 {
0387     static int count;
0388 public:
0389     cl_no_ring_init_helper();
0390     ~cl_no_ring_init_helper();
0391 };
0392 static cl_no_ring_init_helper cl_no_ring_init_helper_instance;
0393 
0394 inline cl_ring::cl_ring ()
0395     : cl_rcpointer (as_cl_private_thing(cl_no_ring)) {}
0396 inline _cl_ring_element::_cl_ring_element ()
0397     : rep ((cl_private_thing) cl_combine(cl_FN_tag,0)) {}
0398 inline cl_ring_element::cl_ring_element ()
0399     : _cl_ring_element (), _ring () {}
0400 
0401 
0402 // Support for built-in number rings.
0403 // Beware, they are not optimally efficient.
0404 
0405 template <class T>
0406 struct cl_number_ring_ops {
0407     bool (* contains) (const cl_number&);
0408     bool (* equal) (const T&, const T&);
0409     bool (* zerop) (const T&);
0410     const T (* plus) (const T&, const T&);
0411     const T (* minus) (const T&, const T&);
0412     const T (* uminus) (const T&);
0413     const T (* mul) (const T&, const T&);
0414     const T (* square) (const T&);
0415     const T (* expt_pos) (const T&, const cl_I&);
0416 };
0417 class cl_heap_number_ring : public cl_heap_ring {
0418 public:
0419     cl_number_ring_ops<cl_number>* ops;
0420     // Constructor.
0421     cl_heap_number_ring (cl_ring_setops* setopv, cl_ring_addops* addopv, cl_ring_mulops* mulopv, cl_number_ring_ops<cl_number>* opv)
0422         : cl_heap_ring (setopv,addopv,mulopv), ops (opv) {}
0423 };
0424 
0425 class cl_number_ring : public cl_ring {
0426 public:
0427     cl_number_ring (cl_heap_number_ring* r)
0428         : cl_ring (r) {}
0429 };
0430 
0431 template <class T>
0432 class cl_specialized_number_ring : public cl_number_ring {
0433 public:
0434     cl_specialized_number_ring ();
0435 };
0436 
0437 // Type test.
0438 inline bool instanceof (const cl_number& x, const cl_number_ring& R)
0439 {
0440     return ((cl_heap_number_ring*) R.heappointer)->ops->contains(x);
0441 }
0442 
0443 
0444 // Hack section.
0445 
0446 // Conversions to subtypes without checking:
0447 // The2(cl_MI)(x) converts x to a cl_MI, without change of representation!
0448   #define The(type)  *(const type *) & cl_identity
0449   #define The2(type)  *(const type *) & cl_identity2
0450 // This inline function is for type checking purposes only.
0451   inline const cl_ring& cl_identity (const cl_ring& r) { return r; }
0452   inline const cl_ring_element& cl_identity2 (const cl_ring_element& x) { return x; }
0453   inline const cl_gcobject& cl_identity (const _cl_ring_element& x) { return x.rep; }
0454 
0455 
0456 // Debugging support.
0457 #ifdef CL_DEBUG
0458 extern int cl_ring_debug_module;
0459 CL_FORCE_LINK(cl_ring_debug_dummy, cl_ring_debug_module)
0460 #endif
0461 
0462 }  // namespace cln
0463 
0464 #endif /* _CL_RING_H */