NumSharp.Build 0.70.0

dotnet add package NumSharp.Build --version 0.70.0
                    
NuGet\Install-Package NumSharp.Build -Version 0.70.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="NumSharp.Build" Version="0.70.0">
  <PrivateAssets>all</PrivateAssets>
  <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="NumSharp.Build" Version="0.70.0" />
                    
Directory.Packages.props
<PackageReference Include="NumSharp.Build">
  <PrivateAssets>all</PrivateAssets>
  <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets>
</PackageReference>
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add NumSharp.Build --version 0.70.0
                    
#r "nuget: NumSharp.Build, 0.70.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package NumSharp.Build@0.70.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=NumSharp.Build&version=0.70.0
                    
Install as a Cake Addin
#tool nuget:?package=NumSharp.Build&version=0.70.0
                    
Install as a Cake Tool

NumSharp.Build

Build-time IL weaver for NumSharp's [NDScoped] deterministic memory reclamation. Installing this package is the whole opt-in — it wires a post-compile step into your project's build, and it is not a dependency and not contagious: it weaves the project it is installed in and nothing downstream. It ships MSBuild targets + a tool only (no lib/, no dependency entries, build/ never buildTransitive/), so a project that merely references your woven library — by project or by package — is never woven and its own [NDScoped] stays inert. dotnet add package installs it with PrivateAssets="all", which keeps it out of your own package's dependency graph; if you write the reference by hand (or under Central Package Management), add PrivateAssets="all" yourself — dotnet pack refuses to ship NumSharp.Build as a dependency of your package otherwise (error NDW018, with the one-line fix; -p:NumSharpBuildAllowAsDependency=true overrides it on purpose).

What it does

A NumSharp composition method allocates a handful of intermediate NDArrays, keeps one as its result, and drops the rest. Dropped arrays normally wait on the finalizer to return their pooled buffers — in a tight loop that lag means cold allocations. Mark the method [NDScoped] and keep the body exactly as you wrote it:

using NumSharp;

[NDScoped]
public static NDArray Normalize(NDArray a)
{
    var mean = np.mean(a);           // transient
    var std  = np.std(a);            // transient
    var centered = a - mean;         // transient
    return centered / std;           // the one you keep
}

At build time the method is rewritten to open an NDScope — the transients are reclaimed the moment the method exits (exception paths included) while the result survives. Your source keeps its 100 % original body; the scope exists only in the compiled IL.

Synchronous iterators work too, under [NDScoped]. An IEnumerable<NDArray> / IEnumerator<NDArray> (yield return) method is woven through its compiler state machine: one scope spans the whole enumeration, yield returned elements survive (the consumer owns them), and hoisted state is reclaimed at the end of iteration or the enumerator's Dispose() (a foreach break included).

Async methods, async iterators and Task/ValueTask returns use [NDScopedAsync]. An async Task<NDArray> / async ValueTask<NDArray> method, an IAsyncEnumerable<NDArray> async iterator, or a non-async method returning Task/ValueTask is marked [NDScopedAsync] (the companion attribute for shapes that suspend across await). The async ones weave through the state machine — one scope spans the logical invocation, suspended across awaits and resumed on whatever thread continues, so temps handed to an in-flight awaited callee stay alive and everything is reclaimed when the invocation completes; a non-async Task/ValueTask return yields a completed task's result immediately and defers reclamation to an incomplete task's completion. Marking a method with the wrong attribute is a build error (NDW009/NDW010), never a silent unwoven ship.

A retained argument is protected with [NDScopedExit]. A scope reclaims every array it tracked except the return value and out params — so an array handed to something that keeps it (a field store, a long-lived collection, a captured closure) would be disposed under the retainer. Mark the retaining parameter and the weaver detaches the argument from the caller's scope at the callee's entry:

public NDArray Weights { get; private set; }
public void Adopt([NDScopedExit] NDArray w) => Weights = w;   // w survives the caller's scope

It works with or without a method-level scope attribute, covers NDArray / NDArray[] / tuples of NDArrays — nested tuples and NDArray[] components detach recursively — (a property setter's value counts), and is a no-op when there is no ambient scope. An unsupported parameter type is a build error (NDW014). A raw public-field store has no parameter to annotate — route it through a setter or call NDScope.Detach by hand.

On a virtual, abstract or interface member the attributes are a contract the inheritors inherit. Every override and implementation — class overrides through any number of levels, implicit and explicit interface implementations, generic instantiations, and overrides in another assembly of a NumSharp member or of a library that used this weaver — is woven exactly as if it carried the attribute itself, so the scoping is stated once, where the API is declared:

public abstract class Layer
{
    [NDScoped] public abstract NDArray Forward(NDArray x);        // the contract — never woven, never an error
    public abstract void Adopt([NDScopedExit] NDArray weights);   // inherited by position
}

public class Dense : Layer
{
    public override NDArray Forward(NDArray x) { var h = x + 1.0; return h.copy(); } // woven
    public override void Adopt(NDArray w) => _w = w;                                  // w is detached
    private NDArray _w;
}

The nearest declaration up the chain wins, and an override's own attribute wins over it — [NDScopedCovered] on an override opts out of the inherited weave. The analyzer resolves the same graph (no NDW012 on an inheriting override; the target gate reads the declaration's attribute), and while this package is absent it reports NDW013 at every member that would have been woven — an own [NDScoped]/[NDScopedAsync]/[NDScopedExit] and an inherited one alike, the latter a shape no metadata text scan can see because the override never spells the attribute.

A companion Roslyn analyzer catches mistakes at compile time — and it ships with NumSharp itself, not with this package. The NumSharp package carries the analyzer (under its analyzers/dotnet/cs/, applied automatically to any PackageReference compile), so it is already active in every project that can use the attributes — before this weaver is ever installed. It reports a wrong or unsupported target as a build ERROR — in the editor, before the weave runs: the wrong attribute (NDW009 = an async/Task method under [NDScoped], NDW010 = a plain sync method or synchronous iterator under [NDScopedAsync], NDW011 = both attributes), a hidden ref/in egress over any NDArray-carrying shape (NDW002), an unsupported carrier return (NDW003), a body-less method (NDW005), a setter-only property (NDW006), or an out parameter whose NDArray-carrying shape the out-escape cannot yield (NDW015). The IL-only checks (an unrecognized state machine, a tail-call, an out-of-date NumSharp, a bad [NDScopedExit] parameter) stay with the weaver post-compile. A SOURCE-mode consumer (ProjectReference to NumSharp.Core + imported targets — no package, so no auto-apply) opts the analyzer in by referencing the analyzer project with OutputItemType="Analyzer", or by setting $(NumSharpBuildAnalyzerDll) at the built analyzer DLL — the parallel to $(NumSharpBuildToolDll).

With the package absent, [NDScoped] (which ships in NumSharp itself) is inert metadata: the method runs unscoped and transients fall back to the finalizer. NumSharp does not depend on or bundle this package — weaving is an explicit opt-in — so NumSharp's own analyzer (and, where no analyzer runs, an MSBuild scan in its targets) reports NDW013 at every attributed member in that state, naming this package as the fix. Adding or removing the package never changes results — only when buffers are reclaimed.

Install

dotnet add package NumSharp.Build

Requires a project that references NumSharp (that is where NDScope and the attribute live) and a .NET 8+ host runtime for the build tool (it rolls forward to any newer major).

Escape hatches

flag effect
-p:SkipNDScopeWeave=true build without weaving (the attribute is inert)
-p:NDScopeWeaveILVerify=true additionally run dotnet-ilverify on the woven output

Documentation

Full reference — which return shapes are woven (tuples, NDArray[], result-struct carriers via INDArrayCarrier, out params), the NDScope API, hand-scoping, and the NDW00x build errors: https://scisharp.github.io/NumSharp/docs/numsharp-build-compiler.html

Part of the SciSharp STACK.

There are no supported framework assets in this package.

Learn more about Target Frameworks and .NET Standard.

This package has no dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.70.0 42 9/6/2026