Files
tensor/internal/core/randomsub_test.go
T
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

131 lines
4.1 KiB
Go

// Copyright (c) 2026 Petr Balvín <opensource@petrbalvin.org> (https://petrbalvin.org)
// SPDX-License-Identifier: MIT
package core
import (
"math"
"testing"
)
// TestGeneratorStreamIsPinned pins the raw stream of one seed: the
// splitmix64 seeding walk and the xoshiro core must keep producing
// exactly these bits, because every recorded oracle digest downstream
// of the generator hangs on them.
func TestGeneratorStreamIsPinned(t *testing.T) {
g := NewGenerator(1)
for _, want := range []uint64{
0xcfc5d07f6f03c29b, 0xbf424132963fe08d, 0x19a37d5757aaf520, 0xbf08119f05cd56d6,
} {
if got := g.Next(); got != want {
t.Fatalf("Next() = %#016x, want %#016x", got, want)
}
}
n, err := Normal(NewGenerator(7), 3, 0, 1)
if err != nil {
t.Fatal(err)
}
for i, want := range []float64{1.674036445441065, 0.53789816819896552, 1.2079282540944534} {
if n.FloatAt(i) != want {
t.Fatalf("Normal draw %d = %.17g, want %.17g", i, n.FloatAt(i), want)
}
}
}
// TestSplitmix64 pins the scalar mixer against an independent
// transcription of the finaliser and pins the state discipline: the
// returned state is the input plus the golden constant, the output is
// the mixed state, and chaining reproduces the walk.
func TestSplitmix64(t *testing.T) {
mix := func(z uint64) uint64 {
z = (z ^ (z >> 30)) * 0xBF58476D1CE4E5B9
z = (z ^ (z >> 27)) * 0x94D049BB133111EB
return z ^ (z >> 31)
}
const golden = 0x9E3779B97F4A7C15
state, v := Splitmix64(0)
if state != golden || v != mix(golden) {
t.Fatalf("Splitmix64(0) = (%#016x, %#016x), want (%#016x, %#016x)", state, v, uint64(golden), mix(golden))
}
for _, s := range []uint64{0, 1, 0xdeadbeef, ^uint64(0)} {
state, v := Splitmix64(s)
if state != s+golden {
t.Fatalf("Splitmix64(%#016x) advanced the state to %#016x, want %#016x", s, state, s+golden)
}
if v != mix(state) {
t.Fatalf("Splitmix64(%#016x) output %#016x, want %#016x", s, v, mix(state))
}
// Chaining from the returned state repeats the definition.
next, nv := Splitmix64(state)
if nv != mix(next) || next != state+golden {
t.Fatal("the chained step disagrees with the one-step definition")
}
}
}
// mustSub builds a substream, failing the test on a bad index.
func mustSub(t *testing.T, seed int64, index int) *Generator {
t.Helper()
g, err := Substream(seed, index)
if err != nil {
t.Fatalf("Substream(%d, %d): %v", seed, index, err)
}
return g
}
// draw returns n uniform floats from g.
func draw(t *testing.T, g *Generator, n int) []float64 {
t.Helper()
a, err := Floats(g, n)
if err != nil {
t.Fatal(err)
}
return a.RawFloats()[:n]
}
// sameBits reports whether two draw prefixes are bit for bit equal.
func sameBits(a, b []float64) bool {
if len(a) != len(b) {
return false
}
for i := range a {
if math.Float64bits(a[i]) != math.Float64bits(b[i]) {
return false
}
}
return true
}
// TestSubstream pins the stream family: the same seed and index
// reproduce the same draws, distinct indices give distinct draws (so
// no member is a copy of another), the family differs from the plain
// seeded generator, and a negative index is an error.
func TestSubstream(t *testing.T) {
const draws = 16
base := draw(t, mustSub(t, 42, 0), draws)
for i := 1; i < 8; i++ {
if sameBits(draw(t, mustSub(t, 42, i), draws), base) {
t.Fatalf("substream %d drew the same prefix as substream 0", i)
}
}
// Determinism: the same index redraws the same bits.
if !sameBits(draw(t, mustSub(t, 42, 3), draws), draw(t, mustSub(t, 42, 3), draws)) {
t.Fatal("the same substream drew different bits on a second construction")
}
// The family hangs off the seed, not beside the plain generator:
// substream 0 must differ from NewGenerator(42) and from the
// neighbouring seed's plain stream.
for _, seed := range []int64{42, 43} {
if sameBits(draw(t, NewGenerator(seed), draws), base) {
t.Fatalf("substream 0 coincides with NewGenerator(%d)", seed)
}
}
// A large index is as legal as a small one.
if _, err := Substream(42, 1<<40); err != nil {
t.Fatalf("Substream at index 2^40: %v", err)
}
if _, err := Substream(42, -1); err == nil {
t.Fatal("a negative index: want an error")
}
}