|
|
// Ring operations.
#ifndef _CL_RING_H
#define _CL_RING_H
#include "cln/object.h"
#include "cln/malloc.h"
#include "cln/proplist.h"
#include "cln/number.h"
#include "cln/io.h"
namespace cln {
class cl_I;
// This file defines the general layout of rings, ring elements, and
// operations available on ring elements. Any subclass of `cl_ring'
// must implement these operations, with the same memory layout.
// (Because generic packages like the polynomial rings access the base
// ring's operation vectors through inline functions defined in this file.)
class cl_heap_ring;
// Rings are reference counted, but not freed immediately when they aren't
// used any more. Hence they inherit from `cl_rcpointer'.
// Vectors of function pointers are more efficient than virtual member
// functions. But it constrains us not to use multiple or virtual inheritance.
//
// Note! We are passing raw `cl_heap_ring*' pointers to the operations
// for efficiency (compared to passing `const cl_ring&', we save a memory
// access, and it is easier to cast to a `cl_heap_ring_specialized*').
// These raw pointers are meant to be used downward (in the dynamic extent
// of the call) only. If you need to save them in a data structure, cast
// to `cl_ring'; this will correctly increment the reference count.
// (This technique is safe because the inline wrapper functions make sure
// that we have a `cl_ring' somewhere containing the pointer, so there
// is no danger of dangling pointers.)
//
// Note! Because the `cl_heap_ring*' -> `cl_ring' conversion increments
// the reference count, you have to use the `cl_private_thing' -> `cl_ring'
// conversion if the reference count is already incremented.
class cl_ring : public cl_rcpointer { public: // Constructor. Takes a cl_heap_ring*, increments its refcount.
cl_ring (cl_heap_ring* r); // Private constructor. Doesn't increment the refcount.
cl_ring (cl_private_thing); // Copy constructor.
cl_ring (const cl_ring&); // Assignment operator.
cl_ring& operator= (const cl_ring&); // Default constructor.
cl_ring (); // Automatic dereferencing.
cl_heap_ring* operator-> () const { return (cl_heap_ring*)heappointer; } }; CL_DEFINE_COPY_CONSTRUCTOR2(cl_ring,cl_rcpointer) CL_DEFINE_ASSIGNMENT_OPERATOR(cl_ring,cl_ring)
// Normal constructor for `cl_ring'.
inline cl_ring::cl_ring (cl_heap_ring* r) { cl_inc_pointer_refcount((cl_heap*)r); pointer = r; } // Private constructor for `cl_ring'.
inline cl_ring::cl_ring (cl_private_thing p) { pointer = p; }
inline bool operator== (const cl_ring& R1, const cl_ring& R2) { return (R1.pointer == R2.pointer); } inline bool operator!= (const cl_ring& R1, const cl_ring& R2) { return (R1.pointer != R2.pointer); } inline bool operator== (const cl_ring& R1, cl_heap_ring* R2) { return (R1.pointer == R2); } inline bool operator!= (const cl_ring& R1, cl_heap_ring* R2) { return (R1.pointer != R2); }
// Representation of an element of a ring.
//
// In order to support true polymorphism (without C++ templates), all
// ring elements share the same basic layout:
// cl_ring ring; // the ring
// cl_gcobject rep; // representation of the element
// The representation of the element depends on the ring, of course,
// but we constrain it to be a single pointer into the heap or an immediate
// value.
//
// Any arithmetic operation on a ring R (like +, -, *) must return a value
// with ring = R. This is
// a. necessary if the computation is to proceed correctly (e.g. in cl_RA,
// ((3/4)*4 mod 3) is 0, simplifying it to ((cl_I)4 mod (cl_I)3) = 1
// wouldn't be correct),
// b. possible even if R is an extension ring of some ring R1 (e.g. cl_N
// being an extension ring of cl_R). Automatic retraction from R to R1
// can be done through dynamic typing: An element of R which happens
// to lie in R1 is stored using the internal representation of R1,
// but with ring = R. Elements of R1 and R\R1 can be distinguished
// through rep's type.
// c. an advantage for the implementation of polynomials and other
// entities which contain many elements of the same ring. They need
// to store only the elements' representations, and a single pointer
// to the ring.
//
// The ring operations exist in two versions:
// - Low-level version, which only operates on the representation.
// - High-level version, which operates on full cl_ring_elements.
// We make this distinction for performance: Multiplication of polynomials
// over Z/nZ, operating on the high-level operations, spends 40% of its
// computing time with packing and unpacking of cl_ring_elements.
// The low-level versions have an underscore prepended and are unsafe.
class _cl_ring_element { public: cl_gcobject rep; // representation of the element
// Default constructor.
_cl_ring_element (); public: /* ugh */ // Constructor.
_cl_ring_element (const cl_heap_ring* R, const cl_gcobject& r) : rep (as_cl_private_thing(r)) { (void)R; } _cl_ring_element (const cl_ring& R, const cl_gcobject& r) : rep (as_cl_private_thing(r)) { (void)R; } public: // Ability to place an object at a given address.
void* operator new (size_t size) { return malloc_hook(size); } void* operator new (size_t size, void* ptr) { (void)size; return ptr; } void operator delete (void* ptr) { free_hook(ptr); } };
class cl_ring_element : public _cl_ring_element { protected: cl_ring _ring; // ring
public: const cl_ring& ring () const { return _ring; } // Default constructor.
cl_ring_element (); public: /* ugh */ // Constructor.
cl_ring_element (const cl_ring& R, const cl_gcobject& r) : _cl_ring_element (R,r), _ring (R) {} cl_ring_element (const cl_ring& R, const _cl_ring_element& r) : _cl_ring_element (r), _ring (R) {} public: // Debugging output.
void debug_print () const; // Ability to place an object at a given address.
void* operator new (size_t size) { return malloc_hook(size); } void* operator new (size_t size, void* ptr) { (void)size; return ptr; } void operator delete (void* ptr) { free_hook(ptr); } };
// The ring operations are encoded as vectors of function pointers. You
// can add more operations to the end of each vector or add new vectors,
// but you must not reorder the operations nor reorder the vectors nor
// change the functions' signatures incompatibly.
// There should ideally be a template class for each vector, but unfortunately
// you lose the ability to initialize the vector using "= { ... }" syntax
// when you subclass it.
struct _cl_ring_setops { // print
void (* fprint) (cl_heap_ring* R, std::ostream& stream, const _cl_ring_element& x); // equality
cl_boolean (* equal) (cl_heap_ring* R, const _cl_ring_element& x, const _cl_ring_element& y); // ...
}; struct _cl_ring_addops { // 0
const _cl_ring_element (* zero) (cl_heap_ring* R); cl_boolean (* zerop) (cl_heap_ring* R, const _cl_ring_element& x); // x+y
const _cl_ring_element (* plus) (cl_heap_ring* R, const _cl_ring_element& x, const _cl_ring_element& y); // x-y
const _cl_ring_element (* minus) (cl_heap_ring* R, const _cl_ring_element& x, const _cl_ring_element& y); // -x
const _cl_ring_element (* uminus) (cl_heap_ring* R, const _cl_ring_element& x); // ...
}; struct _cl_ring_mulops { // 1
const _cl_ring_element (* one) (cl_heap_ring* R); // canonical homomorphism
const _cl_ring_element (* canonhom) (cl_heap_ring* R, const cl_I& x); // x*y
const _cl_ring_element (* mul) (cl_heap_ring* R, const _cl_ring_element& x, const _cl_ring_element& y); // x^2
const _cl_ring_element (* square) (cl_heap_ring* R, const _cl_ring_element& x); // x^y, y Integer >0
const _cl_ring_element (* expt_pos) (cl_heap_ring* R, const _cl_ring_element& x, const cl_I& y); // ...
}; typedef const _cl_ring_setops cl_ring_setops; typedef const _cl_ring_addops cl_ring_addops; typedef const _cl_ring_mulops cl_ring_mulops;
// Representation of a ring in memory.
class cl_heap_ring : public cl_heap { public: // Allocation.
void* operator new (size_t size) { return malloc_hook(size); } // Deallocation.
void operator delete (void* ptr) { free_hook(ptr); } private: cl_property_list properties; protected: cl_ring_setops* setops; cl_ring_addops* addops; cl_ring_mulops* mulops; public: // More information comes here.
// ...
public: // Low-level operations.
void _fprint (std::ostream& stream, const _cl_ring_element& x) { setops->fprint(this,stream,x); } cl_boolean _equal (const _cl_ring_element& x, const _cl_ring_element& y) { return setops->equal(this,x,y); } const _cl_ring_element _zero () { return addops->zero(this); } cl_boolean _zerop (const _cl_ring_element& x) { return addops->zerop(this,x); } const _cl_ring_element _plus (const _cl_ring_element& x, const _cl_ring_element& y) { return addops->plus(this,x,y); } const _cl_ring_element _minus (const _cl_ring_element& x, const _cl_ring_element& y) { return addops->minus(this,x,y); } const _cl_ring_element _uminus (const _cl_ring_element& x) { return addops->uminus(this,x); } const _cl_ring_element _one () { return mulops->one(this); } const _cl_ring_element _canonhom (const cl_I& x) { return mulops->canonhom(this,x);
|