1 // Modular integer operations.
3 #ifndef _CL_MODINTEGER_H
4 #define _CL_MODINTEGER_H
6 #include "cln/object.h"
8 #include "cln/integer.h"
9 #include "cln/random.h"
10 #include "cln/malloc.h"
12 #include "cln/proplist.h"
13 #include "cln/condition.h"
14 #include "cln/exception.h"
15 #undef random // Linux defines random() as a macro!
19 // Representation of an element of a ring Z/mZ.
21 // To protect against mixing elements of different modular rings, such as
22 // (3 mod 4) + (2 mod 5), every modular integer carries its ring in itself.
25 // Representation of a ring Z/mZ.
27 class cl_heap_modint_ring;
29 class cl_modint_ring : public cl_ring {
31 // Default constructor.
33 // Constructor. Takes a cl_heap_modint_ring*, increments its refcount.
34 cl_modint_ring (cl_heap_modint_ring* r);
36 cl_modint_ring (const cl_modint_ring&);
37 // Assignment operator.
38 cl_modint_ring& operator= (const cl_modint_ring&);
39 // Automatic dereferencing.
40 cl_heap_modint_ring* operator-> () const
41 { return (cl_heap_modint_ring*)heappointer; }
45 extern const cl_modint_ring cl_modint0_ring;
46 // Default constructor. This avoids dealing with NULL pointers.
47 inline cl_modint_ring::cl_modint_ring ()
48 : cl_ring (as_cl_private_thing(cl_modint0_ring)) {}
50 class cl_MI_init_helper
57 static cl_MI_init_helper cl_MI_init_helper_instance;
59 // Copy constructor and assignment operator.
60 CL_DEFINE_COPY_CONSTRUCTOR2(cl_modint_ring,cl_ring)
61 CL_DEFINE_ASSIGNMENT_OPERATOR(cl_modint_ring,cl_modint_ring)
63 // Normal constructor for `cl_modint_ring'.
64 inline cl_modint_ring::cl_modint_ring (cl_heap_modint_ring* r)
65 : cl_ring ((cl_private_thing) (cl_inc_pointer_refcount((cl_heap*)r), r)) {}
67 // Operations on modular integer rings.
69 inline bool operator== (const cl_modint_ring& R1, const cl_modint_ring& R2)
70 { return (R1.pointer == R2.pointer); }
71 inline bool operator!= (const cl_modint_ring& R1, const cl_modint_ring& R2)
72 { return (R1.pointer != R2.pointer); }
73 inline bool operator== (const cl_modint_ring& R1, cl_heap_modint_ring* R2)
74 { return (R1.pointer == R2); }
75 inline bool operator!= (const cl_modint_ring& R1, cl_heap_modint_ring* R2)
76 { return (R1.pointer != R2); }
79 // Condition raised when a probable prime is discovered to be composite.
80 struct cl_composite_condition : public cl_condition {
81 SUBCLASS_cl_condition()
82 cl_I p; // the non-prime
83 cl_I factor; // a nontrivial factor, or 0
85 cl_composite_condition (const cl_I& _p)
88 cl_composite_condition (const cl_I& _p, const cl_I& _f)
91 // Implement general condition methods.
92 const char * name () const;
93 void print (std::ostream&) const;
94 ~cl_composite_condition () {}
98 // Representation of an element of a ring Z/mZ.
100 class _cl_MI /* cf. _cl_ring_element */ {
102 cl_I rep; // representative, integer >=0, <m
103 // (maybe the Montgomery representative!)
104 // Default constructor.
105 _cl_MI () : rep () {}
108 _cl_MI (const cl_heap_modint_ring* R, const cl_I& r) : rep (r) { (void)R; }
109 _cl_MI (const cl_modint_ring& R, const cl_I& r) : rep (r) { (void)R; }
112 CL_DEFINE_CONVERTER(_cl_ring_element)
113 public: // Ability to place an object at a given address.
114 void* operator new (size_t size) { return malloc_hook(size); }
115 void* operator new (size_t size, void* ptr) { (void)size; return ptr; }
116 void operator delete (void* ptr) { free_hook(ptr); }
119 class cl_MI /* cf. cl_ring_element */ : public _cl_MI {
121 cl_modint_ring _ring; // ring Z/mZ
123 const cl_modint_ring& ring () const { return _ring; }
124 // Default constructor.
125 cl_MI () : _cl_MI (), _ring () {}
128 cl_MI (const cl_modint_ring& R, const cl_I& r) : _cl_MI (R,r), _ring (R) {}
129 cl_MI (const cl_modint_ring& R, const _cl_MI& r) : _cl_MI (r), _ring (R) {}
132 CL_DEFINE_CONVERTER(cl_ring_element)
134 void debug_print () const;
135 public: // Ability to place an object at a given address.
136 void* operator new (size_t size) { return malloc_hook(size); }
137 void* operator new (size_t size, void* ptr) { (void)size; return ptr; }
138 void operator delete (void* ptr) { free_hook(ptr); }
142 // Representation of an element of a ring Z/mZ or an exception.
148 cl_composite_condition* condition;
150 cl_MI_x (cl_composite_condition* c) : value (), condition (c) {}
151 cl_MI_x (const cl_MI& x) : value (x), condition (NULL) {}
153 //operator cl_MI& () { if (condition) throw runtime_exception(); return value; }
154 //operator const cl_MI& () const { if (condition) throw runtime_exception(); return value; }
155 operator cl_MI () const { if (condition) throw runtime_exception(); return value; }
161 struct _cl_modint_setops /* cf. _cl_ring_setops */ {
163 void (* fprint) (cl_heap_modint_ring* R, std::ostream& stream, const _cl_MI& x);
165 bool (* equal) (cl_heap_modint_ring* R, const _cl_MI& x, const _cl_MI& y);
167 const _cl_MI (* random) (cl_heap_modint_ring* R, random_state& randomstate);
169 struct _cl_modint_addops /* cf. _cl_ring_addops */ {
171 const _cl_MI (* zero) (cl_heap_modint_ring* R);
172 bool (* zerop) (cl_heap_modint_ring* R, const _cl_MI& x);
174 const _cl_MI (* plus) (cl_heap_modint_ring* R, const _cl_MI& x, const _cl_MI& y);
176 const _cl_MI (* minus) (cl_heap_modint_ring* R, const _cl_MI& x, const _cl_MI& y);
178 const _cl_MI (* uminus) (cl_heap_modint_ring* R, const _cl_MI& x);
180 struct _cl_modint_mulops /* cf. _cl_ring_mulops */ {
182 const _cl_MI (* one) (cl_heap_modint_ring* R);
183 // canonical homomorphism
184 const _cl_MI (* canonhom) (cl_heap_modint_ring* R, const cl_I& x);
186 const _cl_MI (* mul) (cl_heap_modint_ring* R, const _cl_MI& x, const _cl_MI& y);
188 const _cl_MI (* square) (cl_heap_modint_ring* R, const _cl_MI& x);
190 const _cl_MI (* expt_pos) (cl_heap_modint_ring* R, const _cl_MI& x, const cl_I& y);
192 const cl_MI_x (* recip) (cl_heap_modint_ring* R, const _cl_MI& x);
194 const cl_MI_x (* div) (cl_heap_modint_ring* R, const _cl_MI& x, const _cl_MI& y);
196 const cl_MI_x (* expt) (cl_heap_modint_ring* R, const _cl_MI& x, const cl_I& y);
197 // x -> x mod m for x>=0
198 const cl_I (* reduce_modulo) (cl_heap_modint_ring* R, const cl_I& x);
199 // some inverse of canonical homomorphism
200 const cl_I (* retract) (cl_heap_modint_ring* R, const _cl_MI& x);
202 typedef const _cl_modint_setops cl_modint_setops;
203 typedef const _cl_modint_addops cl_modint_addops;
204 typedef const _cl_modint_mulops cl_modint_mulops;
206 // Representation of the ring Z/mZ.
208 // Currently rings are garbage collected only when they are not referenced
209 // any more and when the ring table gets full.
211 // Modular integer rings are kept unique in memory. This way, ring equality
212 // can be checked very efficiently by a simple pointer comparison.
214 class cl_heap_modint_ring /* cf. cl_heap_ring */ : public cl_heap {
215 SUBCLASS_cl_heap_ring()
217 cl_property_list properties;
219 cl_modint_setops* setops;
220 cl_modint_addops* addops;
221 cl_modint_mulops* mulops;
223 cl_I modulus; // m, normalized to be >= 0
225 // Low-level operations.
226 void _fprint (std::ostream& stream, const _cl_MI& x)
227 { setops->fprint(this,stream,x); }
228 bool _equal (const _cl_MI& x, const _cl_MI& y)
229 { return setops->equal(this,x,y); }
230 const _cl_MI _random (random_state& randomstate)
231 { return setops->random(this,randomstate); }
232 const _cl_MI _zero ()
233 { return addops->zero(this); }
234 bool _zerop (const _cl_MI& x)
235 { return addops->zerop(this,x); }
236 const _cl_MI _plus (const _cl_MI& x, const _cl_MI& y)
237 { return addops->plus(this,x,y); }
238 const _cl_MI _minus (const _cl_MI& x, const _cl_MI& y)
239 { return addops->minus(this,x,y); }
240 const _cl_MI _uminus (const _cl_MI& x)
241 { return addops->uminus(this,x); }
243 { return mulops->one(this); }
244 const _cl_MI _canonhom (const cl_I& x)
245 { return mulops->canonhom(this,x); }
246 const _cl_MI _mul (const _cl_MI& x, const _cl_MI& y)
247 { return mulops->mul(this,x,y); }
248 const _cl_MI _square (const _cl_MI& x)
249 { return mulops->square(this,x); }
250 const _cl_MI _expt_pos (const _cl_MI& x, const cl_I& y)
251 { return mulops->expt_pos(this,x,y); }
252 const cl_MI_x _recip (const _cl_MI& x)
253 { return mulops->recip(this,x); }
254 const cl_MI_x _div (const _cl_MI& x, const _cl_MI& y)
255 { return mulops->div(this,x,y); }
256 const cl_MI_x _expt (const _cl_MI& x, const cl_I& y)
257 { return mulops->expt(this,x,y); }
258 const cl_I _reduce_modulo (const cl_I& x)
259 { return mulops->reduce_modulo(this,x); }
260 const cl_I _retract (const _cl_MI& x)
261 { return mulops->retract(this,x); }
262 // High-level operations.
263 void fprint (std::ostream& stream, const cl_MI& x)
265 if (!(x.ring() == this)) throw runtime_exception();
268 bool equal (const cl_MI& x, const cl_MI& y)
270 if (!(x.ring() == this)) throw runtime_exception();
271 if (!(y.ring() == this)) throw runtime_exception();
274 const cl_MI random (random_state& randomstate = default_random_state)
276 return cl_MI(this,_random(randomstate));
280 return cl_MI(this,_zero());
282 bool zerop (const cl_MI& x)
284 if (!(x.ring() == this)) throw runtime_exception();
287 const cl_MI plus (const cl_MI& x, const cl_MI& y)
289 if (!(x.ring() == this)) throw runtime_exception();
290 if (!(y.ring() == this)) throw runtime_exception();
291 return cl_MI(this,_plus(x,y));
293 const cl_MI minus (const cl_MI& x, const cl_MI& y)
295 if (!(x.ring() == this)) throw runtime_exception();
296 if (!(y.ring() == this)) throw runtime_exception();
297 return cl_MI(this,_minus(x,y));
299 const cl_MI uminus (const cl_MI& x)
301 if (!(x.ring() == this)) throw runtime_exception();
302 return cl_MI(this,_uminus(x));
306 return cl_MI(this,_one());
308 const cl_MI canonhom (const cl_I& x)
310 return cl_MI(this,_canonhom(x));
312 const cl_MI mul (const cl_MI& x, const cl_MI& y)
314 if (!(x.ring() == this)) throw runtime_exception();
315 if (!(y.ring() == this)) throw runtime_exception();
316 return cl_MI(this,_mul(x,y));
318 const cl_MI square (const cl_MI& x)
320 if (!(x.ring() == this)) throw runtime_exception();
321 return cl_MI(this,_square(x));
323 const cl_MI expt_pos (const cl_MI& x, const cl_I& y)
325 if (!(x.ring() == this)) throw runtime_exception();
326 return cl_MI(this,_expt_pos(x,y));
328 const cl_MI_x recip (const cl_MI& x)
330 if (!(x.ring() == this)) throw runtime_exception();
333 const cl_MI_x div (const cl_MI& x, const cl_MI& y)
335 if (!(x.ring() == this)) throw runtime_exception();
336 if (!(y.ring() == this)) throw runtime_exception();
339 const cl_MI_x expt (const cl_MI& x, const cl_I& y)
341 if (!(x.ring() == this)) throw runtime_exception();
344 const cl_I reduce_modulo (const cl_I& x)
346 return _reduce_modulo(x);
348 const cl_I retract (const cl_MI& x)
350 if (!(x.ring() == this)) throw runtime_exception();
354 sintC bits; // number of bits needed to represent a representative, or -1
355 int log2_bits; // log_2(bits), or -1
356 // Property operations.
357 cl_property* get_property (const cl_symbol& key)
358 { return properties.get_property(key); }
359 void add_property (cl_property* new_property)
360 { properties.add_property(new_property); }
361 // Constructor / destructor.
362 cl_heap_modint_ring (cl_I m, cl_modint_setops*, cl_modint_addops*, cl_modint_mulops*);
363 ~cl_heap_modint_ring () {}
365 #define SUBCLASS_cl_heap_modint_ring() \
366 SUBCLASS_cl_heap_ring()
368 // Lookup or create a modular integer ring Z/mZ
369 extern const cl_modint_ring find_modint_ring (const cl_I& m);
370 static cl_MI_init_helper cl_MI_init_helper_instance2;
372 // Operations on modular integers.
375 inline void fprint (std::ostream& stream, const cl_MI& x)
376 { x.ring()->fprint(stream,x); }
377 CL_DEFINE_PRINT_OPERATOR(cl_MI)
380 inline const cl_MI operator+ (const cl_MI& x, const cl_MI& y)
381 { return x.ring()->plus(x,y); }
382 inline const cl_MI operator+ (const cl_MI& x, const cl_I& y)
383 { return x.ring()->plus(x,x.ring()->canonhom(y)); }
384 inline const cl_MI operator+ (const cl_I& x, const cl_MI& y)
385 { return y.ring()->plus(y.ring()->canonhom(x),y); }
388 inline const cl_MI operator- (const cl_MI& x)
389 { return x.ring()->uminus(x); }
392 inline const cl_MI operator- (const cl_MI& x, const cl_MI& y)
393 { return x.ring()->minus(x,y); }
394 inline const cl_MI operator- (const cl_MI& x, const cl_I& y)
395 { return x.ring()->minus(x,x.ring()->canonhom(y)); }
396 inline const cl_MI operator- (const cl_I& x, const cl_MI& y)
397 { return y.ring()->minus(y.ring()->canonhom(x),y); }
400 extern const cl_MI operator<< (const cl_MI& x, sintC y); // assume 0 <= y < 2^(intCsize-1)
401 extern const cl_MI operator>> (const cl_MI& x, sintC y); // assume m odd, 0 <= y < 2^(intCsize-1)
404 inline bool operator== (const cl_MI& x, const cl_MI& y)
405 { return x.ring()->equal(x,y); }
406 inline bool operator!= (const cl_MI& x, const cl_MI& y)
407 { return !x.ring()->equal(x,y); }
408 inline bool operator== (const cl_MI& x, const cl_I& y)
409 { return x.ring()->equal(x,x.ring()->canonhom(y)); }
410 inline bool operator!= (const cl_MI& x, const cl_I& y)
411 { return !x.ring()->equal(x,x.ring()->canonhom(y)); }
412 inline bool operator== (const cl_I& x, const cl_MI& y)
413 { return y.ring()->equal(y.ring()->canonhom(x),y); }
414 inline bool operator!= (const cl_I& x, const cl_MI& y)
415 { return !y.ring()->equal(y.ring()->canonhom(x),y); }
417 // Compare against 0.
418 inline bool zerop (const cl_MI& x)
419 { return x.ring()->zerop(x); }
422 inline const cl_MI operator* (const cl_MI& x, const cl_MI& y)
423 { return x.ring()->mul(x,y); }
426 inline const cl_MI square (const cl_MI& x)
427 { return x.ring()->square(x); }
429 // Exponentiation x^y, where y > 0.
430 inline const cl_MI expt_pos (const cl_MI& x, const cl_I& y)
431 { return x.ring()->expt_pos(x,y); }
434 inline const cl_MI recip (const cl_MI& x)
435 { return x.ring()->recip(x); }
438 inline const cl_MI div (const cl_MI& x, const cl_MI& y)
439 { return x.ring()->div(x,y); }
440 inline const cl_MI div (const cl_MI& x, const cl_I& y)
441 { return x.ring()->div(x,x.ring()->canonhom(y)); }
442 inline const cl_MI div (const cl_I& x, const cl_MI& y)
443 { return y.ring()->div(y.ring()->canonhom(x),y); }
445 // Exponentiation x^y.
446 inline const cl_MI expt (const cl_MI& x, const cl_I& y)
447 { return x.ring()->expt(x,y); }
449 // Scalar multiplication.
450 inline const cl_MI operator* (const cl_I& x, const cl_MI& y)
451 { return y.ring()->mul(y.ring()->canonhom(x),y); }
452 inline const cl_MI operator* (const cl_MI& x, const cl_I& y)
453 { return x.ring()->mul(x.ring()->canonhom(y),x); }
455 // TODO: implement gcd, index (= gcd), unitp, sqrtp
458 // Debugging support.
460 extern int cl_MI_debug_module;
461 CL_FORCE_LINK(cl_MI_debug_dummy, cl_MI_debug_module)
466 #endif /* _CL_MODINTEGER_H */