# gr.h (continued) – implementing rings

Defining a ring requires putting appropriate data into a `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 `gr_funcptr` entries.

type gr_method_tab_input

  Typedef representing a (index, function pointer) pair.

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

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.

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.

truth_t gr_generic_ctx_predicate(gr_ctx_t ctx)

  Does nothing and returns `T_UNKNOWN`, used as a generic fallback for predicate methods.

truth_t gr_generic_ctx_predicate_true(gr_ctx_t ctx)

  A predicate that does nothing and returns `T_TRUE`.

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

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.