generated from mathias/template-go-web
CD / Lint / Test / Vet (push) Successful in 5s
go.mod declared this module under gitea.d-ma.be, the pre-rename host (infra ADR-0004). That name still resolves in DNS but no longer serves -- HTTPS to it fails outright -- so the declared path pointed at nothing. It built anyway, because a Go module does not have to be fetchable from its own declared path to compile locally. That is exactly what made it durable rot: nothing failed, so nothing flagged it. What it did break is anyone trying to depend on this repo -- `go get git.d-ma.be/mathias/<repo>` fails on the path mismatch, and an importer would have to spell the dead host. Verified safe before changing: nothing in the estate requires this module (checked every go.mod across the Go repos) -- these are leaf binaries, so the rename breaks no importer. Mechanical: module path plus every internal import rewritten, templ regenerated where applicable. Verified after -- go build, go vet, go test and golangci-lint (against a Go 1.26.1 toolchain, matching CI) all pass, and no gitea.d-ma.be reference remains in any .go/.templ/.mod file. Found by an estate-wide scan for the old host, prompted by the same rot turning up in tapir internal/web/views.templ (tapir@4bafd5f).
139 lines
3.4 KiB
Go
139 lines
3.4 KiB
Go
package eval_test
|
|
|
|
import (
|
|
"math"
|
|
"math/rand"
|
|
"testing"
|
|
|
|
"git.d-ma.be/mathias/jepa-fx-risk/internal/eval"
|
|
)
|
|
|
|
func seededRNG(seed int64) *rand.Rand {
|
|
return rand.New(rand.NewSource(seed))
|
|
}
|
|
|
|
// ── LinearProbe (val_vol_r2) ──────────────────────────────────────────────────
|
|
|
|
func TestLinearProbe_Perfect(t *testing.T) {
|
|
n := 50
|
|
emb := make([][]float64, n)
|
|
y := make([]float64, n)
|
|
for i := range emb {
|
|
emb[i] = []float64{float64(i)}
|
|
y[i] = float64(i)
|
|
}
|
|
r2 := eval.LinearProbe(emb, y, 1e-3)
|
|
if r2 < 0.99 {
|
|
t.Fatalf("perfect predictor: want R²≥0.99, got %.4f", r2)
|
|
}
|
|
}
|
|
|
|
func TestLinearProbe_ConstantTarget(t *testing.T) {
|
|
n := 40
|
|
emb := make([][]float64, n)
|
|
y := make([]float64, n)
|
|
for i := range emb {
|
|
emb[i] = []float64{float64(i), float64(i * i)}
|
|
y[i] = 3.0
|
|
}
|
|
r2 := eval.LinearProbe(emb, y, 1e-3)
|
|
if r2 > 0.01 {
|
|
t.Fatalf("constant target: want R²≤0.01, got %.4f", r2)
|
|
}
|
|
}
|
|
|
|
func TestLinearProbe_NoiseEmbedding(t *testing.T) {
|
|
rng := seededRNG(42)
|
|
n := 80
|
|
emb := make([][]float64, n)
|
|
y := make([]float64, n)
|
|
for i := range emb {
|
|
emb[i] = []float64{rng.NormFloat64(), rng.NormFloat64()}
|
|
y[i] = float64(i)
|
|
}
|
|
r2 := eval.LinearProbe(emb, y, 1e-3)
|
|
if r2 > 0.10 {
|
|
t.Fatalf("noise embedding: want R²<0.10, got %.4f", r2)
|
|
}
|
|
}
|
|
|
|
// ── Silhouette ────────────────────────────────────────────────────────────────
|
|
|
|
func TestSilhouette_PerfectClusters(t *testing.T) {
|
|
emb := make([][]float64, 40)
|
|
labels := make([]int, 40)
|
|
for i := range emb {
|
|
if i < 20 {
|
|
emb[i] = []float64{0.0, 0.0}
|
|
labels[i] = 0
|
|
} else {
|
|
emb[i] = []float64{1000.0, 1000.0}
|
|
labels[i] = 1
|
|
}
|
|
}
|
|
sil, err := eval.Silhouette(emb, labels)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if sil < 0.95 {
|
|
t.Fatalf("perfect clusters: want sil≥0.95, got %.4f", sil)
|
|
}
|
|
}
|
|
|
|
func TestSilhouette_SingleLabel(t *testing.T) {
|
|
emb := [][]float64{{1, 2}, {3, 4}, {5, 6}}
|
|
labels := []int{0, 0, 0}
|
|
_, err := eval.Silhouette(emb, labels)
|
|
if err == nil {
|
|
t.Fatal("expected error for single-label input")
|
|
}
|
|
}
|
|
|
|
func TestSilhouette_RandomClusters(t *testing.T) {
|
|
rng := seededRNG(7)
|
|
n := 60
|
|
emb := make([][]float64, n)
|
|
labels := make([]int, n)
|
|
for i := range emb {
|
|
emb[i] = []float64{rng.NormFloat64(), rng.NormFloat64()}
|
|
labels[i] = i % 2
|
|
}
|
|
sil, err := eval.Silhouette(emb, labels)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if math.Abs(sil) > 0.30 {
|
|
t.Fatalf("random clusters: want |sil|≤0.30, got %.4f", sil)
|
|
}
|
|
}
|
|
|
|
// ── EffectiveRank ─────────────────────────────────────────────────────────────
|
|
|
|
func TestEffectiveRank_Rank1(t *testing.T) {
|
|
emb := make([][]float64, 30)
|
|
for i := range emb {
|
|
emb[i] = []float64{1.0, 2.0, 3.0, 4.0}
|
|
}
|
|
er := eval.EffectiveRank(emb)
|
|
if er > 1.5 {
|
|
t.Fatalf("rank-1 matrix: want erank≤1.5, got %.4f", er)
|
|
}
|
|
}
|
|
|
|
func TestEffectiveRank_FullRank(t *testing.T) {
|
|
rng := seededRNG(99)
|
|
dim := 8
|
|
emb := make([][]float64, 200)
|
|
for i := range emb {
|
|
row := make([]float64, dim)
|
|
for j := range row {
|
|
row[j] = rng.NormFloat64()
|
|
}
|
|
emb[i] = row
|
|
}
|
|
er := eval.EffectiveRank(emb)
|
|
if er < float64(dim)*0.7 {
|
|
t.Fatalf("full-rank: want erank≥%.1f, got %.4f", float64(dim)*0.7, er)
|
|
}
|
|
}
|