Library / SDK
mratsim/Arraymancer avatar
mratsim/Arraymancer

Arraymancer: A Nim Tensor Library for CPU, CUDA and OpenCL

A fast, ergonomic and portable tensor library in Nim with a deep learning focus for CPU, GPU and embedded devices via OpenMP, Cuda and OpenCL backends

1,407 stars101 forksNimApache-2.0

At a glance

What is it?
Arraymancer is an N-dimensional array and autograd library written in Nim. It targets numerical computing, classical machine learning and deep learning across CPU, CUDA and OpenCL backends, but its last tagged release predates the current master branch by several years.
Who is it for?
Adopt Arraymancer if you already write Nim and want a tensor type with slicing, broadcasting and an autograd context without leaving the language, or if you need to target CUDA and OpenCL from one codebase. Do not adopt it if you need a stable tagged release with an active changelog, or if your team cannot build against master.
Can I use it commercially?
Yes. Apache-2.0 is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 112 days ago.
What is it written in?
Mainly Nim, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 16, 2026, and from our analysis. They are not legal advice.

DEEP OPEN-SOURCE ANALYSIS

What Arraymancer Is Trying to Be

Arraymancer is an N-dimensional array project written in Nim. The README describes the main focus as providing a fast and ergonomic CPU, Cuda and OpenCL ndarray library on which to build a scientific computing ecosystem, with Numpy and PyTorch named as inspirations. Three use cases are listed: N-dimensional arrays for numerical computing, machine learning algorithms in the Scikit-learn sense (least squares solvers, PCA and dimensionality reduction, classifiers, regressors, clustering, cross-validation), and deep learning. The ndarray component is explicitly separable: the README states it can be used without the machine learning and deep learning parts, and that it can use the OpenMP, Cuda or OpenCL backends. That layering matters for evaluation, because it means the tensor type is the product and the neural network code is an application of it. The intended audience is Nim programmers who want numerical work in the same language as the rest of their program, rather than a Python process calling into a C extension. The README also makes a language-level argument: Nim is compiled and has no interactive REPL like Jupyter, but the author claims much faster prototyping than C++ because Arraymancer compiles in about 5 seconds on a dual-core MacBook. That is the author's own measurement on his own machine, not a general benchmark.

The Tensor Type, Slicing and Broadcasting in Practice

The README preview shows the shape of the API. Tensors are created from sequences with toTensor, including nested sequences, and the printed form carries the element type, the shape and the backend: Tensor[system.int] of shape "[5, 5]" on backend "Cpu". Slicing uses Nim ranges, so foo[1..2, 3..4] selects a sub-block. Reversal is expressed with an underscore and a negative index, foo[_|-1, _], which reverses row order. Reshaping and concatenation are shown with reshape(3,2) and concat(a, b, c0, axis = 0), including concatenation along axis 1. Broadcasting uses a dotted operator form, j +. k, with the example adding a [4,1] tensor to a [1,3] tensor to produce a [4,3] result. That dotted operator convention is worth noting: elementwise and broadcasting operations are distinguished from plain Nim operators at the call site, which keeps the semantics visible in the source but means you cannot paste ordinary arithmetic and expect tensor broadcasting. The backend tag in the printed representation is a useful debugging affordance, since a tensor that silently ended up on the CPU when you expected a GPU is a common source of confusion in multi-backend libraries.

Autograd, Contexts and the Two-Layer Example

