Skip to main content

A fast tensor library in Rust

Project description

ferrix

A fast, memory-safe tensor library implemented in Rust and exposed as a Python package.

ferrix provides an NDArray core with stride-based indexing, vectorized math operations, slicing/reshaping utilities, and Python bindings via pyo3.

Why ferrix

  • Rust core for predictable performance and memory safety.
  • Python-friendly API for quick experimentation.
  • Multi-dimensional arrays with row-major strides.
  • Useful tensor operations for ML and numerical workloads.

Installation

Install from PyPI:

python -m pip install ferrix

Quick Start

import ferrix

# Create two 2x2 arrays
a = ferrix.PyNDArray([1.0, 2.0, 3.0, 4.0], [2, 2])
b = ferrix.PyNDArray([5.0, 6.0, 7.0, 8.0], [2, 2])

# Core arithmetic
print(a.add(b).get([0, 0]))      # 6.0
print(a.mul(b).get([1, 1]))      # 32.0
print(a.scale(0.5).get([1, 0]))  # 1.5

# Matrix multiplication
print(a.matmul(b).get([0, 0]))       # 19.0
print(a.matmul_blas(b).get([0, 0]))  # Compatibility API; currently same as matmul

# Activations and reductions
print(a.relu().get([0, 0]))
print(a.softmax().sum())
print(a.sum(), a.mean(), a.argmax())

# Shape transforms
print(a.transpose().shape())
print(a.reshape([4]).shape())

Complete API Reference (Python)

ferrix exposes two classes:

  • ferrix.PyNDArray for numeric tensors (f64)
  • ferrix.PyBoolArray for boolean masks

PyNDArray

Constructor:

  • PyNDArray(data: list[float], shape: list[int]) -> PyNDArray
x = ferrix.PyNDArray([1.0, 2.0, 3.0, 4.0], [2, 2])

Introspection and element access:

  • shape() -> list[int]
  • get(index: list[int]) -> float
x = ferrix.PyNDArray([1.0, 2.0, 3.0, 4.0], [2, 2])
print(x.shape())      # [2, 2]
print(x.get([1, 0]))  # 3.0

Reductions:

  • sum() -> float
  • mean() -> float
  • argmax() -> int (index in flattened row-major order)
x = ferrix.PyNDArray([1.0, 5.0, 3.0, 4.0], [2, 2])
print(x.sum())     # 13.0
print(x.mean())    # 3.25
print(x.argmax())  # 1

Element-wise math:

  • add(other: PyNDArray) -> PyNDArray
  • mul(other: PyNDArray) -> PyNDArray
  • scale(scalar: float) -> PyNDArray
a = ferrix.PyNDArray([1.0, 2.0, 3.0, 4.0], [2, 2])
b = ferrix.PyNDArray([5.0, 6.0, 7.0, 8.0], [2, 2])

print(a.add(b).get([0, 1]))   # 8.0
print(a.mul(b).get([1, 0]))   # 21.0
print(a.scale(10).get([1, 1]))  # 40.0

Activation functions:

  • relu() -> PyNDArray
  • sigmoid() -> PyNDArray
  • softmax() -> PyNDArray
x = ferrix.PyNDArray([-1.0, 0.0, 1.0], [1, 3])
print(x.relu().get([0, 0]))
print(x.sigmoid().get([0, 2]))
print(x.softmax().sum())

Matrix operations:

  • matmul(other: PyNDArray) -> PyNDArray
  • matmul_blas(other: PyNDArray) -> PyNDArray
a = ferrix.PyNDArray([1.0, 2.0, 3.0, 4.0], [2, 2])
b = ferrix.PyNDArray([5.0, 6.0, 7.0, 8.0], [2, 2])

print(a.matmul(b).get([0, 0]))
print(a.matmul_blas(b).get([0, 0]))

Note: matmul_blas is currently a compatibility API that uses the same backend behavior as matmul.

Reshape and transpose:

  • reshape(new_shape: list[int]) -> PyNDArray
  • transpose() -> PyNDArray (2D transpose)
x = ferrix.PyNDArray([1.0, 2.0, 3.0, 4.0], [2, 2])
print(x.reshape([4]).shape())
print(x.transpose().shape())

Slicing and indexing:

  • slice_row(row: int) -> PyNDArray (2D)
  • slice_col(col: int) -> PyNDArray (2D)
  • slice_range(axis: int, start: int, end: int) -> PyNDArray
  • fancy_index(indices: list[int]) -> PyNDArray (1D input)
  • gather(axis: int, indices: list[int]) -> PyNDArray
m = ferrix.PyNDArray([1.0, 2.0, 3.0, 4.0, 5.0, 6.0], [2, 3])
v = ferrix.PyNDArray([10.0, 20.0, 30.0, 40.0], [4])

print(m.slice_row(1).shape())
print(m.slice_col(2).shape())
print(m.slice_range(1, 0, 2).shape())
print(v.fancy_index([3, 1, 1]).shape())
print(m.gather(1, [2, 0]).shape())

Masking and conditional operations:

  • boolean_mask(mask: PyBoolArray) -> PyNDArray
  • masked_fill(mask: PyBoolArray, value: float) -> None (in-place)
  • where_(condition: PyBoolArray, other: PyNDArray) -> PyNDArray
