Files
tensor/stats/bench_test.go
petrbalvin af4ee19703
Release / gates (push) Successful in 4m38s
Test / test (push) Successful in 5m16s
Release / release (push) Successful in 35s
feat: initial release
Assisted-by: GLM 5.3 Flash
2026-09-03 10:00:00 +02:00

266 lines
5.2 KiB
Go

// Copyright (c) 2026 Petr Balvín <opensource@petrbalvin.org> (https://petrbalvin.org)
// SPDX-License-Identifier: MIT
package stats
import (
"math"
"testing"
"sourcedock.dev/petrbalvin/tensor/internal/core"
)
// Benchmarks for the package's heavy paths: the O(n·m) kernel-density
// sweep, the sort-backed summaries, the regression and GLM normal
// equations and the incomplete-function machinery under the CDFs.
// benchSeries builds a deterministic float vector of length n mixing a
// few incommensurate frequencies, so sorts and moment sums see a
// realistic spread without a generator.
func benchSeries(n int) []float64 {
vals := make([]float64, n)
for i := range vals {
x := float64(i)
vals[i] = math.Sin(0.001*x)*10 + math.Sin(0.013*x)*3 + math.Cos(0.11*x) + float64(i%7)*0.125
}
return vals
}
func benchArray(b *testing.B, n int, shape ...int) *core.Array {
b.Helper()
if len(shape) == 0 {
shape = []int{n}
}
a, err := core.FromFloats(benchSeries(n), shape...)
if err != nil {
b.Fatal(err)
}
return a
}
func BenchmarkKernelDensity(b *testing.B) {
sample := benchArray(b, 1000)
points := benchArray(b, 256)
b.ReportAllocs()
for b.Loop() {
if _, err := KernelDensity(sample, 0.5, points); err != nil {
b.Fatal(err)
}
}
}
func BenchmarkKernelDensitySilverman(b *testing.B) {
sample := benchArray(b, 2000)
points := benchArray(b, 512)
b.ReportAllocs()
for b.Loop() {
if _, err := KernelDensity(sample, 0, points); err != nil {
b.Fatal(err)
}
}
}
func BenchmarkHistogram(b *testing.B) {
a := benchArray(b, 100000)
b.ReportAllocs()
for b.Loop() {
if _, _, err := Histogram(a, 64); err != nil {
b.Fatal(err)
}
}
}
func BenchmarkRollingMean(b *testing.B) {
a := benchArray(b, 8192)
b.ReportAllocs()
for b.Loop() {
if _, err := RollingMean(a, 32); err != nil {
b.Fatal(err)
}
}
}
// benchmarkRolling1M drives one rolling reduction over a million-sample
// series at the short and the long window, the pair the carried-update
// rescan trade-off is measured on.
func benchmarkRolling1M(b *testing.B, window int, sum bool) {
b.Helper()
a := benchArray(b, 1<<20)
b.ReportAllocs()
for b.Loop() {
var err error
if sum {
_, err = RollingSum(a, window)
} else {
_, err = RollingMean(a, window)
}
if err != nil {
b.Fatal(err)
}
}
}
func BenchmarkRollingSumWindow8(b *testing.B) {
benchmarkRolling1M(b, 8, true)
}
func BenchmarkRollingSumWindow4096(b *testing.B) {
benchmarkRolling1M(b, 4096, true)
}
func BenchmarkRollingMeanWindow8(b *testing.B) {
benchmarkRolling1M(b, 8, false)
}
func BenchmarkRollingMeanWindow4096(b *testing.B) {
benchmarkRolling1M(b, 4096, false)
}
func BenchmarkRollingMax(b *testing.B) {
a := benchArray(b, 8192)
b.ReportAllocs()
for b.Loop() {
if _, err := RollingMax(a, 32); err != nil {
b.Fatal(err)
}
}
}
func BenchmarkMedian(b *testing.B) {
a := benchArray(b, 50000)
b.ReportAllocs()
for b.Loop() {
if _, err := Median(a); err != nil {
b.Fatal(err)
}
}
}
func BenchmarkCovarianceMatrix(b *testing.B) {
a := benchArray(b, 1000*16, 1000, 16)
b.ReportAllocs()
for b.Loop() {
if _, err := CovarianceMatrix(a); err != nil {
b.Fatal(err)
}
}
}
func BenchmarkLinearRegression(b *testing.B) {
n, p := 2000, 8
xv := make([]float64, n*p)
yv := make([]float64, n)
for r := range n {
yv[r] = 0
for c := range p {
v := float64((r*31+c*17)%97)/97 - 0.5
xv[r*p+c] = v
yv[r] += float64(c+1) * v
}
}
x, err := core.FromFloats(xv, n, p)
if err != nil {
b.Fatal(err)
}
y, err := core.FromFloats(yv, n)
if err != nil {
b.Fatal(err)
}
b.ReportAllocs()
for b.Loop() {
if _, err := LinearRegression(x, y); err != nil {
b.Fatal(err)
}
}
}
func BenchmarkLogisticRegression(b *testing.B) {
n, p := 1000, 6
xv := make([]float64, n*p)
yv := make([]float64, n)
for r := range n {
eta := -1.5
for c := range p {
v := float64((r*13+c*29)%53)/53 - 0.5
xv[r*p+c] = v
eta += float64(c) * v
}
if r%2 == 0 {
eta += 0.5
}
if eta > 0 {
yv[r] = 1
}
}
x, err := core.FromFloats(xv, n, p)
if err != nil {
b.Fatal(err)
}
y, err := core.FromFloats(yv, n)
if err != nil {
b.Fatal(err)
}
b.ReportAllocs()
for b.Loop() {
if _, err := LogisticRegression(x, y); err != nil {
b.Fatal(err)
}
}
}
func BenchmarkGammaCDF(b *testing.B) {
b.ReportAllocs()
for b.Loop() {
if _, err := GammaCDF(2.5, 3.0, 1.2); err != nil {
b.Fatal(err)
}
}
}
func BenchmarkBetaIncomplete(b *testing.B) {
b.ReportAllocs()
for b.Loop() {
if _, err := BetaIncomplete(0.4, 2.5, 3.5); err != nil {
b.Fatal(err)
}
}
}
func BenchmarkStudentTQuantile(b *testing.B) {
b.ReportAllocs()
for b.Loop() {
if _, err := StudentTQuantile(0.975, 12); err != nil {
b.Fatal(err)
}
}
}
func BenchmarkNormalQuantile(b *testing.B) {
b.ReportAllocs()
for b.Loop() {
if _, err := NormalQuantile(0.975); err != nil {
b.Fatal(err)
}
}
}
func BenchmarkGammaQuantile(b *testing.B) {
b.ReportAllocs()
for b.Loop() {
if _, err := GammaQuantile(0.99, 3, 1.2); err != nil {
b.Fatal(err)
}
}
}
func BenchmarkKolmogorovSmirnovTest(b *testing.B) {
a := benchArray(b, 4000)
c := benchArray(b, 5000)
b.ReportAllocs()
for b.Loop() {
if _, _, err := KolmogorovSmirnovTest(a, c); err != nil {
b.Fatal(err)
}
}
}