Minimal N-dimensional float array library in C++.
Checkout the documentation: https://inclinedadarsh.github.io/incliarray/.
- Tiny, readable implementation (single header + single source) focused on concepts
- Explicit shapes/strides and careful ownership rules (base vs view)
- Lightweight reverse‑mode autograd for core ops
- N‑dimensional float arrays with row‑major layout
- Safe, stride‑aware indexing:
get(std::vector<int>),set(std::vector<int>, float)- Flat
get(int),set(int)on contiguous, owning arrays only
- Introspection and layout helpers:
metadata,isContiguous,print(data or grads) - Initialization/fill:
zeros,ones,fill,fillSequentialrandint(low, high),rand()in [0,1),rand(low, high)
- Views and materialization:
slicereturns a detached, non‑owning view (shares data, no autograd linkage)clone()creates a contiguous, owning copy (detached)
- Reshape:
reshape(newShape)for contiguous, owning arrays - Broadcasting arithmetic (array ⊕ array):
+,-,/,element_wise_multiply - Scalar arithmetic (array ⊕ scalar):
+ float,- float,/ float,element_wise_multiply(float) - Element‑wise power with scalar exponent:
operator^(float) - 2D matrix multiplication:
operator*(no broadcasting) - Reductions:
sum()reduces all elements to a 1‑element arraysum(axis)keeps reduced dimension as size 1, supports negative axes
- Autograd:
- Results from core ops capture
prev,op,label backward()builds a topological order and accumulates gradients- Implemented grads for add/sub (array & scalar), div (array & scalar), element‑wise multiply (array & scalar), matrix multiply, and power (scalar exponent)
- Results from core ops capture
- Safety/constraints:
- Flat indexing and reshape are allowed only on contiguous, owning arrays
- Views are non‑owning; fill operations are disallowed on non‑owning arrays
- Division warns on divisor 0; gradient contributions on zero divisors are skipped
mkdir build && cd build
cmake ..
make
./examples/basic_scalarsExamples are built from examples/ when BUILD_EXAMPLES is ON (default). You can also run ./examples/basic_vectors if present.
See examples/README.md for details about each example.
mkdir build && cd build
cmake .. -DBUILD_EXAMPLES=OFF
sudo make installThis installs headers to /usr/local/include and the library to /usr/local/lib by default.
In your project's CMakeLists.txt:
find_package(NDArray REQUIRED)
add_executable(myapp myapp.cpp)
target_link_libraries(myapp PRIVATE NDArray)Then include it in code as:
#include <NDArray.h>If installed to default prefixes, this typically works:
g++ -std=c++17 myapp.cpp -lNDArray -o myappAnd in your code:
#include <NDArray.h>If you installed to a custom prefix, add -I<include_dir> and -L<lib_dir> accordingly.
- Install Doxygen and
graphviz:
sudo apt-get install -y doxygen graphviz- Generate docs:
./build-docs.shOpen html/index.html in your browser.
.
├── CMakeLists.txt // Library build + install rules
├── Doxyfile // Doxygen configuration
├── include/
│ ├── NDArray.h // NDArray class declaration
│ └── utils.h // Internal helpers (strides, offsets, broadcasting)
├── src/
│ ├── NDArray.cpp // NDArray implementation
│ └── utils.cpp // Helper implementations
├── examples/
│ ├── CMakeLists.txt // Example build targets
│ ├── basic_scalars.cpp
│ └── basic_vectors.cpp
├── LICENSE
└── README.md
#include <NDArray.h>
#include <iostream>
int main() {
NDArray A({2, 3});
A.fillSequential();
NDArray B({1, 3});
B.ones();
NDArray C = A + B; // broadcast add
NDArray D = C.element_wise_multiply(2.0f);
NDArray E = D - 3.0f; // scalar sub
NDArray W({3, 2});
W.randint(1, 5);
NDArray G = A * W; // 2D matmul (2x3) * (3x2)
NDArray S = G.sum(); // reduce to scalar (1)
S.backward();
std::cout << "Grad A:" << std::endl;
A.print(NDArray::PrintType::Grad);
}Built with some neovim and some maths by Adarsh Dubey.
MIT License. Do whatever you want, just don’t sue me.