# Data structures¶

libgumath is a lightweight library for managing and dispatching computational kernels that target XND containers.

Functions are multimethods in a lookup table. Typically, applications that use libgumath should create a new lookup table for each namespace. For example, Python modules generally should have a module-specific lookup table.

## Kernel signatures¶

```
typedef int (* gm_xnd_kernel_t)(xnd_t stack[], ndt_context_t *ctx);
```

The signature of an *xnd* kernel. *stack* contains incoming and outgoing
arguments. In case of an error, kernels are expected to set a context error
message and return *-1*.

In case of success, the return value is *0*.

```
typedef int (* gm_strided_kernel_t)(char **args, intptr_t *dimensions, intptr_t *steps, void *data);
```

The signature of a NumPy compatible kernel. These signatures are for applications that want to use existing NumPy compatible kernels on XND containers.

XND containers are automatically converted to a temporary ndarray before kernel application.

## Kernel set¶

```
/* Collection of specialized kernels for a single function signature. */
typedef struct {
ndt_t *sig;
const ndt_constraint_t *constraint;
/* Xnd signatures */
gm_xnd_kernel_t C; /* dispatch ensures c-contiguous */
gm_xnd_kernel_t Fortran; /* dispatch ensures f-contiguous */
gm_xnd_kernel_t Xnd; /* selected if non-contiguous or both C and Fortran are NULL */
/* NumPy signature */
gm_strided_kernel_t Strided;
} gm_kernel_set_t;
```

A kernel set contains the function signature, an optional constraint function,
and up to four specialized kernels, each of which may be *NULL*.

The dispatch calls the kernels in the following order of preference:

If the inner dimensions of the incoming arguments are C-contiguous, the *C*
kernel is called first. In case of *Fortran* inner dimensions, *Fortran*
is called first.

If an *Xnd* kernel is present, it is called next, then the *Strided* kernel.

## Kernel set initialization¶

```
typedef struct {
const char *name;
const char *sig;
const ndt_constraint_t *constraint;
gm_xnd_kernel_t C;
gm_xnd_kernel_t Fortran;
gm_xnd_kernel_t Xnd;
gm_strided_kernel_t Strided;
} gm_kernel_init_t;
int gm_add_kernel(gm_tbl_t *tbl, const gm_kernel_init_t *kernel, ndt_context_t *ctx);
```

The *gm_kernel_init_t* is used for initializing a kernel set. Usually, a C
translation unit contains an array of hundreds of *gm_kernel_init_t* structs
together with a function that initializes a specific lookup table.

## Multimethod struct¶

```
/* Multimethod with associated kernels */
typedef struct gm_func gm_func_t;
typedef const gm_kernel_set_t *(*gm_typecheck_t)(ndt_apply_spec_t *spec,
const gm_func_t *f, const ndt_t *in[], int nin, ndt_context_t *ctx);
struct gm_func {
char *name;
gm_typecheck_t typecheck; /* Experimental optimized type-checking, may be NULL. */
int nkernels;
gm_kernel_set_t kernels[GM_MAX_KERNELS];
};
```

This is the multimethod struct for a given function name. Each multimethod has
a *nkernels* associated kernel sets with unique type signatures.

If *typecheck* is *NULL*, the generic libndtypes multimethod dispatch is used
to locate the kernel. This is an O(N) operation, whose search time is negligible
for large array operations.

The *typecheck* field can be set to an optimized lookup function that has
internal knowledge of kernel set locations. The only restriction to the
function is that it must behave exactly as the generic libndtypes typecheck.