Packages
Eigen-backed CPU Nx backend, packaged as a mob plugin. The always-available baseline for on-device ML (no GPU required); cross-compiled to a static lib<>.a and linked into the app via the cpp_archive plugin contribution.
Current section
Files
Jump to
Current section
Files
mob_nx_eigen
README.md
README.md
# mob_nx_eigen
Eigen-backed CPU [Nx](https://github.com/elixir-nx/nx) backend, packaged as a
[mob](https://github.com/GenericJam/mob) plugin.
This is the **always-available baseline** for on-device numerics. Eigen is a
header-only C++ template library (NEON-vectorised on ARM), so it needs no GPU
and runs anywhere mob runs — iOS and Android, any chip. GPU-accelerated
backends (Vulkan, MLX, TFLite) layer on top where a device supports them;
NxEigen is the fallback that always works.
## How it's built
The NIF is a C++ `:cpp_archive` plugin contribution: mob_dev's
`MobDev.Plugin.CppArchive` cross-compiles it to `libnx_eigen.a` per target ABI
and static-links it into the app's single signed native binary (required —
Android `RTLD_LOCAL` hides the BEAM's `enif_*` symbols from a separately-loaded
`.so`, and iOS forbids `dlopen`). It references NxEigen's own NIF source + Fine
headers straight from its deps (`{:dep, …}` tokens) and ships the Eigen-FFT
bridge itself (`c_src/`).
**Eigen headers** are fetched at compile time by the bundled `eigen_headers` Mix
compiler into `eigen-3.4.0/` (gitignored) — the published `nx_eigen` hex package
downloads Eigen in its own Makefile and ships a precompiled `.so`, so a clean
`mix deps.get` has no Eigen for the source cross-compile to reference. Set
`EIGEN_DIR` to a local Eigen 3.4.0 checkout to skip the download.
> **Android ABI:** since mob_dev 0.7.13 the `cpp_archive` is cross-compiled for
> the `x86_64` emulator ABI too, so an x86_64 build links. mob_dev (0.7.17)
> still installs the `nx_eigen` OTP library the NIF loads from only for
> arm64-v8a / armeabi-v7a (`MobDev.NativeBuild.install_nx_eigen_otp_libs/1`),
> so on an x86_64 emulator the NIF does not load and `configure/0` falls back
> to `Nx.BinaryBackend`. Use an arm device or emulator for NxEigen itself.
Requires a mob_dev with `cpp_archive` + the `ANDROID_HOME`-aware NDK resolution
(≥ the release carrying MOB-89).
## Use
```elixir
# mix.exs
{:mob_nx_eigen, "~> 0.1"}
# mob.exs
config :mob, :plugins, [:mob_nx_eigen]
```
The plugin's `lifecycle.on_start` calls `MobNxEigen.configure/0` at app boot,
which makes `NxEigen.Backend` the global Nx backend (falling back to
`Nx.BinaryBackend` if the NIF can't load).
`mix mob.selftest` runs `MobNxEigen.SelfTest` on the device: `Nx.dot/2` and `Nx.fft/1` on `NxEigen.Backend` (a skip on x86 Android without the `nx_eigen` OTP library, see above).
## Status
Replaces the bespoke `nxeigen` hooks that used to live in mob_dev core
(`mix mob.enable nxeigen`). Verified on an iOS simulator and an arm64 Android
emulator by the self-test (MOB-418).