9. Backend

The eminus code is written such that multiple array backends can be used. Naturally, this adds a layer of complexity. Luckily, not too much. This document will inform developers about possible intricacies.

9.1. Writing backend agnostic code

Writing backend agnostic code is most of the time straightforward. Where one normally uses NumPy, e.g., with

import numpy as np
np.ones(3)

one can now write

from eminus import backend as xp
xp.ones(3)

One caveat is that one has to type imports of submodules explicitly instead of relying on from imports.

from eminus import backend as xp
xp.linalg.det([[3]])

This is because the backend module will be determined at runtime. from imports do not support this dynamic system.

The backend can be changed using the config module with

import eminus
eminus.backend = "numpy"

Currently supported backends are NumPy and Torch.

There are a few differences between the two backends. Luckily, many can be mitigated using the array-api-compat package. In cases where this does not work, a wrapper function can be added to the backend module, e.g., to get xp.delete to work for Torch tensors.

The largest difference can be found in the strictness of types. Where NumPy easily casts types, e.g., in a matrix multiplication between a float and a complex type, Torch needs an additional cast from float to complex.

To simplify some operations, there are also helper functions available in the backend module, e.g., to check if a variable is a backend array

from eminus import backend as xp
a = xp.ones(3)
xp.is_array(a)

9.1.1. GPU

Torch supports calculations on the GPU, while NumPy does not. However, some functionalities are exclusive to NumPy (mostly in the extras). Therefore, it is sometimes needed to convert the Torch GPU tensors to NumPy CPU arrays. For this, the to_np helper function can be utilized

from eminus import backend as xp
from eminus import config

config.use_gpu = True
a = xp.ones(3)
a = xp.to_np(a)

9.1.2. Running tests

To test the functionality for a backend, one can select it by using the custom pytest --backend option. By default, the tests will be performed using NumPy. The tests are written such that they work independently of the selected backend. To test arrays that may exist on different devices or as arrays of different backends, one can use the utility functions in the testing module.