The neural network example, from examples/ex03_simple_two_layers.nim, is a fully-connected ReLU network with one hidden layer trained to predict y from x by minimizing squared Euclidean distance. The dimensions are set as N, D_in, H, D_out equal to 64, 1000, 100 and 10. The mechanism shown is a context object: let ctx = newContext Tensor[float32] creates the autograd context that holds the computational graph. Inputs are wrapped with ctx.variable(randomTensor[float32](N, D_in, 1'f32)), while the target y is a plain randomTensor and is not wrapped. That distinction is the clearest signal of the design: variables participate in the graph, plain tensors are data. The context is parameterized by the element type, so the graph is built for Tensor[float32] here. The README excerpt stops before the model definition, so the loss, backward and optimizer calls are not visible in the supplied material, and I will not describe them. What can be said is that the autograd entry point is a context you construct explicitly and thread through the model, rather than a global tape or a decorator.

Compilation Flags and the BLAS/LAPACK Dependency

Arraymancer is configured at compile time through Nim define flags, listed in the README. Release and danger modes are -d:release and -d:danger, the latter disabling runtime checks such as array bounds checking. BLAS and LAPACK are selected with -d:blas=blaslibname and -d:lapack=lapacklibname. If you do not define these, the README states Arraymancer tries to find a BLAS library automatically, for example blas.so, blas.dll or libopenblas.dll, on your path, and the same for LAPACK. The older flags -d:mkl and -d:openblas are deprecated; the README says to use -d:blas=mkl -d:lapack=mkl or -d:blas=openblas -d:lapack=openblas instead, and only when you want to force a specific library rather than let discovery run. Multithreading is enabled with -d:openmp. GPU support is -d:cuda, and -d:cudnn implies -d:cuda. There is also -d:avx512, which supplies -mavx512dq to gcc or clang; the README notes that without this flag the binary does not use AVX512 even on CPUs that support it, and that setting it makes the binary incompatible with CPUs lacking AVX512. That is a deployment constraint, not just a build tuning knob. The README points at nim.cfg for tuning library paths, and says the defaults should work on Mac and Linux, and on Windows after downloading libopenblas.dll or another BLAS/LAPACK DLL and placing it in a folder on your path or in the compilation output folder.

Where the Project's Own Metadata Should Give You Pause

Two facts stand out. The stability badge in the README reads experimental. The most recent tagged release is v0.7.0, named Memories of Ice, dated 2021-07-04, followed by v0.6.1 in 2020 and v0.6.0 in 2020. Meanwhile the repository's last push is 2026-05-26. The gap between the newest tag and the newest commit means the master branch carries years of work that no release captures. Anyone installing from a tagged release is not installing what the maintainer is working on, and anyone installing from master is depending on untagged code. The README itself references this indirectly: the AVX512 flag is annotated as coming from v0.7.9, a version that does not appear in the release list supplied here. So the documentation already describes behaviour beyond the latest tag. This is the single most important thing to verify before adopting, and it is not a criticism of the code so much as a statement about what you are actually pulling. The Apache-2.0 licence is permissive and includes a patent grant; that is a statement about the licence text, not legal advice, and if you redistribute binaries you should read the notice and attribution requirements yourself.

A Real Alternative and the Actual Difference

The obvious comparison is PyTorch, which the README names as an inspiration. The difference is not in the tensor abstraction, which is deliberately similar, but in what sits around it. PyTorch ships a Python interpreter with an interactive workflow, a large set of prebuilt wheels, and a CUDA stack that users typically install rather than compile. Arraymancer requires a Nim toolchain, a working BLAS and LAPACK installation discovered at compile time or named explicitly, and a recompile for each backend and flag combination you want: -d:openmp for threads, -d:cuda for GPU, -d:cudnn for cuDNN, -d:avx512 for that instruction set. You pay build complexity and gain a single compiled binary with no Python runtime and no interpreter overhead at execution time. The README's own framing supports this: it argues Nim gives faster prototyping than C++ because of short compile times, not that it beats Python for interactivity. If your work is exploratory and lives in notebooks, the compile-and-run loop is the wrong shape. If your work is a shipped binary that happens to need tensors, the trade goes the other way. Choose on that axis rather than on API familiarity, because the API is the part that will feel familiar either way.

Maintenance Cost and What to Check Before You Commit

The maintenance surface here is mostly build-time. You are responsible for a BLAS and LAPACK library being present and discoverable, and the README's guidance for Windows is manual: download libopenblas.dll or another BLAS/LAPACK DLL and copy it into a folder on your path or into the compilation output folder. The nim.cfg file is where library paths are tuned, and the README warns you may want to adjust it after installation for OpenBLAS, MKL and Cuda compilation. Upgrades are complicated by the release gap described above: pinning to v0.7.0 gives you a fixed point but forgoes years of master work, while tracking master gives you current code with no version number to cite in a bug report. A practical check is to build the two-layer example from examples/ex03_simple_two_layers.nim on your target platform with the exact flags you intend to ship, because that exercises Tensor[float32], the autograd context, randomTensor and the BLAS path in one go. If that compiles and runs, the rest of the surface is likely reachable; if it does not, you have found the problem before writing any model code. The Apache-2.0 licence permits commercial use and modification, subject to its notice requirements, but confirming that is your call and not something this review can settle.

Editorial conclusion

Adopt Arraymancer if you already write Nim and want a tensor type with slicing, broadcasting and an autograd context without leaving the language, or if you need to target CUDA and OpenCL from one codebase. Do not adopt it if you need a stable tagged release with an active changelog, or if your team cannot build against master. Before committing, verify that a BLAS and LAPACK library resolves on your platform, that the flags you need (-d:openmp, -d:cuda, -d:cudnn) compile with your Nim version, and that the API you plan to use exists on master rather than only in the v0.7.0 tag.

Official sources

  1. License: Apache-2.0
  2. mratsim/Arraymancer on GitHub
  3. Project website
  4. README
  5. Releases
Community notes

Community notes