You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

446 lines
16 KiB

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