feat: initial release
Release / gates (push) Successful in 4m38s
Test / test (push) Successful in 5m16s
Release / release (push) Successful in 35s

Assisted-by: GLM 5.3 Flash
This commit is contained in:
2026-09-03 10:00:00 +02:00
commit af4ee19703
617 changed files with 191195 additions and 0 deletions
+119
View File
@@ -0,0 +1,119 @@
// Copyright (c) 2026 Petr Balvín <opensource@petrbalvin.org> (https://petrbalvin.org)
// SPDX-License-Identifier: MIT
package signal
import (
"strings"
"testing"
"sourcedock.dev/petrbalvin/tensor/internal/core"
)
// Complex-refusal pins: complex inputs that reached FloatAt's nil-int
// branch, degenerate kernels and empty windows that answered NaN, and
// contract gaps the sibling entry points had already closed.
// TestResampleComplexRefusal: Resample and Decimate widened a complex
// series through widenFloats, which panicked instead of refusing.
func TestResampleComplexRefusal(t *testing.T) {
c := mustComplexes(t, []complex128{1 + 1i, 2, 3 - 1i, 4}, 4)
if _, err := Resample(c, 2, 1, 0); err == nil || !strings.Contains(err.Error(), "complex") {
t.Fatalf("Resample on complex: err = %v", err)
}
if _, err := Decimate(c, 2, 0); err == nil || !strings.Contains(err.Error(), "complex") {
t.Fatalf("Decimate on complex: err = %v", err)
}
}
// TestNUFFTComplexCoordinates: complex coordinates reached FloatAt's
// nil-int branch and panicked.
func TestNUFFTComplexCoordinates(t *testing.T) {
x := mustComplexes(t, []complex128{0.1 + 0.2i, -0.2}, 2)
c := mustComplexes(t, []complex128{1, 2i}, 2)
if _, err := NUFFTType1(x, c, 8); err == nil || !strings.Contains(err.Error(), "real") {
t.Fatalf("NUFFTType1 with complex coordinates: err = %v", err)
}
}
// TestAnalyticSignalComplexRefusal: the analytic signal is defined for
// a real series; a complex one was silently transformed.
func TestAnalyticSignalComplexRefusal(t *testing.T) {
c := mustComplexes(t, []complex128{1, 2, 3, 4}, 4)
if _, err := AnalyticSignal(c); err == nil || !strings.Contains(err.Error(), "complex") {
t.Fatalf("AnalyticSignal on complex: err = %v", err)
}
}
// TestConvComplexBiasRefusal: the convolutions gate the input and the
// kernel on dtype but widened the bias through FloatAt, whose complex
// branch reads a nil payload and panics. A complex bias is refused
// like a complex kernel.
func TestConvComplexBiasRefusal(t *testing.T) {
bias := mustComplexes(t, []complex128{1 + 2i}, 1)
in2 := mustFloats(t, []float64{1, 2, 3, 4, 5, 6, 7, 8}, 1, 1, 2, 4)
ker2 := mustFloats(t, []float64{1, 0, 0, 1}, 1, 1, 2, 2)
in3 := mustFloats(t, []float64{1, 2, 3, 4, 5, 6, 7, 8}, 1, 1, 2, 2, 2)
ker3 := mustFloats(t, []float64{1, 1, 1, 1, 1, 1, 1, 1}, 1, 1, 2, 2, 2)
in1 := mustFloats(t, []float64{1, 2, 3, 4}, 1, 1, 4)
ker1 := mustFloats(t, []float64{1, 1}, 1, 1, 2)
for name, fn := range map[string]func() (*core.Array, error){
"Conv1D": func() (*core.Array, error) { return Conv1D(in1, ker1, bias, 1, 0, 1) },
"Conv2D": func() (*core.Array, error) { return Conv2D(in2, ker2, bias, 1, 0) },
"Conv3D": func() (*core.Array, error) { return Conv3D(in3, ker3, bias, 1, [3]int{0, 0, 0}, [3]int{1, 1, 1}) },
"ConvTranspose2D": func() (*core.Array, error) { return ConvTranspose2D(in2, ker2, bias, 1, 0) },
} {
if _, err := fn(); err == nil || !strings.Contains(err.Error(), "complex bias") {
t.Fatalf("%s with a complex bias: err = %v", name, err)
}
}
}
// TestDecimateOneTap: taps = 1 divided by taps−1 = 0 in the Kaiser
// window and every output sample came back NaN; a one-tap kernel is
// the identity, so decimation keeps every factor-th sample.
func TestDecimateOneTap(t *testing.T) {
x := mustFromFloats(t, []float64{10, 11, 12, 13, 14, 15, 16, 17}, 8)
out, err := Decimate(x, 2, 1)
if err != nil {
t.Fatalf("Decimate taps=1: %v", err)
}
if out.Len() != 4 {
t.Fatalf("output length %d, want 4", out.Len())
}
for i := range 4 {
if got := out.FloatAt(i); got != float64(10+2*i) {
t.Fatalf("out[%d] = %v, want %d", i, got, 10+2*i)
}
}
}
// TestAdaptivePoolEmptySpatial: a zero-length spatial dimension left
// every window empty and max answered -Inf while avg divided by zero;
// both are errors now, in every rank.
func TestAdaptivePoolEmptySpatial(t *testing.T) {
empty1D, err := core.Zeros(core.Float, 1, 1, 0)
if err != nil {
t.Fatal(err)
}
empty2D, err := core.Zeros(core.Float, 1, 1, 0, 4)
if err != nil {
t.Fatal(err)
}
empty3D, err := core.Zeros(core.Float, 1, 1, 2, 0, 4)
if err != nil {
t.Fatal(err)
}
for name, fn := range map[string]func() (*core.Array, error){
"max1D": func() (*core.Array, error) { return AdaptiveMaxPool1D(empty1D, 2) },
"max2D": func() (*core.Array, error) { return AdaptiveMaxPool2D(empty2D, 2, 2) },
"max3D": func() (*core.Array, error) { return AdaptiveMaxPool3D(empty3D, 2, 2, 2) },
"avg1D": func() (*core.Array, error) { return AdaptiveAvgPool1D(empty1D, 2) },
"avg2D": func() (*core.Array, error) { return AdaptiveAvgPool2D(empty2D, 2, 2) },
"avg3D": func() (*core.Array, error) { return AdaptiveAvgPool3D(empty3D, 2, 2, 2) },
} {
if _, err := fn(); err == nil || !strings.Contains(err.Error(), "spatial") {
t.Fatalf("%s on an empty spatial dimension: err = %v", name, err)
}
}
}