x = ferrix.PyNDArray([1.0, 2.0, 3.0, 4.0], [2, 2])
y = ferrix.PyNDArray([9.0, 9.0, 9.0, 9.0], [2, 2])
mask = ferrix.PyBoolArray([True, False, True, False], [2, 2])

print(x.boolean_mask(mask).shape())
x.masked_fill(mask, -1.0)
print(x.where_(mask, y).shape())

Mutation and cumulative operations:

  • set_slice(axis: int, start: int, end: int, value: float) -> None (in-place)
  • cumsum() -> PyNDArray (flattened cumulative sum)
x = ferrix.PyNDArray([1.0, 2.0, 3.0, 4.0], [2, 2])
x.set_slice(0, 0, 1, 0.0)
print(x.get([0, 1]))
print(x.cumsum().shape())

PyBoolArray

Constructor and methods:

  • PyBoolArray(data: list[bool], shape: list[int]) -> PyBoolArray
  • shape() -> list[int]
mask = ferrix.PyBoolArray([True, False, True, False], [2, 2])
print(mask.shape())

Error Behavior

  • Invalid shapes, indices, or axis values raise Python exceptions backed by Rust panics.
  • Most binary operations require shape compatibility.
  • fancy_index is for 1D arrays.
  • transpose and slice_row/slice_col require 2D arrays.

Feature Notes

  • Arrays are row-major and stride-aware.
  • Shape checks and index checks panic on invalid inputs in the Rust core.
  • matmul_blas is currently a compatibility method that falls back to the same implementation as matmul.
  • Parallel execution is used for selected element-wise operations through rayon.

Benchmarks (Indicative)

The following numbers are from repository examples and should be treated as indicative (hardware and build mode dependent):

Operation ferrix NumPy
matmul 512x512 6.5 ms 2.1 ms
relu 1M elements 0.52 ms 0.76 ms

Build From Source (Optional)

This project uses maturin to build the Python extension from Rust.

Prerequisites

  • Rust toolchain (cargo, rustc)
  • Python >=3.8
  • maturin

Local development build

python -m pip install --upgrade pip maturin
maturin develop

After this, import ferrix uses your local build in the active virtual environment.

Build wheel/sdist

rm -rf dist
maturin build --release --out dist
maturin sdist --out dist

Release and Publishing

For a complete PyPI release runbook, see:

  • docs/pypi-guide.md

It includes versioning rules, artifact validation, upload options, and post-release checks.

Repository Layout

Key files and directories:

  • src/lib.rs: Rust tensor core (NDArray and NDArrayView)
  • src/python.rs: Python bindings (PyNDArray, PyBoolArray)
  • src/tests/: Rust unit tests
  • test_ferrix.py: Python API tests
  • pyproject.toml: Python packaging metadata and build backend
  • Cargo.toml: Rust crate configuration

Contributing

Contributions are welcome.

For contributions and release process details, start from docs/pypi-guide.md and open a PR with clear change notes.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

ferrix-0.1.6-cp311-cp311-win_amd64.whl (198.8 kB view details)

Uploaded CPython 3.11Windows x86-64

ferrix-0.1.6-cp311-cp311-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl (621.8 kB view details)

Uploaded CPython 3.11macOS 10.12+ universal2 (ARM64, x86-64)macOS 10.12+ x86-64macOS 11.0+ ARM64

ferrix-0.1.6-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (362.6 kB view details)

Uploaded CPython 3.8manylinux: glibc 2.17+ x86-64

File details

Details for the file ferrix-0.1.6-cp311-cp311-win_amd64.whl.

File metadata

  • Download URL: ferrix-0.1.6-cp311-cp311-win_amd64.whl
  • Upload date:
  • Size: 198.8 kB
  • Tags: CPython 3.11, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: maturin/1.13.1

File hashes

Hashes for ferrix-0.1.6-cp311-cp311-win_amd64.whl
Algorithm Hash digest
SHA256 57bae39558d6b8f312c19ea2e39ce9793eeae881f97f2b240ae63d8469ae921b
MD5 9580dfbf0d57bc05645b7e40addc305a
BLAKE2b-256 f13d9f25dc17004bef954b88f32dfa278eef1289ec5079989fea7cef3e7fac07

See more details on using hashes here.

File details

Details for the file ferrix-0.1.6-cp311-cp311-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl.

File metadata

File hashes

Hashes for ferrix-0.1.6-cp311-cp311-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl
Algorithm Hash digest
SHA256 b69b1c7e9274d7b1df522f5fdb44c3b2acb619e6d2a8382634f9fc7ffb36ae7e
MD5 0e1c762b5da85d6ece12f6f1fed43bff
BLAKE2b-256 40d3c6af234437dbbd939c4c0a280871f675e93de7c3da39724b44cc538d0d2d

See more details on using hashes here.

File details

Details for the file ferrix-0.1.6-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for ferrix-0.1.6-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 8c2799b10d312116081bfa9c43bf07ce43f2efe24aa2648c80832910fb84c570
MD5 07cdf396e339a91574be6873cc29f76c
BLAKE2b-256 530bbba9ab98240d5b15bb8ef6e1ff1bd84d32d554e1cdb17162b12443e20a2c

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page