Skip to content

Indexing routines: implement the 25 missing np.* indexing functions (diag, nditer, r_/c_, take_along_axis, ...) #624

Description

@Nucs

Overview

Indexing routines is NumSharp's largest partial gap: 10 of 35 implemented. This tracks the 25 missing functions, grouped into four work clusters. It is dominated by np.diag -- ~115K GitHub hits, one of the most-used NumPy functions overall and absent today (NumSharp has diagonal for extraction but not the diag constructor/dual).

Problem

The gap spans four very different kinds of work -- pure index arithmetic (diagonals/triangles), a slice-expression DSL (r_/c_/s_/ix_/ogrid), iterator objects, and along-axis selection. Splitting by cluster lets the cheap, high-value pieces (esp. diag) ship first.

Verified codebase state

  • Implemented (np.*): take, put, compress, place, where, nonzero, diagonal, indices, ravel_multi_index, unravel_index (+ mgrid exists).
  • Missing (25 below): verified absent from np.* (including static properties, so c_/r_/s_/ogrid are confirmed missing) and as NDArray methods (reflection + source grep).
  • Nuance: the internal multi-operand iterator (public static class NDIter, Backends/Iterators/NDIter.cs) already exists -- so the nditer/ndindex/ndenumerate cluster is mostly a public wrapper, not new machinery.

Proposal

Add under np.*, cluster by cluster. Recommended order: A -> (D, C) -> B, leading with diag.

A. Diagonal & triangle index-math -- pure index arithmetic, no new kernels (do first)

  • diag (114,816) -- extract a diagonal or construct a diagonal matrix (the dual of diagonal)
  • fill_diagonal (26,032) -- write the main diagonal of an array in place
  • triu_indices (8,944) -- upper-triangle indices of an (n,m) array
  • triu_indices_from (4,600) -- upper-triangle indices for a given array
  • diag_indices (4,340) -- indices to access the main diagonal
  • tril_indices (3,800) -- lower-triangle indices of an (n,m) array
  • diag_indices_from (3,488) -- main-diagonal indices for a given array
  • tril_indices_from (3,140) -- lower-triangle indices for a given array
  • mask_indices (2,156) -- indices from a generic triangle-mask function

D. Along-axis selection -- selection kernels (build on take/put/place)

  • select (23,040) -- piecewise pick from choice arrays by a condition list
  • take_along_axis (10,584) -- gather by matching 1-D index and data slices
  • choose (9,416) -- build an array from an index array + a list of choice arrays
  • putmask (3,512) -- masked in-place write (broadcasting values)
  • put_along_axis (3,088) -- scatter by matching 1-D index and data slices

C. Iterator objects -- mostly surfacing the existing NDIter engine

  • nditer (42,416) -- multi-operand iterator object -- internal NDIter engine already exists (Backends/Iterators/NDIter.cs)
  • ndindex (20,160) -- N-dimensional index iterator
  • ndenumerate (8,288) -- N-dimensional (index, value) iterator
  • iterable (5,488) -- predicate: is the object iterable (trivial)
  • nested_iters (1,664) -- nested multi-operand iterators
  • flatiter (4,800) -- flat-iterator type behind .flat

B. Grid / slice-expression DSL -- needs C# indexer sugar

  • r_ (44,016) -- row-wise concatenation / build from slice objects
  • c_ (35,600) -- column-wise concatenation / build from slice objects
  • ix_ (32,544) -- open-mesh index from multiple sequences
  • s_ (19,104) -- slice-literal builder for index tuples
  • ogrid (6,888) -- open (non-fleshed) meshgrid (mgrid already exists in NumSharp)

Evidence -- GitHub usage ranking

# Function GitHub hits Cluster What it does
1 np.diag 114,816 A extract a diagonal or construct a diagonal matrix (the dual of diagonal)
2 np.r_[] 44,016 B row-wise concatenation / build from slice objects
3 np.nditer 42,416 C multi-operand iterator object -- internal NDIter engine already exists (Backends/Iterators/NDIter.cs)
4 np.c_[] 35,600 B column-wise concatenation / build from slice objects
5 np.ix_ 32,544 B open-mesh index from multiple sequences
6 np.fill_diagonal 26,032 A write the main diagonal of an array in place
7 np.select 23,040 D piecewise pick from choice arrays by a condition list
8 np.ndindex 20,160 C N-dimensional index iterator
9 np.s_[] 19,104 B slice-literal builder for index tuples
10 np.take_along_axis 10,584 D gather by matching 1-D index and data slices
11 np.choose 9,416 D build an array from an index array + a list of choice arrays
12 np.triu_indices 8,944 A upper-triangle indices of an (n,m) array
13 np.ndenumerate 8,288 C N-dimensional (index, value) iterator
14 np.ogrid[] 6,888 B open (non-fleshed) meshgrid (mgrid already exists in NumSharp)
15 np.iterable 5,488 C predicate: is the object iterable (trivial)
16 np.flatiter 4,800 C flat-iterator type behind .flat
17 np.triu_indices_from 4,600 A upper-triangle indices for a given array
18 np.diag_indices 4,340 A indices to access the main diagonal
19 np.tril_indices 3,800 A lower-triangle indices of an (n,m) array
20 np.putmask 3,512 D masked in-place write (broadcasting values)
21 np.diag_indices_from 3,488 A main-diagonal indices for a given array
22 np.tril_indices_from 3,140 A lower-triangle indices for a given array
23 np.put_along_axis 3,088 D scatter by matching 1-D index and data slices
24 np.mask_indices 2,156 A indices from a generic triangle-mask function
25 np.nested_iters 1,664 C nested multi-operand iterators

Combined usage ~ 441,924 hits -- the largest of the three sweep issues, and diag (~114,816) is the single most-used missing function in the entire sweep.

Usage = GitHub REST code-search total_count in each function's canonical call form (np.<fn>(, or np.<fn>[ for the index-expression objects). It is an approximate estimate (noisy plus/minus ~10% on large sets) and counts only the dominant np. alias. Measured 2026-07-19; treat as relative demand, not exact.

Scope / Non-goals

  • np.matrix-returning behavior is out of scope (NumSharp has no matrix subclass; np.matlib is deprecated).
  • nditer should expose the existing NDIter engine, not a re-implementation; full NumPy op_flags/buffering parity can be staged.
  • The DSL objects (r_/c_/s_) require C# indexer ergonomics -- acceptable to expose a close-but-not-identical surface where C# syntax forces it (document divergences).

Related issues

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    NumPy 2.x ComplianceAligns behavior with NumPy 2.x (NEPs, breaking changes)apiPublic API surface (np.*, NDArray methods, operators)coreInternal engine: Shape, Storage, TensorEngine, iteratorsenhancementNew feature or requestmissing feature/sNumPy function not yet implemented in NumSharp

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions