Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
c4b75de
chore: remove Deepak Kumar Battini from package authors
Nucs Jun 28, 2026
80fcbf9
fix(casting): ToByteArray() returns logical C-order bytes (NumPy toby…
Nucs Jun 29, 2026
ec0bb40
bench(history): publish 2026-06-29 snapshot (new latest) + recover bi…
Nucs Jun 29, 2026
68fec24
fix(reductions,casts): normalize non-0/1 bool bytes everywhere bool i…
Nucs Jun 30, 2026
22589ad
fix(dtype): make Char promote/compute as the uint16 masquerade (6 Cha…
Nucs Jun 30, 2026
9c8873f
test(openbugs): reproduce NEP50 out-of-range python-scalar gap (colle…
Nucs Jun 30, 2026
7a975d3
test(fuzz): expand differential-fuzz grids to all 15 dtypes & all ops…
Nucs Jun 30, 2026
9b05fe6
test(fuzz): extend Decimal oracle to power/var/std/matmul/astype (all…
Nucs Jun 30, 2026
e8ed49d
feat(casting): tobytes(order) — full NumPy ndarray.tobytes C/F/A/K pa…
Nucs Jun 30, 2026
420242f
test(fuzz): Group A coverage — wire 18 array→array np.* ops into the …
Nucs Jun 30, 2026
6421caa
test(fuzz): Group A Batches 4-6 — 15 more np.* ops (shape/selection/s…
Nucs Jul 1, 2026
cb31c47
fix(dtype): np.min_scalar_type — stop avoiding int8/float16 (NumPy pa…
Nucs Jul 1, 2026
fdd1624
feat(io): np.tofile(sep, format) — full NumPy ndarray.tofile parity +…
Nucs Jul 1, 2026
2eb6591
fix(printing): tofile/scalar-str parity — '#' flag decimal point + fl…
Nucs Jul 1, 2026
7b79744
fix(dtype): int8/float16 avoidance across the type-resolution surface…
Nucs Jul 1, 2026
22aac57
test(fuzz): decimal oracle — floor/ceil/trunc/diff/clip/stat/where/so…
Nucs Jul 1, 2026
b77d437
feat(casting): ndarray.astype(casting=) gate — close the last type-co…
Nucs Jul 1, 2026
8f07f17
feat(math): np.rint — round-half-to-even ufunc (NumPy parity), reusin…
Nucs Jul 1, 2026
0282d50
test(rint): enforce NumPy parity — signed zero, Half/Char, out=/where…
Nucs Jul 1, 2026
f6a59f3
feat(io): full np.fromfile parity — count/offset/sep(text)/default-dt…
Nucs Jul 1, 2026
5d38769
refactor(casting)!: dissolve legacy NDArray.ToByteArray — tobytes is …
Nucs Jul 1, 2026
a656949
docs(memory): correct UnmanagedMemoryBlock(T*, long) ownership remark
Nucs Jul 1, 2026
64c912e
test(casting): pin GetData<T>/ToArray<T> dtype-mismatch semantics
Nucs Jul 1, 2026
8d5631e
docs(website): 15-dtype table, namespace overwrite, TOC links, benchm…
Nucs Jul 1, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 13 additions & 7 deletions .claude/CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -247,9 +247,9 @@ Tested against NumPy 2.x.
`are_broadcastable`, `broadcast`, `broadcast_arrays`, `broadcast_to`

### Math — Arithmetic
`abs`, `absolute`, `add`, `arccos`, `arcsin`, `arctan`, `arctan2`, `cbrt`, `ceil`, `clip`, `convolve`, `cos`, `cosh`, `deg2rad`, `degrees`, `divide`, `exp`, `exp2`, `expm1`, `floor`, `floor_divide`, `log`, `log10`, `log1p`, `log2`, `mod`, `modf`, `multiply`, `negative`, `positive`, `power`, `rad2deg`, `radians`, `reciprocal`, `sign`, `sin`, `sinh`, `sqrt`, `square`, `subtract`, `tan`, `tanh`, `true_divide`, `trunc`
`abs`, `absolute`, `add`, `arccos`, `arcsin`, `arctan`, `arctan2`, `cbrt`, `ceil`, `clip`, `convolve`, `cos`, `cosh`, `deg2rad`, `degrees`, `divide`, `exp`, `exp2`, `expm1`, `floor`, `floor_divide`, `log`, `log10`, `log1p`, `log2`, `mod`, `modf`, `multiply`, `negative`, `positive`, `power`, `rad2deg`, `radians`, `reciprocal`, `rint`, `sign`, `sin`, `sinh`, `sqrt`, `square`, `subtract`, `tan`, `tanh`, `true_divide`, `trunc`

**ufunc `out=` / `where=` parameters** are supported on the elementwise core (NumPy semantics, probed against 2.4.2): binary `add`/`subtract`/`multiply`/`divide`/`true_divide`/`mod`/`power`/`floor_divide`/`arctan2`/`bitwise_and`/`bitwise_or`/`bitwise_xor`, unary `sqrt`/`exp`/`log`/`sin`/`cos`/`tan`/`abs`/`absolute`/`negative`/`square`/`log2`/`log10`/`log1p`/`exp2`/`expm1`/`cbrt`/`sign`/`floor`/`ceil`/`trunc`/`reciprocal`/`sinh`/`cosh`/`tanh`/`arcsin`/`arccos`/`arctan`/`deg2rad`(`radians`)/`rad2deg`(`degrees`)/`invert`(`bitwise_not`). `round_`/`around` take `out=` ONLY (np.round is a function, not a ufunc — no where/dtype; decimals≠0 cast errors name ufunc 'multiply' per NumPy's composition). floor/ceil/trunc have IDENTITY loops on every bool/int dtype (dtype preserved; np.round's int path is an identity copy); the loop dtype comes from the input tier (`sinh(i1, out=f8)` stores float16-precision values); reciprocal int 1/0 → signed MinValue (NumPy 2.4.2); sign/positive reject bool with the verbatim no-loop UFuncTypeError; bitwise/invert raise the no-loop TypeError for float inputs (probed order: bad where → no-loop → out-cast → shape). `out` joins the broadcast but is never stretched, requires a same_kind cast from the loop dtype (resolved from inputs), returns the same instance, and may alias an input (overlap-safe via COPY_IF_OVERLAP). `where` must be bool, broadcasts and joins the output shape; masked-off `out` slots keep prior contents. Engine plumbing: `Backends/Default/Math/DefaultEngine.UfuncOut.cs`.
**ufunc `out=` / `where=` parameters** are supported on the elementwise core (NumPy semantics, probed against 2.4.2): binary `add`/`subtract`/`multiply`/`divide`/`true_divide`/`mod`/`power`/`floor_divide`/`arctan2`/`bitwise_and`/`bitwise_or`/`bitwise_xor`, unary `sqrt`/`exp`/`log`/`sin`/`cos`/`tan`/`abs`/`absolute`/`negative`/`square`/`log2`/`log10`/`log1p`/`exp2`/`expm1`/`cbrt`/`sign`/`floor`/`ceil`/`trunc`/`reciprocal`/`sinh`/`cosh`/`tanh`/`arcsin`/`arccos`/`arctan`/`deg2rad`(`radians`)/`rad2deg`(`degrees`)/`invert`(`bitwise_not`)/`rint`. `round_`/`around` take `out=` ONLY (np.round is a function, not a ufunc — no where/dtype; decimals≠0 cast errors name ufunc 'multiply' per NumPy's composition). `rint` is the TRUE ufunc form of round-half-to-even: unlike `round_`/`around` (which preserve integer dtype) it is float-tier (bool/i8/u8→f16, i16/u16→f32, i32+→f64, floats/complex preserved) and reuses `UnaryOp.Round`'s kernel (complex rounds real+imag; `dtype=<int>`→no-loop). floor/ceil/trunc have IDENTITY loops on every bool/int dtype (dtype preserved; np.round's int path is an identity copy); the loop dtype comes from the input tier (`sinh(i1, out=f8)` stores float16-precision values); reciprocal int 1/0 → signed MinValue (NumPy 2.4.2); sign/positive reject bool with the verbatim no-loop UFuncTypeError; bitwise/invert raise the no-loop TypeError for float inputs (probed order: bad where → no-loop → out-cast → shape). `out` joins the broadcast but is never stretched, requires a same_kind cast from the loop dtype (resolved from inputs), returns the same instance, and may alias an input (overlap-safe via COPY_IF_OVERLAP). `where` must be bool, broadcasts and joins the output shape; masked-off `out` slots keep prior contents. Engine plumbing: `Backends/Default/Math/DefaultEngine.UfuncOut.cs`.

**Each of those ufuncs exposes ONE NumPy-shaped overload** — `f(x[, x2], NDArray out = null, NDArray where = null, NPTypeCode? dtype = null)` mirroring NumPy's `f(x1[, x2], /, out=None, *, where=True, dtype=None)`: `out` is the second/third positional slot exactly like NumPy, `where`/`dtype` are reachable by name without `out`. `dtype=` selects the LOOP (NumPy loop-signature semantics, probed): computation runs at that precision even with `out=` (`sqrt([2.], out=f64, dtype=f32)` stores the f32-rounded value; `add(0.1, 0.2, out=f64, dtype=f32)` stores `0.30000001…`), `power(2, -1, dtype: f64) = 0.5` (the negative-int-exponent ValueError applies only to integer loops), `power(10, 11, dtype: f64) = 1e11` exactly (no compute-then-cast), `add(True, True, dtype: i32) = 2` (the bool→logical-OR remap keys off the FINAL loop dtype), `negative(bool, dtype: f64)` is legal, and inputs must reach the loop via same_kind casts (verbatim `Cannot cast ufunc '<name>' input [N] from ...` errors; binary errors are indexed, unary are not). Loop-existence gates raise `No loop matching ... ufunc <name>`: float-only ufuncs (sqrt/exp/log/trig + `divide`/`true_divide`) reject int/bool dtype; bitwise rejects float/complex/decimal dtype. `positive` is a full ufunc (identity loops at every dtype EXCEPT bool: plain `positive(bool)` and `dtype: bool` raise the verbatim `did not contain a loop with signature matching types <class 'numpy.dtypes.XDType'> -> ...` texts; `positive(bool, dtype: f64)` works). `round_`/`around` follow NumPy's non-ufunc shape `round(a, int decimals = 0, NDArray out = null)` (2nd positional is decimals, NOT out). Positional-dtype overloads (`np.sqrt(x, NPTypeCode.Single)`, `(x, Type)`) also exist for source compat as non-NumPy call forms (NumPy's 2nd positional is `out`). Tests: `Math/UfuncDtypeOverloadTests.cs`.

Expand Down Expand Up @@ -553,24 +553,30 @@ Proves every NDIter-backed op is **bit-identical** to NumPy 2.4.2 across the inp
```
test/oracle/ corpus generators (NumPy 2.4.2 — run by hand / nightly soak)
layout_catalog.py memory-layout builders (the "44 variations": 26 single + 9 pair + 5 where)
gen_oracle.py deterministic op matrices (astype/binary/unary/reduce/where/… — ~90 ops)
gen_oracle.py deterministic op matrices (astype/binary/unary/reduce/where/… — ~90 ops);
per-mode dtype axes widened to ALL_DTYPES; Char woven into every tier
via the uint16 proxy (char_tier, relabelled uint16->char)
gen_decimal_oracle.cs INDEPENDENT C# oracle for Decimal (no NumPy analog): naive scalar
System.Decimal math -> decimal_{unary,binary,reduce,scan,power,
varstd,matmul,astype,stat,where,sort,manip}.jsonl
gen_index_oracle.py getter/setter index oracle (token index over 15 base recipes)
fuzz_random.py seeded random fuzzer (imports the other two)
test/NumSharp.UnitTest/Fuzz/ C# replay harness (no Python)
FuzzCorpus.cs rebuilds EXACT NDArray views from (dtype,shape,strides,offset,bytes)
OpRegistry.cs op-name → NumSharp call (pairs 1:1 with gen_oracle.py)
BitDiff.cs / Shrinker.cs bit-exact compare (NaN tokenized) / shrink a failure to 1 element
BitDiff.cs / Shrinker.cs bit-exact compare (NaN tokenized; Decimal by canonical VALUE so 1.0m≡1.00m) / shrink a failure to 1 element
MisalignedRegistry.cs the documented, excused divergences (intended differences and excused cases)
FuzzCorpusTests.cs one [FuzzMatrix] test per op-corpus file (checks dtype + shape + bytes + error parity)
IndexOracleTests.cs index get/set differential gate (curated + dtype + seeded-random tiers)
MetamorphicTests.cs oracle-free invariants (round-trips / involutions / identities — no NumPy)
HarnessSelfTests.cs proves the harness has teeth (BitDiff detects value/NaN/-0 diffs; non-vacuous)
corpus/*.jsonl committed corpus (~51K cases / 28 tiers), copied to test output via the csproj glob
corpus/*.jsonl committed corpus (~68K cases / 40 tiers; op corpus ~53K incl. 3.7K Char woven + 579 Decimal), copied to test output via the csproj glob
```

- **Generators live in `test/oracle/`** and write the corpus into `test/NumSharp.UnitTest/Fuzz/corpus/` (path resolved relative to `test/oracle/`). CI replays the committed corpus, never the generators.
- **Three `FuzzMatrix` gates**: `FuzzCorpusTests` (the op corpus — ~40K cases / 25 tiers, checking dtype + shape + bytes + error parity), `IndexOracleTests` (the index oracle — `index_curated` 2,265 + `index_dtype` 104 + `index_random` 10,000; the advanced-indexing parity gate), and `MetamorphicTests` (12 NumPy-free invariants). A failing op case auto-shrinks to a 1-element repro.
- **Regenerate** (deterministic; needs `numpy==2.4.2`): `python test/oracle/gen_oracle.py <mode>` (modes: `smoke astype_full binary divmod_power comparison unary reduce where place matmul bitwise unary_extra nanreduce scan stat logic modf manip sort tail params aliasing copyto errors`) + `python test/oracle/gen_index_oracle.py` (the `index_*` tiers) + `python test/oracle/fuzz_random.py 1234 2000 random_smoke.jsonl`, then `dotnet build` (copies the corpus to test output).
- **Three `FuzzMatrix` gates**: `FuzzCorpusTests` (the op corpus — ~53K cases across the tiers, checking dtype + shape + bytes + error parity; Char woven into every tier, 12 `Decimal*` tiers: unary/binary/reduce/scan/power/varstd/matmul/astype/stat/where/sort/manip), `IndexOracleTests` (the index oracle — `index_curated` 2,265 + `index_dtype` 104 + `index_random` 10,000; the advanced-indexing parity gate), and `MetamorphicTests` (12 NumPy-free invariants). A failing op case auto-shrinks to a 1-element repro.
- **Dtype coverage**: per-mode dtype axes widened toward `ALL_DTYPES`. **Char** (no NumPy dtype) is woven into every tier via the uint16 proxy (`gen_oracle.char_tier`, relabelled uint16→char). **Decimal** (no NumPy analog) rides an independent C# oracle (`gen_decimal_oracle.cs`, naive scalar `System.Decimal`). Verified Char/clip-bool bugs are carved from the green corpus and reproduced under `[OpenBugs]` (`OpenBugs.Char.cs`, `OpenBugs.DtypeCoverage.cs`) — NOT excused in `MisalignedRegistry`.
- **Regenerate** (deterministic; needs `numpy==2.4.2`): `python test/oracle/gen_oracle.py <mode>` (modes: `smoke astype_full binary divmod_power comparison unary reduce where place matmul bitwise unary_extra nanreduce scan stat logic modf manip sort tail params aliasing copyto errors`) + `python test/oracle/gen_index_oracle.py` (the `index_*` tiers) + `python test/oracle/fuzz_random.py 1234 2000 random_smoke.jsonl` + `dotnet run test/oracle/gen_decimal_oracle.cs` (the `decimal_*` tiers), then `dotnet build` (copies the corpus to test output).
- **Run the gate**: `dotnet test --filter "TestCategory=FuzzMatrix"`. Each case is bit-exact (pass), a documented difference in `MisalignedRegistry` (excused, never silent), or a failure (red). Full divergence ledger: `test/NumSharp.UnitTest/Fuzz/README.md`.

## CI Pipeline
Expand Down
Loading
Loading