Repository navigation
feat: thirteen dtypes with NumPy 2.x promotion - #42
Merged
Merged
Conversation
…mpy promotion fixture The design for Phase 2: why the dtype is a runtime property of the one Array type rather than a generic Dense[T] (promotion picks the result type from both operands, which a generic method cannot express; the consumers are dynamic; nothing existing breaks), the storage layout that leaves the float64 hot path untouched, the NumPy semantics and the deliberate differences, the two breaking changes, and the delivery order. testdata/promotion.json is generated from NumPy 2.5.3 by testdata/promotion.py: the 13x13 result_type table, weak-scalar results, unary ufunc and reduction dtypes. The implementation will be tested against every cell. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Array now holds bool, the eight integer types, float32/64 and complex64/128, chosen at run time as in NumPy. Float64 storage and every float64 kernel are untouched; the other dtypes live in a typed slice and run generic loops, one per element type, picked by type switches that gen_dtypes.go generates. Promotion is numpy.result_type; Go scalars are weak as Python scalars are under NEP 50 (Scalar, and the *Scalar methods' float64). Integer true division gives float64; sums and products accumulate in int64/uint64; float ufuncs on integers give float32 where NumPy gives float16. New: DType, ZerosOf/OnesOf/FullOf, FromSlice/Data/Item, AsType, AtComplex/SetComplex, Scalar, SumAll/ProdAll, LogicalNot/And/Or/Xor, Any/All, Real/Imag/Conj/Angle. Breaking: comparisons return Bool; Nonzero and ArgMax/ArgMinAxis return Int64 indices. MaskSelect and Where accept any dtype by truthiness, so the old 0/1 float masks keep working. The float64 comparison and arg-axis kernels they used are removed. Checked against NumPy 2.5.3: all 169 result_type cells, weak scalars, and the result dtype of unary ufuncs and reductions; 3,147 values over 47 operations on every dtype with edge values (bit-exact where both sides round correctly; a sabotaged integer max fails 48). Coverage 100% under the CI gate. Float64 Add/Sum/Max/AddInto A/B against main, interleaved: within noise (0.93-1.02). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Phase 2: dtypes. Design first (docs/design-dtypes.md), then the implementation.
What
Arrayholds bool, int8…int64, uint8…uint64, float32/64, complex64/128 — a runtime property, as in NumPy. The float64 storage and every float64 SIMD/multicore kernel are untouched; the other dtypes run generic loops dispatched by generated type switches (gen_dtypes.go→zz_dtypes_gen.go).numpy.result_type; Go scalars are weak (NEP 50):Scalar(1), and the*Scalarmethods' float64.DType,ZerosOf/OnesOf/FullOf,FromSlice/Data/Item,AsType,AtComplex/SetComplex,Scalar,SumAll/ProdAll,Logical*,Any/All,Real/Imag/Conj/Angle.Breaking
BoolNonzero,ArgMaxAxis,ArgMinAxis→ Float64 indicesInt64MaskSelect/Whereaccept any dtype by truthiness, so old 0/1 masks still work. The only fleet consumer (go-embedded-ruby) uses none of these.Verification
result_typecells, weak scalars, unary/reduction result dtypes — all match (float16 read as float32, the documented difference).maxfails 48.-race -coverpkg); vet for linux/386, linux/arm, js/wasm; the s390x test binary builds.Found on the way
NumPy's out-of-range float→int casts are platform-defined (arm64:
+Inf→int8 is −1). Here they saturate on every platform — documented onAsType.🤖 Generated with Claude Code