⚙️ e3j-ops
This package contains the CUDA/C++ source for e3j.
The Python bindings to XLA handlers are bundled into the e3j_ops shared object, which
the main e3j package wraps in custom JAX primitives via the ffi_call API.
Note: The
e3j_opsABI should not be considered stable for now, but considered private within thee3jPython API.
Building from source
The CMake build recipes are defined in CMakeLists.txt.
The Makefile of e3j also defines fine-graind recipes to build and test individual CUDA/C++ objects.
Project structure
The source is organized as follows:
- cuda : CUDA kernel implementations
- ffi : XLA-FFI handlers declarations and pybind11 module definition
- xla : vendored XLA FFI headers
- tests : C++ kernel tests
CUDA/C++ source
Each operation is defined in its own namespace following a common interface (see e.g. tensor_product.cuh for detailed signatures):
- a namespace
e3j::op_namewithin the enclosinge3jnamespace, - a struct
e3j::op_name::Paramsfor passing hyperparameters, - a
__global__CUDA functione3j::op_name::kernel(), - a
__host__launchere3j::op_name::launch()
Although object-oriented patterns are hard to mix with __device__ code,
this name-based ABI is subject to change.
namespace e3j {
namespace op_name {
struct Params;
template <typename Idx, typename Val>
__global__ void kernel (Params p, ...);
template <typename Idx, typename Val>
e3j::Error launch (..., Params p, cudaStream_t stream);
} // namespace op_name
} // namespace e3j
Most kernels are templated across a range of index and/or value data types. Some e3j primitives automatically dispatch to narrow index dtypes (uint8 / uint16) when feature spaces dimensions are small enough. Value dtypes are float32, float64 and float16, each usable with any index dtype. Kernels compute and accumulate in the value dtype. float16 is not supported yet on the atomicAdd based paths (scatter_add_1 and the LEADING_CHANNELS tensor product), which return Unimplemented.
XLA-FFI handlers
The FFI layer uses the XLA FFI API to bind kernel launchers
as XLA custom calls. Each handler is registered with XLA_FFI_DEFINE_HANDLER,
receiving typed buffers and attributes directly (no opaque descriptor packing):
xla::Error OpNameHandler(
cudaStream_t stream,
int32_t num_out,
xla::AnyBuffer x,
xla::Result<xla::AnyBuffer> out
) {
// ... dtype dispatch ...
return e3j::op_name::launch<Idx, Val>(
x.typed_data<Idx>(),
out->typed_data<Val>(),
params, stream
).to_xla();
}
XLA_FFI_DEFINE_HANDLER(
xla_op_name,
OpNameHandler,
xla::Ffi::Bind()
.Ctx<xla::PlatformStream<cudaStream_t>>()
.Attr<int32_t>("num_out")
.Arg<xla::AnyBuffer>()
.Ret<xla::AnyBuffer>()
);
Handlers are exposed to Python as PyCapsules via pyEncapsulateFunction
in e3j_ops.h, and registered in the
pybind11 module defined in e3j_ops.cpp.
Contributing
Although it is too early for e3j_ops to accept significant external contributions, bug reports or questions are very welcome via GitHub issues and discussions.
Citing
If you use e3j within your work, we kindly ask you to cite the following preprint:
@article{Peltre26-e3j,
title = {{E3J}: an Efficient and Open-Source Euclidean Equivariance Backend},
author = {Peltre, Olivier and Picard, Armand and Pichard, Adrien and Giacomoni, Luca and Braganca, Miguel and Heyraud, Valentin and Brunken, Christoph and Tilly, Jules},
journal = {preprint},
year = {2026},
url = {(preprint)}
}
}
Release files for e3j-ops 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Built distributions (wheels)
| File | Reset | |||
|---|---|---|---|---|
| e3j_ops-0.1.0-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl | CPython 3.14 | CPython 3.14 | Linux glibc 2.24+ x86-64, Linux glibc 2.28+ x86-64 | Details |
| e3j_ops-0.1.0-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl | CPython 3.13 | CPython 3.13 | Linux glibc 2.28+ x86-64, Linux glibc 2.24+ x86-64 | Details |
| e3j_ops-0.1.0-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl | CPython 3.12 | CPython 3.12 | Linux glibc 2.24+ x86-64, Linux glibc 2.28+ x86-64 | Details |
| e3j_ops-0.1.0-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl | CPython 3.11 | CPython 3.11 | Linux glibc 2.24+ x86-64, Linux glibc 2.28+ x86-64 | Details |
Total release size: 35.9 MB
Release files / e3j_ops-0.1.0-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl
| Download URL | e3j_ops-0.1.0-cp314-cp314-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl |
|---|---|
| Size | 9.0 MB |
| Tags | CPython 3.14 Linux glibc 2.24+ x86-64 Linux glibc 2.28+ x86-64 |
|
SHA-256 checksum How to use checksums |
55058f74b2ac1fdcff51880b386b34fa9afeeac76504f759532a0fb64ad82110
|
|
BLAKE2b-256 checksum How to use checksums |
8744234b70100b79bd71905c13c1750a503c6a279170a31c9ec9b4747b0db0a3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.13
|
Release files / e3j_ops-0.1.0-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl
| Download URL | e3j_ops-0.1.0-cp313-cp313-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl |
|---|---|
| Size | 9.0 MB |
| Tags | CPython 3.13 Linux glibc 2.24+ x86-64 Linux glibc 2.28+ x86-64 |
|
SHA-256 checksum How to use checksums |
4b959231dcb2c693458710eb3036be59f776d556baa7c56ab303a308a409caa7
|
|
BLAKE2b-256 checksum How to use checksums |
21e86c55d270c7b624f37cde40c12ad545b1a0cd0921a0f18c4d42186c13b8da
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.13
|
Release files / e3j_ops-0.1.0-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl
| Download URL | e3j_ops-0.1.0-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl |
|---|---|
| Size | 9.0 MB |
| Tags | CPython 3.12 Linux glibc 2.24+ x86-64 Linux glibc 2.28+ x86-64 |
|
SHA-256 checksum How to use checksums |
ef15b95eebd6dc9b023e5d9c8aadbcad6d4e73dafbf969ea624704fb3cf499f0
|
|
BLAKE2b-256 checksum How to use checksums |
76e9f38b2934f59a065785e55fcd8691d3a9c259b6bf67a52b4b07657194b78e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.13
|
Release files / e3j_ops-0.1.0-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl
| Download URL | e3j_ops-0.1.0-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64.whl |
|---|---|
| Size | 9.0 MB |
| Tags | CPython 3.11 Linux glibc 2.24+ x86-64 Linux glibc 2.28+ x86-64 |
|
SHA-256 checksum How to use checksums |
d3a323d2f5a79b2f61fa69d32490e458c31c6526e2f2edd289493126c5025391
|
|
BLAKE2b-256 checksum How to use checksums |
d5dc080850d794f899d31fb481d6b11d66c24f2eb00396e7183440243cd0a8fb
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.13
|