// Modular integer operations. #ifndef _CL_MODINTEGER_H #define _CL_MODINTEGER_H #include "cln/object.h" #include "cln/ring.h" #include "cln/integer.h" #include "cln/random.h" #include "cln/malloc.h" #include "cln/io.h" #include "cln/proplist.h" #include "cln/condition.h" #include "cln/abort.h" #undef random // Linux defines random() as a macro! namespace cln { // Representation of an element of a ring Z/mZ. // To protect against mixing elements of different modular rings, such as // (3 mod 4) + (2 mod 5), every modular integer carries its ring in itself. // Representation of a ring Z/mZ. class cl_heap_modint_ring; class cl_modint_ring : public cl_ring { public: // Default constructor. cl_modint_ring (); // Constructor. Takes a cl_heap_modint_ring*, increments its refcount. cl_modint_ring (cl_heap_modint_ring* r); // Copy constructor. cl_modint_ring (const cl_modint_ring&); // Assignment operator. cl_modint_ring& operator= (const cl_modint_ring&); // Automatic dereferencing. cl_heap_modint_ring* operator-> () const { return (cl_heap_modint_ring*)heappointer; } }; // Z/0Z extern const cl_modint_ring cl_modint0_ring; // Default constructor. This avoids dealing with NULL pointers. inline cl_modint_ring::cl_modint_ring () : cl_ring (as_cl_private_thing(cl_modint0_ring)) {} CL_REQUIRE(cl_MI) // Copy constructor and assignment operator. CL_DEFINE_COPY_CONSTRUCTOR2(cl_modint_ring,cl_ring) CL_DEFINE_ASSIGNMENT_OPERATOR(cl_modint_ring,cl_modint_ring) // Normal constructor for `cl_modint_ring'. inline cl_modint_ring::cl_modint_ring (cl_heap_modint_ring* r) : cl_ring ((cl_private_thing) (cl_inc_pointer_refcount((cl_heap*)r), r)) {} // Operations on modular integer rings. inline bool operator== (const cl_modint_ring& R1, const cl_modint_ring& R2) { return (R1.pointer == R2.pointer); } inline bool operator!= (const cl_modint_ring& R1, const cl_modint_ring& R2) { return (R1.pointer != R2.pointer); } inline bool operator== (const cl_modint_ring& R1, cl_heap_modint_ring* R2) { return (R1.pointer == R2); } inline bool operator!= (const cl_modint_ring& R1, cl_heap_modint_ring* R2) { return (R1.pointer != R2); } // Condition raised when a probable prime is discovered to be composite. struct cl_composite_condition : public cl_condition { SUBCLASS_cl_condition() cl_I p; // the non-prime cl_I factor; // a nontrivial factor, or 0 // Constructors. cl_composite_condition (const cl_I& _p) : p (_p), factor (0) { print(std::cerr); } cl_composite_condition (const cl_I& _p, const cl_I& _f) : p (_p), factor (_f) { print(std::cerr); } // Implement general condition methods. const char * name () const; void print (std::ostream&) const; ~cl_composite_condition () {} }; // Representation of an element of a ring Z/mZ. class _cl_MI /* cf. _cl_ring_element */ { public: cl_I rep; // representative, integer >=0, 0 const _cl_MI (* expt_pos) (cl_heap_modint_ring* R, const _cl_MI& x, const cl_I& y); // x^-1 const cl_MI_x (* recip) (cl_heap_modint_ring* R, const _cl_MI& x); // x*y^-1 const cl_MI_x (* div) (cl_heap_modint_ring* R, const _cl_MI& x, const _cl_MI& y); // x^y, y Integer const cl_MI_x (* expt) (cl_heap_modint_ring* R, const _cl_MI& x, const cl_I& y); // x -> x mod m for x>=0 const cl_I (* reduce_modulo) (cl_heap_modint_ring* R, const cl_I& x); // some inverse of canonical homomorphism const cl_I (* retract) (cl_heap_modint_ring* R, const _cl_MI& x); }; typedef const _cl_modint_setops cl_modint_setops; typedef const _cl_modint_addops cl_modint_addops; typedef const _cl_modint_mulops cl_modint_mulops; // Representation of the ring Z/mZ. // Currently rings are garbage collected only when they are not referenced // any more and when the ring table gets full. // Modular integer rings are kept unique in memory. This way, ring equality // can be checked very efficiently by a simple pointer comparison. class cl_heap_modint_ring /* cf. cl_heap_ring */ : public cl_heap { SUBCLASS_cl_heap_ring() private: cl_property_list properties; protected: cl_modint_setops* setops; cl_modint_addops* addops; cl_modint_mulops* mulops; public: cl_I modulus; // m, normalized to be >= 0 public: // Low-level operations. void _fprint (std::ostream& stream, const _cl_MI& x) { setops->fprint(this,stream,x); } cl_boolean _equal (const _cl_MI& x, const _cl_MI& y) { return setops->equal(this,x,y); } const _cl_MI _random (random_state& randomstate) { return setops->random(this,randomstate); } const _cl_MI _zero () { return addops->zero(this); } cl_boolean _zerop (const _cl_MI& x) { return addops->zerop(this,x); } const _cl_MI _plus (const _cl_MI& x, const _cl_MI& y) { return addops->plus(this,x,y); } const _cl_MI _minus (const _cl_MI& x, const _cl_MI& y) { return addops->minus(this,x,y); } const _cl_MI _uminus (const _cl_MI& x) { return addops->uminus(this,x); } const _cl_MI _one () { return mulops->one(this); } const _cl_MI _canonhom (const cl_I& x) { return mulops->canonhom(this,x); } const _cl_MI _mul (const _cl_MI& x, const _cl_MI& y) { return mulops->mul(this,x,y); } const _cl_MI _square (const _cl_MI& x) { return mulops->square(this,x); } const _cl_MI _expt_pos (const _cl_MI& x, const cl_I& y) { return mulops->expt_pos(this,x,y); } const cl_MI_x _recip (const _cl_MI& x) { return mulops->recip(this,x); } const cl_MI_x _div (const _cl_MI& x, const _cl_MI& y) { return mulops->div(this,x,y); } const cl_MI_x _expt (const _cl_MI& x, const cl_I& y) { return mulops->expt(this,x,y); } const cl_I _reduce_modulo (const cl_I& x) { return mulops->reduce_modulo(this,x); } const cl_I _retract (const _cl_MI& x) { return mulops->retract(this,x); } // High-level operations. void fprint (std::ostream& stream, const cl_MI& x) { if (!(x.ring() == this)) cl_abort(); _fprint(stream,x); } cl_boolean equal (const cl_MI& x, const cl_MI& y) { if (!(x.ring() == this)) cl_abort(); if (!(y.ring() == this)) cl_abort(); return _equal(x,y); } const cl_MI random (random_state& randomstate = default_random_state) { return cl_MI(this,_random(randomstate)); } const cl_MI zero () { return cl_MI(this,_zero()); } cl_boolean zerop (const cl_MI& x) { if (!(x.ring() == this)) cl_abort(); return _zerop(x); } const cl_MI plus (const cl_MI& x, const cl_MI& y) { if (!(x.ring() == this)) cl_abort(); if (!(y.ring() == this)) cl_abort(); return cl_MI(this,_plus(x,y)); } const cl_MI minus (const cl_MI& x, const cl_MI& y) { if (!(x.ring() == this)) cl_abort(); if (!(y.ring() == this)) cl_abort(); return cl_MI(this,_minus(x,y)); } const cl_MI uminus (const cl_MI& x) { if (!(x.ring() == this)) cl_abort(); return cl_MI(this,_uminus(x)); } const cl_MI one () { return cl_MI(this,_one()); } const cl_MI canonhom (const cl_I& x) { return cl_MI(this,_canonhom(x)); } const cl_MI mul (const cl_MI& x, const cl_MI& y) { if (!(x.ring() == this)) cl_abort(); if (!(y.ring() == this)) cl_abort(); return cl_MI(this,_mul(x,y)); } const cl_MI square (const cl_MI& x) { if (!(x.ring() == this)) cl_abort(); return cl_MI(this,_square(x)); } const cl_MI expt_pos (const cl_MI& x, const cl_I& y) { if (!(x.ring() == this)) cl_abort(); return cl_MI(this,_expt_pos(x,y)); } const cl_MI_x recip (const cl_MI& x) { if (!(x.ring() == this)) cl_abort(); return _recip(x); } const cl_MI_x div (const cl_MI& x, const cl_MI& y) { if (!(x.ring() == this)) cl_abort(); if (!(y.ring() == this)) cl_abort(); return _div(x,y); } const cl_MI_x expt (const cl_MI& x, const cl_I& y) { if (!(x.ring() == this)) cl_abort(); return _expt(x,y); } const cl_I reduce_modulo (const cl_I& x) { return _reduce_modulo(x); } const cl_I retract (const cl_MI& x) { if (!(x.ring() == this)) cl_abort(); return _retract(x); } // Miscellaneous. sintL bits; // number of bits needed to represent a representative, or -1 int log2_bits; // log_2(bits), or -1 // Property operations. cl_property* get_property (const cl_symbol& key) { return properties.get_property(key); } void add_property (cl_property* new_property) { properties.add_property(new_property); } // Constructor. cl_heap_modint_ring (cl_I m, cl_modint_setops*, cl_modint_addops*, cl_modint_mulops*); // This class is intented to be subclassable, hence needs a virtual destructor. virtual ~cl_heap_modint_ring () {} private: virtual void dummy (); }; #define SUBCLASS_cl_heap_modint_ring() \ SUBCLASS_cl_heap_ring() // Lookup or create a modular integer ring Z/mZ extern const cl_modint_ring find_modint_ring (const cl_I& m); CL_REQUIRE(cl_MI) // Runtime typing support. extern cl_class cl_class_modint_ring; // Operations on modular integers. // Output. inline void fprint (std::ostream& stream, const cl_MI& x) { x.ring()->fprint(stream,x); } CL_DEFINE_PRINT_OPERATOR(cl_MI) // Add. inline const cl_MI operator+ (const cl_MI& x, const cl_MI& y) { return x.ring()->plus(x,y); } inline const cl_MI operator+ (const cl_MI& x, const cl_I& y) { return x.ring()->plus(x,x.ring()->canonhom(y)); } inline const cl_MI operator+ (const cl_I& x, const cl_MI& y) { return y.ring()->plus(y.ring()->canonhom(x),y); } // Negate. inline const cl_MI operator- (const cl_MI& x) { return x.ring()->uminus(x); } // Subtract. inline const cl_MI operator- (const cl_MI& x, const cl_MI& y) { return x.ring()->minus(x,y); } inline const cl_MI operator- (const cl_MI& x, const cl_I& y) { return x.ring()->minus(x,x.ring()->canonhom(y)); } inline const cl_MI operator- (const cl_I& x, const cl_MI& y) { return y.ring()->minus(y.ring()->canonhom(x),y); } // Shifts. extern const cl_MI operator<< (const cl_MI& x, sintL y); // assume 0 <= y < 2^31 extern const cl_MI operator>> (const cl_MI& x, sintL y); // assume m odd, 0 <= y < 2^31 // Equality. inline bool operator== (const cl_MI& x, const cl_MI& y) { return x.ring()->equal(x,y); } inline bool operator!= (const cl_MI& x, const cl_MI& y) { return !x.ring()->equal(x,y); } inline bool operator== (const cl_MI& x, const cl_I& y) { return x.ring()->equal(x,x.ring()->canonhom(y)); } inline bool operator!= (const cl_MI& x, const cl_I& y) { return !x.ring()->equal(x,x.ring()->canonhom(y)); } inline bool operator== (const cl_I& x, const cl_MI& y) { return y.ring()->equal(y.ring()->canonhom(x),y); } inline bool operator!= (const cl_I& x, const cl_MI& y) { return !y.ring()->equal(y.ring()->canonhom(x),y); } // Compare against 0. inline cl_boolean zerop (const cl_MI& x) { return x.ring()->zerop(x); } // Multiply. inline const cl_MI operator* (const cl_MI& x, const cl_MI& y) { return x.ring()->mul(x,y); } // Squaring. inline const cl_MI square (const cl_MI& x) { return x.ring()->square(x); } // Exponentiation x^y, where y > 0. inline const cl_MI expt_pos (const cl_MI& x, const cl_I& y) { return x.ring()->expt_pos(x,y); } // Reciprocal. inline const cl_MI recip (const cl_MI& x) { return x.ring()->recip(x); } // Division. inline const cl_MI div (const cl_MI& x, const cl_MI& y) { return x.ring()->div(x,y); } inline const cl_MI div (const cl_MI& x, const cl_I& y) { return x.ring()->div(x,x.ring()->canonhom(y)); } inline const cl_MI div (const cl_I& x, const cl_MI& y) { return y.ring()->div(y.ring()->canonhom(x),y); } // Exponentiation x^y. inline const cl_MI expt (const cl_MI& x, const cl_I& y) { return x.ring()->expt(x,y); } // Scalar multiplication. inline const cl_MI operator* (const cl_I& x, const cl_MI& y) { return y.ring()->mul(y.ring()->canonhom(x),y); } inline const cl_MI operator* (const cl_MI& x, const cl_I& y) { return x.ring()->mul(x.ring()->canonhom(y),x); } // TODO: implement gcd, index (= gcd), unitp, sqrtp // Debugging support. #ifdef CL_DEBUG extern int cl_MI_debug_module; CL_FORCE_LINK(cl_MI_debug_dummy, cl_MI_debug_module) #endif } // namespace cln #endif /* _CL_MODINTEGER_H */