NumSharp: A NumPy-Shaped Array Library for .NET Without CPython
High Performance Computation for N-D Tensors in .NET, similar API to NumPy.
At a glance
- What is it?
- NumSharp brings NDArray, broadcasting, dtype promotion and a broad np.* surface to C# and F#. It targets NumPy 2.x compatibility and generates kernels at runtime, but the compatibility surface is still a work in progress.
- Who is it for?
- NumSharp fits .NET teams that want NumPy-shaped array code inside a normal C# or F# process, without hosting CPython. It is the wrong pick if your code depends on NumPy functions outside the published coverage map, or if you need a frozen compatibility guarantee before you ship.
- 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 5 days ago.
- What is it written in?
- Mainly C#, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
The gap NumSharp fills between C# numerics and NumPy idioms
C# has arrays and spans, but it does not have a standard N-dimensional array type with shape, strides, offsets and view semantics. Teams that want that model either embed CPython through Python.NET and pay the interop cost, or hand-roll indexing and broadcasting logic that drifts from what their Python colleagues expect. NumSharp exists to close that gap. The README describes it as "a native .NET array library with a NumPy-shaped API" and states the compatibility target is NumPy 2.x, with NumPy treated as the source of truth when the two disagree. The intended audience is named directly: scientific computing, numerical utilities, machine learning infrastructure, and projects that want NumPy-style array operations in ordinary .NET code. The library is Apache-2.0 licensed, written in C#, and published on NuGet as NumSharp.
How NDArray, broadcasting and runtime-generated kernels fit together
The core type is NDArray, which carries shape, stride, offset and view metadata. Slicing produces views rather than copies, which is why the README example can take a strided window out of a reshaped range and pass it to a reduction without an intermediate allocation. Broadcasting follows the NumPy rule of expanding shapes without materializing repeated values, so an operation between arrays of different rank does not build a full-sized copy of the smaller operand first. On top of that sits an NDIter-style execution layer. The README points to a fused np.evaluate expression path whose stated purpose is reducing intermediate allocations, which matters when a chain of elementwise operations would otherwise create a temporary per step. The performance story is runtime code generation: the project uses C# dynamic IL generation to emit kernels specialized to the dtype and memory layout actually in play, then relies on JIT compilation and SIMD CPU acceleration for the inner loop. The README claims this approach produces higher performance marks than NumPy on many functions, and points to a benchmark dashboard rather than quoting numbers inline. That claim is the project's own, published as tracked release snapshots; I have not run those benchmarks, so treat the dashboard as the primary source and read the methodology before repeating the comparison. The dtype layer covers 15 core dtypes with NumPy-oriented promotion and conversion behavior, and there is a separate compliance document describing where NumSharp matches NumPy and where it does not.
Getting a first array running from NuGet
Installation is a single package reference. The README gives:
dotnet add package NumSharp
The usage example is deliberately close to NumPy. In C#:
using NumSharp;
var a = np.arange(12).reshape(3, 4); var window = a[":, 1::2"];
Console.WriteLine(window); Console.WriteLine(np.sum(window, axis: 0));
The equivalent Python is shown side by side, with the slice written as a[:, 1::2] and the reduction as window.sum(axis=0). Note the C# slice syntax: the colon and double-colon step are passed as a string, not as a language-level range operator. That is a design choice worth knowing before you port code, because slicing errors surface at parse time rather than compile time. For building from source, the README gives:
dotnet build test/NumSharp.Tests/NumSharp.Tests.csproj --configuration Release
and a CI-style test invocation using dotnet test against the same project with --configuration Release, --no-build and a --framework argument. The README text for that last flag is truncated in the supplied material, so check the repository's workflow file for the exact target framework moniker rather than copying a partial command.
Where the NumPy compatibility promise breaks down
The honest framing is in the project's own documentation set: there is a coverage and support dashboard described as "the full implementation roadmap to complete 100% NumPy porting", with an explorer for checking individual functions. A roadmap to full porting is an admission that full porting has not happened. So the practical limitation is coverage, not correctness of what exists. If your code path calls a NumPy function that has not been implemented or is only partially implemented, you find out at runtime, and the failure may be a missing method rather than a subtly different result. The second limitation is the performance claim itself. Runtime IL generation means the first call into a given dtype and layout combination pays a generation cost before the specialized kernel is available; the README does not describe a warmup or ahead-of-time path, so latency-sensitive first calls deserve measurement in your own workload. Third, the API shape is close to NumPy but is not NumPy. Slice strings, the np.* naming convention and C# type inference all mean that a mechanical translation of a Python file will need editing. If your team's actual requirement is running existing Python numerical code unchanged, NumSharp is the wrong tool and an interop layer is the better fit.
NumSharp against MathNet.Numerics: different problems, different shapes
The obvious .NET alternative for numerical work is MathNet.Numerics. The difference in approach is structural rather than a matter of speed. MathNet centers on matrices and vectors with a linear algebra focus: dense and sparse matrix types, decompositions, solvers, statistics distributions. Its mental model is the matrix. NumSharp's mental model is the N-dimensional array with arbitrary rank, stride and view metadata, plus NumPy's broadcasting and dtype promotion rules. Those two models overlap on two-dimensional work and diverge everywhere else. If you are doing linear algebra on matrices, MathNet's API is built for exactly that and its decomposition coverage is the point of the library. If you are doing elementwise work on tensors of rank three or four, slicing views, or translating Python analysis code that leans on broadcasting, MathNet's model makes you reshape everything into matrices and back. NumSharp also differs by generating specialized kernels at runtime, whereas MathNet is conventional compiled C#. That is the trade: NumSharp can specialize to a dtype and layout combination it discovers at execution time, and it pays for that with code generation and a compatibility surface that is still being filled in.
Release cadence, licence and what an upgrade actually costs you
The release history supplied shows v0.50.0-prerelease, then v0.60.0 and v0.70.0 as stable releases, roughly two months apart, with the latest push to master shortly after v0.70.0. Pre-1.0 version numbers matter here. Every minor bump is a potential breaking change by convention, and the v0.50.0 release was labelled the long indexing release, which tells you indexing semantics were still being extended at that point. Budget for reading release notes before each upgrade rather than floating the package version. The licence is Apache-2.0, which permits commercial and closed-source use and includes an explicit patent grant. That is a permissive arrangement, but it is not legal advice: if you redistribute NumSharp inside a product, read the LICENSE file and your own obligations around attribution and any NOTICE file in the repository. There is no separate commercial support tier described in the supplied material, so maintenance cost is essentially the cost of tracking a pre-1.0 library's API churn yourself. The project does publish tracked benchmark snapshots per release, which gives you a way to compare a version you are on against a version you are considering without running the suite yourself.
Who should adopt NumSharp, and what to check before committing
Adopt it if you are writing C# or F# numerical code that genuinely wants NumPy's programming model: rank-N arrays, broadcasting, dtype-aware math, and a familiar np.* vocabulary, all inside a normal .NET process with no CPython hosting. The build, test and package story is standard dotnet tooling, and the Apache-2.0 licence is permissive. Do not adopt it if your requirement is executing existing Python numerical code as-is, or if you need a stable 1.0 compatibility guarantee today, or if your workload is fundamentally matrix linear algebra where MathNet.Numerics already fits the shape of the problem. The one thing to verify before you commit is coverage against your own call list. Open the coverage and support dashboard, walk every np.* function your code will call, and confirm each one is implemented rather than on the roadmap. Do that check against a pinned version, because the dashboard reflects the current state of a library whose stated goal is still 100% NumPy porting.
Editorial conclusion
NumSharp fits .NET teams that want NumPy-shaped array code inside a normal C# or F# process, without hosting CPython. It is the wrong pick if your code depends on NumPy functions outside the published coverage map, or if you need a frozen compatibility guarantee before you ship. Before adopting, open the coverage and support dashboard and confirm every function you call is listed, then pin the exact NumSharp version in your csproj rather than floating it.
Community notes