RepoPilotOpen in app →

rust-ndarray/ndarray

ndarray: an N-dimensional array with array views, multidimensional slicing, and efficient operations

Healthy

Healthy across the board

weakest axis
Use as dependencyHealthy

Permissive license, no critical CVEs, actively maintained — safe to depend on.

Fork & modifyHealthy

Has a license, tests, and CI — clean foundation to fork and modify.

Learn fromHealthy

Documented and popular — useful reference codebase to read through.

Deploy as-isHealthy

No critical CVEs, sane security posture — runnable as-is.

  • Last commit 3mo ago
  • 20 active contributors
  • Apache-2.0 licensed
Show all 6 evidence items →
  • CI configured
  • Tests present
  • Concentrated ownership — top contributor handles 51% of recent commits

Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests

Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.

Embed the "Healthy" badge

Paste into your README — live-updates from the latest cached analysis.

Variant:
RepoPilot: Healthy
[![RepoPilot: Healthy](https://repopilot.app/api/badge/rust-ndarray/ndarray)](https://repopilot.app/r/rust-ndarray/ndarray)

Paste at the top of your README.md — renders inline like a shields.io badge.

Preview social card (1200×630)

This card auto-renders when someone shares https://repopilot.app/r/rust-ndarray/ndarray on X, Slack, or LinkedIn.

Onboarding doc

Onboarding: rust-ndarray/ndarray

Generated by RepoPilot · 2026-05-09 · Source

🤖Agent protocol

If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:

  1. Verify the contract. Run the bash script in Verify before trusting below. If any check returns FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding.
  2. Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
  3. Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/rust-ndarray/ndarray shows verifiable citations alongside every claim.

If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.

🎯Verdict

GO — Healthy across the board

  • Last commit 3mo ago
  • 20 active contributors
  • Apache-2.0 licensed
  • CI configured
  • Tests present
  • ⚠ Concentrated ownership — top contributor handles 51% of recent commits

<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>

Verify before trusting

This artifact was generated by RepoPilot at a point in time. Before an agent acts on it, the checks below confirm that the live rust-ndarray/ndarray repo on your machine still matches what RepoPilot saw. If any fail, the artifact is stale — regenerate it at repopilot.app/r/rust-ndarray/ndarray.

What it runs against: a local clone of rust-ndarray/ndarray — the script inspects git remote, the LICENSE file, file paths in the working tree, and git log. Read-only; no mutations.

| # | What we check | Why it matters | |---|---|---| | 1 | You're in rust-ndarray/ndarray | Confirms the artifact applies here, not a fork | | 2 | License is still Apache-2.0 | Catches relicense before you depend on it | | 3 | Default branch master exists | Catches branch renames | | 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code | | 5 | Last commit ≤ 110 days ago | Catches sudden abandonment since generation |

<details> <summary><b>Run all checks</b> — paste this script from inside your clone of <code>rust-ndarray/ndarray</code></summary>
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of rust-ndarray/ndarray. If you don't
# have one yet, run these first:
#
#   git clone https://github.com/rust-ndarray/ndarray.git
#   cd ndarray
#
# Then paste this script. Every check is read-only — no mutations.

set +e
fail=0
ok()   { echo "ok:   $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }

# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
  echo "FAIL: not inside a git repository. cd into your clone of rust-ndarray/ndarray and re-run."
  exit 2
fi

# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "rust-ndarray/ndarray(\\.git)?\\b" \\
  && ok "origin remote is rust-ndarray/ndarray" \\
  || miss "origin remote is not rust-ndarray/ndarray (artifact may be from a fork)"

# 2. License matches what RepoPilot saw
(grep -qiE "^(Apache-2\\.0)" LICENSE 2>/dev/null \\
   || grep -qiE "\"license\"\\s*:\\s*\"Apache-2\\.0\"" package.json 2>/dev/null) \\
  && ok "license is Apache-2.0" \\
  || miss "license drift — was Apache-2.0 at generation time"

# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
  && ok "default branch master exists" \\
  || miss "default branch master no longer exists"

# 4. Critical files exist
test -f "src/lib.rs" \\
  && ok "src/lib.rs" \\
  || miss "missing critical file: src/lib.rs"
test -f "src/dimension/mod.rs" \\
  && ok "src/dimension/mod.rs" \\
  || miss "missing critical file: src/dimension/mod.rs"
test -f "src/data_traits.rs" \\
  && ok "src/data_traits.rs" \\
  || miss "missing critical file: src/data_traits.rs"
test -f "src/arraytraits.rs" \\
  && ok "src/arraytraits.rs" \\
  || miss "missing critical file: src/arraytraits.rs"
test -f "src/dimension/ndindex.rs" \\
  && ok "src/dimension/ndindex.rs" \\
  || miss "missing critical file: src/dimension/ndindex.rs"

# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 110 ]; then
  ok "last commit was $days_since_last days ago (artifact saw ~80d)"
else
  miss "last commit was $days_since_last days ago — artifact may be stale"
fi

echo
if [ "$fail" -eq 0 ]; then
  echo "artifact verified (0 failures) — safe to trust"
else
  echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/rust-ndarray/ndarray"
  exit 1
fi

Each check prints ok: or FAIL:. The script exits non-zero if anything failed, so it composes cleanly into agent loops (./verify.sh || regenerate-and-retry).

</details>

TL;DR

ndarray is a Rust library that provides N-dimensional array containers with support for owned arrays, views, arbitrary-step slicing, and efficient numeric operations. It's the NumPy equivalent for Rust, enabling multidimensional data manipulation with optional transparent BLAS acceleration for matrix multiplication and performance-critical numeric workloads. Monorepo with /src core library (the main ndarray crate), /crates subdirectory containing specialized test suites (blas-tests/, numeric-tests/, serialization-tests/, blas-mock-tests/, ndarray-gen/) for isolated testing of optional features, and /benches containing micro-benchmarks for construction, iteration, GEMM operations, and parallel workloads.

👥Who it's for

Rust systems programmers, numerical computing researchers, and data scientists building performance-critical applications (scientific computing, machine learning, image processing) who need NumPy-like ergonomics without Python's runtime overhead. Contributors are typically domain experts in linear algebra, BLAS integration, or high-performance computing.

🌱Maturity & risk

Production-ready and actively maintained. The crate shows 1.3M lines of Rust code, comprehensive CI/CD (ci.yaml, latest-deps.yaml workflows), extensive test suites in crates/ subdirectories (blas-tests, numeric-tests, serialization-tests), and clear semver discipline. However, the README explicitly states 'breaking changes are expected during evolution' (currently v0.17.2), indicating intentional API evolution rather than full stability.

Low to moderate risk for consumers; high risk for tight integration. Dependencies are minimal and well-maintained (num-traits, num-integer, num-complex, matrixmultiply); the matrixmultiply backend is actively updated. Risk vectors: (1) Feature-flagged BLAS support (cblas-sys, libc) adds conditional complexity, (2) Rayon parallelization introduces threading semantics, (3) No single-maintainer risk visible but breaking API changes documented, (4) std is default but no-std support requires feature management.

Active areas of work

Active development indicated by ci.yaml (continuous integration), latest-deps.yaml (dependency freshness testing), and matrixmultiply 0.3.2 with threading support newly exposed via matrixmultiply-threading feature. Recent expansion of test coverage via separate crates suggests ongoing hardening of BLAS and numeric correctness. Version 0.17.2 represents recent release.

🚀Get running

git clone https://github.com/rust-ndarray/ndarray.git
cd ndarray
cargo build
cargo test
cargo bench --bench iter

Daily commands: This is a library crate. Run tests: cargo test (full suite with all features), cargo test --no-default-features (no-std check), cargo test --features 'blas rayon' (optional features). Run benchmarks: cargo bench (all benches), cargo bench --bench iter (specific benchmark).

🗺️Map of the codebase

  • src/lib.rs — Main library entry point defining the Array type and core public API; every contributor must understand the top-level module structure and type exports
  • src/dimension/mod.rs — Dimension trait and implementations (Dim0–Dim6, Dynamic) that define how array shapes are represented; fundamental to all array operations
  • src/data_traits.rs — Core traits (Data, DataMut, RawData, RawDataClone) defining ownership and borrowing semantics for array backing storage
  • src/arraytraits.rs — Defines the Array type struct and core indexing/iteration traits; central to understanding how arrays behave
  • src/dimension/ndindex.rs — Multi-dimensional indexing logic enabling efficient iteration and slicing across all dimensions
  • Cargo.toml — Project configuration, feature flags, and dependency management; critical for building and testing the crate
  • src/dimension/broadcast.rs — Broadcasting logic for shape alignment in element-wise operations; core to vectorized computations

🧩Components & responsibilities

  • Dimension trait & implementations (Ix0–Ix6, IxDyn) (Rust generics, macros) — Define shape, rank, stride calculations, and iteration bounds for any dimension type
    • Failure mode: Incorrect stride or bound calculation → out-of-bounds memory access or silent data corruption

🛠️How to make changes

Add a new array method (e.g., custom reduction)

  1. Define the method trait on the Array type in src/arraytraits.rs or appropriate module (src/arraytraits.rs)
  2. Implement using dimension-aware iteration from src/dimension/ndindex.rs (src/dimension/ndindex.rs)
  3. Add tests in a test module at the bottom of your implementation file (src/arraytraits.rs)
  4. Add a benchmark in benches/ if performance-critical (benches/bench1.rs)

Support a new dimension type (fixed-rank array)

  1. Add a new dimension type in src/dimension/dim.rs using the Ix macro (src/dimension/dim.rs)
  2. Register the type in src/dimension/mod.rs and ensure it implements the Dimension trait (src/dimension/mod.rs)
  3. Create a type alias in src/aliases.rs (e.g., Array7<T> = Array<T, Ix7>) (src/aliases.rs)
  4. Re-export from src/lib.rs (src/lib.rs)

Add element-wise or axis-wise operation (e.g., zip with new combinator)

  1. Define the operation trait/struct in src/zip/ or a new module (src/lib.rs)
  2. Implement broadcasting logic using src/dimension/broadcast.rs (src/dimension/broadcast.rs)
  3. Integrate with multi-dimensional iteration from src/dimension/ndindex.rs (src/dimension/ndindex.rs)
  4. Add tests and example in examples/ (e.g., examples/zip_many.rs) (examples/zip_many.rs)

🔧Why these technologies

  • Generic Array<T, D> with phantom-type dimensions — Enables compile-time shape checking for fixed-rank arrays (Ix1–Ix6) while supporting dynamic shapes (IxDyn) without runtime overhead for known dimensions
  • RawData trait with DataMut/Data subtypes — Decouples memory management from array logic, enabling zero-copy views and custom data containers (e.g., for GPU or memory-mapped data)
  • Dimension trait with macro-generated types — Provides unified interface for all rank types while macro-generation avoids boilerplate and ensures consistency
  • NDIndex multi-dimensional iteration — Efficiently traverses arrays of any rank in row-major order without recursion or indirection, critical for performance-sensitive operations
  • Feature flags (blas, serde, rayon) — Keeps minimal dependencies for core functionality while enabling optional integrations with BLAS libraries, serialization, and parallelism

⚖️Trade-offs already made

  • Fixed-rank dimensions (Ix0–Ix6) as separate types vs. fully dynamic

    • Why: Compile-time rank checking catches errors early and enables optimizations; user chooses between speed and flexibility
    • Consequence: Users must pick array rank at creation time; mixing Ix2 and Ix3 requires runtime polymorphism or refactoring
  • Row-major (C) memory layout as default

    • Why: Common in scientific computing; simplifies iteration and cache locality for most use cases
    • Consequence: Column-major (Fortran) operations are less efficient; users must transpose or use custom layouts
  • No implicit broadcasting in indexing; explicit zip for element-wise ops

    • Why: Avoids hidden allocations and makes performance characteristics clear; user control
    • Consequence: More verbose than NumPy; requires learning zip/map_inplace patterns
  • Zero-copy slicing and views over copying

    • Why: Maximizes performance for large arrays and chained operations
    • Consequence: Lifetime tracking required; borrowing rules can be complex for nested operations

🚫Non-goals (don't propose these)

  • Automatic BLAS/GPU dispatch (available via optional ndarray-linalg crate, not built-in)
  • NumPy API compatibility (distinct Rust design; interop via bindings)
  • Sparse array support (out of scope; separate crates like sprs handle this)
  • Real-time constraint guarantees (no embedded RTOS support)
  • Distributed/cluster computing (single-node focus; use with rayon/MPI externally)

🪤Traps & gotchas

(1) BLAS feature complexity: blas feature requires external BLAS library (OpenBLAS, MKL, Accelerate) set up via blas-src crate—tests in crates/blas-tests/ will silently skip if misconfigured, masking integration bugs. (2) Dimension type rigidity: Arrays require compile-time dimension specification; switching from Ix2 to IxDyn requires type-level refactoring, not just data migration. (3) Rayon thread-local state: rayon feature enables parallel iteration but introduces implicit global thread pool initialization (no explicit pool control exposed). (4) no-std requires careful feature disabling: methods like linspace, logspace, std_axis, var_axis are gated behind std feature; consumers building no-std must audit which Array methods they call. (5) matrixmultiply-threading is separate from rayon: enabling threading for matrixmultiply does not automatically use rayon; it uses separate threading via matrixmultiply crate.

🏗️Architecture

💡Concepts to learn

  • Strided array views — Core feature enabling efficient slicing with arbitrary step sizes and negative indices without copying; understanding memory layout (Fortran vs C order, strides) is essential for performance debugging
  • BLAS/GEMM (General Matrix Multiply) — Pluggable backend for matrix multiplication; ndarray transparently dispatches to system BLAS (OpenBLAS, MKL) or falls back to matrixmultiply—understanding when BLAS is invoked is critical for performance profiling
  • Broadcast semantics — Array operations automatically broadcast lower-rank arrays to match higher ranks (e.g., adding 1D vector to 2D matrix); this implicit behavior reduces code verbosity but requires understanding dimension alignment rules
  • Type-level dimension tracking (Ix0–Ix6, IxDyn) — Rust's type system encodes array dimensionality at compile time, enabling zero-cost abstractions and compiler-verified indexing; shifting between fixed and dynamic ranks requires understanding the dimension type hierarchy
  • Data ownership and borrowing patterns (Array vs ArrayView) — ndarray's three types (Array=owned, ArrayView=borrowed, ArrayViewMut=mutable borrow) mirror Rust's borrow checker; understanding when views create new references vs shallow clones is essential for memory safety and performance
  • Zip/Azip (parallel array iteration) — zip! and par_azip! macros enable element-wise operations with automatic alignment checking and optional rayon parallelization; underpins ergonomic vectorized code without explicit loops
  • Memory layout (C-contiguous vs Fortran-contiguous) — Arrays can be stored in row-major (C) or column-major (Fortran) order; layout affects iteration performance and BLAS dispatch efficiency—critical for porting NumPy code with specific layout assumptions
  • ndarray-stats/ndarray-stats — Extends ndarray with statistical functions (mean, variance, quantiles per axis); primary companion crate for numerical analysis workloads
  • rust-ndarray/ndarray-linalg — Provides high-level linear algebra abstractions (SVD, QR, eigenvalue decomposition) on top of ndarray + BLAS
  • dimforge/nalgebra — Alternative Rust linear algebra library with fixed-size matrices; direct competitor for small-dimension workloads
  • PyO3/pyo3 — Enables ndarray interop with NumPy arrays via Python bindings; common integration pattern for hybrid Rust-Python projects
  • polars-rs/polars — DataFrames library built on Arrow; uses ndarray concepts for columnar operations in analytical workflows

🪄PR ideas

To work on one of these in Claude Code or Cursor, paste: Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.

Add comprehensive benchmarks for memory layout and view performance

The repo has benchmarks for operations (benches/iter.rs, benches/numeric.rs, etc.) but lacks dedicated benchmarks for view creation, slicing overhead, and memory layout transformations—core features advertised in the README. This would help catch performance regressions in ndarray's key differentiator (efficient array views and slicing) and provide guidance for users on view vs copy trade-offs.

  • [ ] Create benches/views_slicing.rs with benchmarks for: creating views, slicing operations, layout transformations (C vs Fortran order), and contiguous vs non-contiguous access patterns
  • [ ] Add benchmarks for chunking and splitting operations referenced in README but not in benches/chunks.rs
  • [ ] Run benchmarks against the latest release to establish baseline metrics
  • [ ] Document expected performance characteristics in a new section of README-quick-start.md

Implement comprehensive tests for BLAS feature interactions

The repo has blas-tests and blas-mock-tests crates (crates/blas-tests/, crates/blas-mock-tests/), but the test coverage appears minimal (only dyn.rs and oper.rs). Given BLAS is a prominent keyword and feature, there should be extensive tests verifying BLAS dispatch for gemv/gemm operations, mixed BLAS/non-BLAS code paths, and edge cases. This prevents silent fallback behavior and performance regressions.

  • [ ] Expand crates/blas-tests/tests/oper.rs to cover matrix multiplication variants (different dimensions, strides, dtypes)
  • [ ] Add tests in crates/blas-tests/tests/ for: BLAS fallback scenarios, mixed operation chains, and performance-critical operations documented in benches/gemv_gemm.rs
  • [ ] Add integration test verifying correct results when blas feature is enabled vs disabled in crates/blas-tests/tests/feature-gating.rs
  • [ ] Document BLAS dispatch rules in a new doc comment in src/linalg/ or equivalent module

Add targeted benchmarks and tests for rayon parallelization edge cases

The rayon feature is listed as optional and there's benches/par_rayon.rs, but CI config shows no explicit rayon-specific test or benchmark runs. Without dedicated coverage, parallel code paths (critical for N-dimensional operations) can have subtle bugs, data races, or suboptimal scheduling. New contributors can add focused tests for common parallel pitfalls.

  • [ ] Create crates/rayon-tests/ with tests for: par_map_inplace, par_iter edge cases (empty arrays, single-element), and thread-safety under high contention
  • [ ] Expand benches/par_rayon.rs to include scaling tests (1, 2, 4, 8 threads) and show where parallelization provides benefit vs overhead
  • [ ] Add a CI workflow step in .github/workflows/ci.yaml to explicitly run tests with and without rayon feature enabled
  • [ ] Document rayon performance guidance in README-quick-start.md (e.g., minimum array size before parallelization helps)

🌿Good first issues

  • Audit /src/slicing.rs for edge cases with negative indices + step size combinations and add comprehensive property-based tests using quickcheck in crates/numeric-tests/tests/ (currently limited coverage for step slicing).
  • Implement missing Axis::into_iter() convenience method returning a named iterator struct (similar to .iter() style) and add examples in /examples/ subdirectory (none currently exist in file list).
  • Expand benches/construct.rs to include benchmarks for .from_shape_fn() and .from_elem() with various element types (i32, f64, Complex<f64>) to identify construction bottlenecks pre-BLAS.

Top contributors

Click to expand

📝Recent commits

Click to expand
  • 27af864 — perf(iteration): use move instead of clone for iteration (#1586) (akern40)
  • fd67f70 — Change linspace to take a range argument. (#1580) (Kwonunn)
  • 1daa82f — docs/tests: fix rustdoc links and appease clippy strict lints (#1576) (RPG-Alex)
  • f6f06ce — fix(docs): readme: spelling mistake (#1579) (Jackneill)
  • 49cbd5d — Add phase angle calculation functions for complex arrays (#1543) (jmg049)
  • f6a3205 — Expand Zip to up to 9 producers (#1559) (felsenhower)
  • 2cf23d6 — chore: Release (akern40)
  • 1eb4559 — Remove most version specifiers in README (#1573) (akern40)
  • 59c1ce0 — Craft a release log for 0.17.2 (#1572) (akern40)
  • 6fd0a9d — Clean up clippy allows and unnecessary borrows (#1571) (RPG-Alex)

🔒Security observations

The ndarray crate demonstrates a solid security posture with no critical vulnerabilities identified. The codebase follows Rust's memory safety guarantees and uses well-maintained dependencies. Primary concerns are around optional external C integrations (BLAS), transitive dependency management, and platform-specific atomic operation fallbacks. The crate maintains dual licensing (MIT/Apache-2.0), has active CI/CD pipelines, and explicitly defines supported Rust versions (1.64+). Recommended improvements include stricter dependency pinning at the workspace level and comprehensive security auditing of optional feature dependencies.

  • Medium · Optional BLAS Feature with External C Dependencies — Cargo.toml, [dependencies] section, blas feature gate. The 'blas' feature enables optional integration with cblas-sys and libc. While these are legitimate dependencies for numerical computing, enabling BLAS without proper vetting of the underlying C library implementations could introduce memory safety risks if the external C libraries contain vulnerabilities. Fix: Maintain an inventory of BLAS library versions used in production. Regularly audit cblas-sys and libc for security updates. Consider requiring explicit feature activation rather than including BLAS support by default.
  • Low · Deprecated Atomic Operations Fallback — Cargo.toml, [target.'cfg(not(target_has_atomic = "ptr"))'.dependencies]. The crate uses 'portable-atomic' as a fallback for platforms without native atomic pointer support (cfg(not(target_has_atomic = "ptr"))). This introduces an additional dependency for non-standard platforms that may have different maintenance and security standards. Fix: Monitor portable-atomic for security updates. Document which platforms require this fallback and ensure they are tested in CI/CD pipelines.
  • Low · Transitive Dependency Risk - num-integer, num-traits, num-complex — Cargo.toml, [dependencies] section. The crate depends on workspace dependencies num-integer, num-traits, and num-complex which are not pinned to specific versions in the provided Cargo.toml snippet. Transitive dependency resolution could introduce unexpected breaking changes or security vulnerabilities. Fix: Use a workspace Cargo.toml or Cargo.lock to maintain tight control over dependency versions. Regularly audit transitive dependencies using 'cargo audit' and 'cargo-tree'.
  • Low · Optional Rayon Dependency for Parallel Processing — Cargo.toml, rayon dependency and rayon feature. The optional 'rayon' dependency enables multi-threaded operations. While Rayon is a well-maintained crate, users enabling parallel processing features should be aware of potential data race conditions if misused in their code. Fix: Document thread-safety guarantees for parallelized operations. Add warnings about data races in API documentation where rayon features are used.

LLM-derived; treat as a starting point, not a security audit.


Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.

Healthy signals · rust-ndarray/ndarray — RepoPilot