您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

442 行
16 KiB

  1. // Ring operations.
  2. #ifndef _CL_RING_H
  3. #define _CL_RING_H
  4. #include "cln/object.h"
  5. #include "cln/malloc.h"
  6. #include "cln/proplist.h"
  7. #include "cln/number.h"
  8. #include "cln/io.h"
  9. namespace cln {
  10. class cl_I;
  11. // This file defines the general layout of rings, ring elements, and
  12. // operations available on ring elements. Any subclass of `cl_ring'
  13. // must implement these operations, with the same memory layout.
  14. // (Because generic packages like the polynomial rings access the base
  15. // ring's operation vectors through inline functions defined in this file.)
  16. class cl_heap_ring;
  17. // Rings are reference counted, but not freed immediately when they aren't
  18. // used any more. Hence they inherit from `cl_rcpointer'.
  19. // Vectors of function pointers are more efficient than virtual member
  20. // functions. But it constrains us not to use multiple or virtual inheritance.
  21. //
  22. // Note! We are passing raw `cl_heap_ring*' pointers to the operations
  23. // for efficiency (compared to passing `const cl_ring&', we save a memory
  24. // access, and it is easier to cast to a `cl_heap_ring_specialized*').
  25. // These raw pointers are meant to be used downward (in the dynamic extent
  26. // of the call) only. If you need to save them in a data structure, cast
  27. // to `cl_ring'; this will correctly increment the reference count.
  28. // (This technique is safe because the inline wrapper functions make sure
  29. // that we have a `cl_ring' somewhere containing the pointer, so there
  30. // is no danger of dangling pointers.)
  31. //
  32. // Note! Because the `cl_heap_ring*' -> `cl_ring' conversion increments
  33. // the reference count, you have to use the `cl_private_thing' -> `cl_ring'
  34. // conversion if the reference count is already incremented.
  35. class cl_ring : public cl_rcpointer {
  36. public:
  37. // Constructor. Takes a cl_heap_ring*, increments its refcount.
  38. cl_ring (cl_heap_ring* r);
  39. // Private constructor. Doesn't increment the refcount.
  40. cl_ring (cl_private_thing);
  41. // Copy constructor.
  42. cl_ring (const cl_ring&);
  43. // Assignment operator.
  44. cl_ring& operator= (const cl_ring&);
  45. // Default constructor.
  46. cl_ring ();
  47. // Automatic dereferencing.
  48. cl_heap_ring* operator-> () const
  49. { return (cl_heap_ring*)heappointer; }
  50. };
  51. CL_DEFINE_COPY_CONSTRUCTOR2(cl_ring,cl_rcpointer)
  52. CL_DEFINE_ASSIGNMENT_OPERATOR(cl_ring,cl_ring)
  53. // Normal constructor for `cl_ring'.
  54. inline cl_ring::cl_ring (cl_heap_ring* r)
  55. { cl_inc_pointer_refcount((cl_heap*)r); pointer = r; }
  56. // Private constructor for `cl_ring'.
  57. inline cl_ring::cl_ring (cl_private_thing p)
  58. { pointer = p; }
  59. inline bool operator== (const cl_ring& R1, const cl_ring& R2)
  60. { return (R1.pointer == R2.pointer); }
  61. inline bool operator!= (const cl_ring& R1, const cl_ring& R2)
  62. { return (R1.pointer != R2.pointer); }
  63. inline bool operator== (const cl_ring& R1, cl_heap_ring* R2)
  64. { return (R1.pointer == R2); }
  65. inline bool operator!= (const cl_ring& R1, cl_heap_ring* R2)
  66. { return (R1.pointer != R2); }
  67. // Representation of an element of a ring.
  68. //
  69. // In order to support true polymorphism (without C++ templates), all
  70. // ring elements share the same basic layout:
  71. // cl_ring ring; // the ring
  72. // cl_gcobject rep; // representation of the element
  73. // The representation of the element depends on the ring, of course,
  74. // but we constrain it to be a single pointer into the heap or an immediate
  75. // value.
  76. //
  77. // Any arithmetic operation on a ring R (like +, -, *) must return a value
  78. // with ring = R. This is
  79. // a. necessary if the computation is to proceed correctly (e.g. in cl_RA,
  80. // ((3/4)*4 mod 3) is 0, simplifying it to ((cl_I)4 mod (cl_I)3) = 1
  81. // wouldn't be correct),
  82. // b. possible even if R is an extension ring of some ring R1 (e.g. cl_N
  83. // being an extension ring of cl_R). Automatic retraction from R to R1
  84. // can be done through dynamic typing: An element of R which happens
  85. // to lie in R1 is stored using the internal representation of R1,
  86. // but with ring = R. Elements of R1 and R\R1 can be distinguished
  87. // through rep's type.
  88. // c. an advantage for the implementation of polynomials and other
  89. // entities which contain many elements of the same ring. They need
  90. // to store only the elements' representations, and a single pointer
  91. // to the ring.
  92. //
  93. // The ring operations exist in two versions:
  94. // - Low-level version, which only operates on the representation.
  95. // - High-level version, which operates on full cl_ring_elements.
  96. // We make this distinction for performance: Multiplication of polynomials
  97. // over Z/nZ, operating on the high-level operations, spends 40% of its
  98. // computing time with packing and unpacking of cl_ring_elements.
  99. // The low-level versions have an underscore prepended and are unsafe.
  100. class _cl_ring_element {
  101. public:
  102. cl_gcobject rep; // representation of the element
  103. // Default constructor.
  104. _cl_ring_element ();
  105. public: /* ugh */
  106. // Constructor.
  107. _cl_ring_element (const cl_heap_ring* R, const cl_gcobject& r) : rep (as_cl_private_thing(r)) { (void)R; }
  108. _cl_ring_element (const cl_ring& R, const cl_gcobject& r) : rep (as_cl_private_thing(r)) { (void)R; }
  109. public: // Ability to place an object at a given address.
  110. void* operator new (size_t size) { return malloc_hook(size); }
  111. void* operator new (size_t size, void* ptr) { (void)size; return ptr; }
  112. void operator delete (void* ptr) { free_hook(ptr); }
  113. };
  114. class cl_ring_element : public _cl_ring_element {
  115. protected:
  116. cl_ring _ring; // ring
  117. public:
  118. const cl_ring& ring () const { return _ring; }
  119. // Default constructor.
  120. cl_ring_element ();
  121. public: /* ugh */
  122. // Constructor.
  123. cl_ring_element (const cl_ring& R, const cl_gcobject& r) : _cl_ring_element (R,r), _ring (R) {}
  124. cl_ring_element (const cl_ring& R, const _cl_ring_element& r) : _cl_ring_element (r), _ring (R) {}
  125. public: // Debugging output.
  126. void debug_print () const;
  127. // Ability to place an object at a given address.
  128. void* operator new (size_t size) { return malloc_hook(size); }
  129. void* operator new (size_t size, void* ptr) { (void)size; return ptr; }
  130. void operator delete (void* ptr) { free_hook(ptr); }
  131. };
  132. // The ring operations are encoded as vectors of function pointers. You
  133. // can add more operations to the end of each vector or add new vectors,
  134. // but you must not reorder the operations nor reorder the vectors nor
  135. // change the functions' signatures incompatibly.
  136. // There should ideally be a template class for each vector, but unfortunately
  137. // you lose the ability to initialize the vector using "= { ... }" syntax
  138. // when you subclass it.
  139. struct _cl_ring_setops {
  140. // print
  141. void (* fprint) (cl_heap_ring* R, std::ostream& stream, const _cl_ring_element& x);
  142. // equality
  143. cl_boolean (* equal) (cl_heap_ring* R, const _cl_ring_element& x, const _cl_ring_element& y);
  144. // ...
  145. };
  146. struct _cl_ring_addops {
  147. // 0
  148. const _cl_ring_element (* zero) (cl_heap_ring* R);
  149. cl_boolean (* zerop) (cl_heap_ring* R, const _cl_ring_element& x);
  150. // x+y
  151. const _cl_ring_element (* plus) (cl_heap_ring* R, const _cl_ring_element& x, const _cl_ring_element& y);
  152. // x-y
  153. const _cl_ring_element (* minus) (cl_heap_ring* R, const _cl_ring_element& x, const _cl_ring_element& y);
  154. // -x
  155. const _cl_ring_element (* uminus) (cl_heap_ring* R, const _cl_ring_element& x);
  156. // ...
  157. };
  158. struct _cl_ring_mulops {
  159. // 1
  160. const _cl_ring_element (* one) (cl_heap_ring* R);
  161. // canonical homomorphism
  162. const _cl_ring_element (* canonhom) (cl_heap_ring* R, const cl_I& x);
  163. // x*y
  164. const _cl_ring_element (* mul) (cl_heap_ring* R, const _cl_ring_element& x, const _cl_ring_element& y);
  165. // x^2
  166. const _cl_ring_element (* square) (cl_heap_ring* R, const _cl_ring_element& x);
  167. // x^y, y Integer >0
  168. const _cl_ring_element (* expt_pos) (cl_heap_ring* R, const _cl_ring_element& x, const cl_I& y);
  169. // ...
  170. };
  171. typedef const _cl_ring_setops cl_ring_setops;
  172. typedef const _cl_ring_addops cl_ring_addops;
  173. typedef const _cl_ring_mulops cl_ring_mulops;
  174. // Representation of a ring in memory.
  175. class cl_heap_ring : public cl_heap {
  176. public:
  177. // Allocation.
  178. void* operator new (size_t size) { return malloc_hook(size); }
  179. // Deallocation.
  180. void operator delete (void* ptr) { free_hook(ptr); }
  181. private:
  182. cl_property_list properties;
  183. protected:
  184. cl_ring_setops* setops;
  185. cl_ring_addops* addops;
  186. cl_ring_mulops* mulops;
  187. public:
  188. // More information comes here.
  189. // ...
  190. public:
  191. // Low-level operations.
  192. void _fprint (std::ostream& stream, const _cl_ring_element& x)
  193. { setops->fprint(this,stream,x); }
  194. cl_boolean _equal (const _cl_ring_element& x, const _cl_ring_element& y)
  195. { return setops->equal(this,x,y); }
  196. const _cl_ring_element _zero ()
  197. { return addops->zero(this); }
  198. cl_boolean _zerop (const _cl_ring_element& x)
  199. { return addops->zerop(this,x); }
  200. const _cl_ring_element _plus (const _cl_ring_element& x, const _cl_ring_element& y)
  201. { return addops->plus(this,x,y); }
  202. const _cl_ring_element _minus (const _cl_ring_element& x, const _cl_ring_element& y)
  203. { return addops->minus(this,x,y); }
  204. const _cl_ring_element _uminus (const _cl_ring_element& x)
  205. { return addops->uminus(this,x); }
  206. const _cl_ring_element _one ()
  207. { return mulops->one(this); }
  208. const _cl_ring_element _canonhom (const cl_I& x)
  209. { return mulops->canonhom(this,x);