// Copyright (c) 2026 Petr BalvĂ­n (https://petrbalvin.org) // SPDX-License-Identifier: MIT package integrate import ( "math" "strings" "testing" "sourcedock.dev/petrbalvin/tensor/internal/core" ) // Regression pins: budgets that did not bound what they // promised, and non-finite states that integrated to no error. // TestIntegrateNDDimensionBudget: in 10 dimensions the root box alone // costs 5^10 + 3^10 evaluations, about five times the default budget, // before the first budget check could fire. func TestIntegrateNDDimensionBudget(t *testing.T) { lower := make([]float64, 10) upper := make([]float64, 10) for i := range upper { upper[i] = 1 } f := func(x []float64) float64 { return 1 } _, err := IntegrateND(f, lower, upper, CubatureOptions{}) if err == nil || !strings.Contains(err.Error(), "budget") { t.Fatalf("IntegrateND in 10 dimensions under the default budget: err = %v", err) } } // TestPDEStepCountBound: a dt far below tFinal/1e12 wrapped the step // count conversion, and the silently larger step ran past the wave // equation's CFL check. func TestPDEStepCountBound(t *testing.T) { u0, err := core.FromFloats([]float64{0, 1, 0, 1, 0}, 5) if err != nil { t.Fatal(err) } if _, err := IntegrateHeat1D(u0, 1, 0.1, 1, 1e-300, 2, 0, 0); err == nil || !strings.Contains(err.Error(), "1e12") { t.Fatalf("Heat1D with an unhonourable dt: err = %v", err) } u2, err := core.FromFloats([]float64{1, 2, 3, 4, 5, 6, 7, 8, 9}, 3, 3) if err != nil { t.Fatal(err) } if _, err := IntegrateHeat2D(u2, 1, 0.1, 0.1, 1, 1e-300, 2, 0, 0, 0, 0); err == nil || !strings.Contains(err.Error(), "1e12") { t.Fatalf("Heat2D with an unhonourable dt: err = %v", err) } } // TestPDEVerletRejectNonFinite: a NaN or Inf initial state flowed // through the stencils and published an all-NaN history with no error. func TestPDEVerletRejectNonFinite(t *testing.T) { bad, err := core.FromFloats([]float64{1, math.NaN(), 0, 1, 0}, 5) if err != nil { t.Fatal(err) } if _, err := IntegrateHeat1D(bad, 1, 0.1, 1, 0.1, 2, 0, 0); err == nil || !strings.Contains(err.Error(), "non-finite") { t.Fatalf("Heat1D on a NaN state: err = %v", err) } q, err := core.FromFloats([]float64{1, math.Inf(1)}, 2) if err != nil { t.Fatal(err) } p, err := core.FromFloats([]float64{0, 0}, 2) if err != nil { t.Fatal(err) } accel := func(x *core.Array) (*core.Array, error) { return core.Copy(x), nil } if _, _, err := IntegrateVerlet(accel, 0, 1, q, p, 2); err == nil || !strings.Contains(err.Error(), "non-finite") { t.Fatalf("Verlet on an Inf state: err = %v", err) } }