.. _gr-implementing: **gr.h (continued)** -- implementing rings =============================================================================== .. highlight:: c Defining a ring requires putting appropriate data into a :type:`gr_ctx_t` parent object, most importantly the method table and the size of elements. Example -------------------------------------------------------------------------------- This is an extract from the ``fmpz`` wrapper in ``gr/fmpz.c``:: /* Some methods */ ... int _gr_fmpz_add(fmpz_t res, const fmpz_t x, const fmpz_t y, const gr_ctx_t ctx) { fmpz_add(res, x, y); return GR_SUCCESS; } ... /* The method table */ int _fmpz_methods_initialized = 0; gr_static_method_table _fmpz_methods; gr_method_tab_input _fmpz_methods_input[] = { {GR_METHOD_CTX_IS_RING, (gr_funcptr) gr_generic_ctx_predicate_true}, ... {GR_METHOD_INIT, (gr_funcptr) _gr_fmpz_init}, {GR_METHOD_CLEAR, (gr_funcptr) _gr_fmpz_clear}, ... {GR_METHOD_ADD_FMPZ, (gr_funcptr) _gr_fmpz_add}, ... {0, (gr_funcptr) NULL}, }; /* Context object initializer */ void gr_ctx_init_fmpz(gr_ctx_t ctx) { ctx->which_ring = GR_CTX_FMPZ; ctx->sizeof_elem = sizeof(fmpz); ctx->size_limit = WORD_MAX; ctx->methods = _fmpz_methods; if (!_fmpz_methods_initialized) { gr_method_tab_init(_fmpz_methods, _fmpz_methods_input); _fmpz_methods_initialized = 1; } } Note that the method table only has to be constructed once, allowing new context objects for the same domain to be initialized cheaply. Method table -------------------------------------------------------------------------------- .. type:: gr_funcptr Typedef for a pointer to a function with signature ``int func(void)``, used to represent method table entries. .. type:: gr_method Enumeration type for indexing method tables. Enum values named ``GR_METHOD_INIT``, ``GR_METHOD_ADD_UI``, etc. correspond to methods ``gr_init``, ``gr_add_ui``, etc. The number of methods is given by ``GR_METHOD_TAB_SIZE``, which can be used to declare static method tables. .. type:: gr_static_method_table Typedef for an array of length ``GR_METHOD_TAB_SIZE`` with :type:`gr_funcptr` entries. .. type:: gr_method_tab_input Typedef representing a (index, function pointer) pair. .. function:: void gr_method_tab_init(gr_funcptr * methods, gr_method_tab_input * tab) Initializes the method table *methods*. This first inserts default and generic methods in all slots, and then overwrites with the specialized methods listed in *tab*. Placeholder and trivial methods -------------------------------------------------------------------------------- .. function:: int gr_not_implemented(void) This function does nothing and returns ``GR_UNABLE``. It is used as a generic fallback method when no implementation is available. .. function:: int gr_not_in_domain(void) This function does nothing and returns ``GR_DOMAIN``. It can be used for an operation that never makes sense in the present domain, e.g.\ for the constant `\pi` in the rational numbers. .. function:: truth_t gr_generic_ctx_predicate(gr_ctx_t ctx) Does nothing and returns ``T_UNKNOWN``, used as a generic fallback for predicate methods. .. function:: truth_t gr_generic_ctx_predicate_true(gr_ctx_t ctx) A predicate that does nothing and returns ``T_TRUE``. .. function:: truth_t gr_generic_ctx_predicate_false(gr_ctx_t ctx) A predicate that does nothing and returns ``T_FALSE``. Required methods -------------------------------------------------------------------------------- A context object must at minimum define the following methods for a ring: * ``init`` * ``clear`` * ``swap`` * ``randtest`` * ``write`` * ``zero`` * ``one`` * ``equal`` * ``set`` * ``set_si`` * ``set_ui`` * ``set_fmpz`` * ``neg`` * ``add`` * ``sub`` * ``mul`` Other methods have generic defaults which may be overridden for performance or completeness. Implementing context predicates (``ctx_is_integral_domain``, ``ctx_is_field``, etc.) is strongly recommended so that the most appropriate algorithms can be used in generic implementations. Rings with cheap operations on single elements should also provide non-generic versions of performance-critical vector operations to minimize overhead. The most important vector operations include: * ``vec_init`` * ``vec_clear`` * ``vec_swap`` * ``vec_zero`` * ``vec_neg`` * ``vec_add`` * ``vec_sub`` * ``vec_mul_scalar_ui``/``si`` * ``vec_addmul_scalar_ui``/``si`` * ``vec_dot`` * ``vec_dot_rev`` Dot products, for example, are the main building block for classical polynomial multiplication and matrix multiplication. The methods * ``poly_mullow`` * ``matrix_mul`` should be overridden for rings where faster-than-classical polynomial and matrix multiplication is possible. Other higher-complexity generic algorithms will try to reduce to polynomial and matrix multiplication automatically, but may in turn need to be overridden to select accurate cutoffs between different algorithms. Testing rings -------------------------------------------------------------------------------- .. function:: void gr_test_ring(gr_ctx_t R, slong iters, int test_flags) Test correctness of the ring *R*. This calls test functions for various methods, each being repeated up to *iters* times. .. raw:: latex \newpage