// Copyright (c) 2026 Petr Balvín (https://petrbalvin.org) // SPDX-License-Identifier: MIT package core import ( "math" "testing" ) // The staged views design (docs/ARCHITECTURE.md) starts with the // representation: an array may alias another's storage, either as a // contiguous region (payload rebased, strides nil; invisible to every // kernel) or as a strided view (payload rebased plus explicit strides). // These tests pin the machinery before Slice starts producing views. // stridedColumnViewOf builds the column slice [c0, c1) of a 2-D array // as a strided view, the shape a non-contiguous Slice will produce. func stridedColumnViewOf(a *Array, c0, c1 int) *Array { rows, cols := a.Shape()[0], a.Shape()[1] view := &Array{ shape: []int{rows, c1 - c0}, dt: a.Dtype(), floats: a.RawFloats()[c0:], strides: []int{cols, 1}, } return view } // TestStridedViewAccessors pins the accessor contract on a strided // view: element i must come from payload[Σ i_d·strides[d]], never from // payload[i]. func TestStridedViewAccessors(t *testing.T) { base, err := FromFloats([]float64{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, }, 3, 4) if err != nil { t.Fatal(err) } view := stridedColumnViewOf(base, 1, 3) // columns 1..2 if view.Len() != 6 { t.Fatalf("view len %d, want 6", view.Len()) } if view.isContiguous() { t.Fatal("strided view reported contiguous") } // Row-major over (3, 2): [[2,3],[6,7],[10,11]]. want := []float64{2, 3, 6, 7, 10, 11} for i, w := range want { if got := view.FloatAt(i); got != w { t.Errorf("view.FloatAt(%d) = %v, want %v", i, got, w) } } // The multi-dimensional accessor agrees. for r := range 3 { for c := range 2 { if got, _ := FloatAt(view, r, c); got != want[r*2+c] { t.Errorf("FloatAt(view, %d, %d) = %v, want %v", r, c, got, want[r*2+c]) } } } if got := view.String(); got != "float (3, 2) [2, 3, 6, 7, 10, 11]" { t.Errorf("view.String() = %q", got) } } // TestStridedViewMaterialise pins that a view copies out its own // elements, densely and in view order, and that the copy is independent // of the aliased storage. func TestStridedViewMaterialise(t *testing.T) { base, err := FromFloats([]float64{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, }, 3, 4) if err != nil { t.Fatal(err) } view := stridedColumnViewOf(base, 1, 3) dense := view.materialise() if !dense.isContiguous() { t.Fatal("materialised copy still carries strides") } if dense.Len() != 6 || dense.Shape()[0] != 3 || dense.Shape()[1] != 2 { t.Fatalf("materialised shape %s len %d", shapeText(dense.Shape()), dense.Len()) } want := []float64{2, 3, 6, 7, 10, 11} for i, w := range want { if got := dense.FloatAt(i); got != w { t.Errorf("materialised[%d] = %v, want %v", i, got, w) } } // The copy owns its payload: the view is still the base's columns. if base.FloatAt(1) != 2 { t.Fatalf("base mutated by materialise: %v", base.FloatAt(1)) } } // TestMaterialiseContiguousIsIdentity pins the fast path: a contiguous // array is returned untouched, so callers can materialise unconditionally // without paying a copy. func TestMaterialiseContiguousIsIdentity(t *testing.T) { a, err := FromFloats([]float64{1, 2, 3, 4}, 2, 2) if err != nil { t.Fatal(err) } if !a.isContiguous() { t.Fatal("fresh array is not contiguous") } if a.materialise() != a { t.Fatal("contiguous materialise copied instead of returning the receiver") } } // TestContiguousRebasedViewIsTransparent pins the property the kernels // lean on: a contiguous region becomes a view by rebasing the payload // with nil strides, so payload[i] is element i exactly as before and no // kernel needs to know a view exists. func TestContiguousRebasedViewIsTransparent(t *testing.T) { base, err := FromInts([]int64{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, }, 3, 4) if err != nil { t.Fatal(err) } // Row 1 of the base, as a (1, 4) 2-D view. row := &Array{ shape: []int{1, 4}, dt: Int, ints: base.RawInts()[4:8], } if !row.isContiguous() { t.Fatal("rebased row view is not contiguous") } if row.Len() != 4 { t.Fatalf("row view len %d, want 4", row.Len()) } for i, w := range []int64{5, 6, 7, 8} { if got, _ := IntAt(row, 0, i); got != w { t.Errorf("IntAt(row, 0, %d) = %d, want %d", i, got, w) } } // Direct payload reads are valid for a contiguous view: this is the // guarantee that keeps every kernel working unchanged. if row.RawInts()[0] != 5 || row.RawInts()[3] != 8 { t.Fatalf("direct payload read on a contiguous view is wrong: %v", row.RawInts()[:4]) } // A copy of a view carries only the view's elements. cp := Copy(row) if cp.Len() != 4 || len(cp.RawInts()) != 4 { t.Fatalf("Copy(view) len %d payload %d, want 4", cp.Len(), len(cp.RawInts())) } } // TestPhysIndexMapping pins the index mapping directly, including the // contiguous fast path. func TestPhysIndexMapping(t *testing.T) { contiguous := &Array{shape: []int{2, 3}, dt: Int, ints: make([]int64, 6)} for i := range 6 { if got := contiguous.physIndex(i); got != i { t.Errorf("contiguous physIndex(%d) = %d, want identity", i, got) } } // (2, 2) view over a 3-wide base starting at column 1: // element (r, c) is at payload[r*3 + c]. view := &Array{shape: []int{2, 2}, dt: Int, ints: make([]int64, 6), strides: []int{3, 1}} want := []int{0, 1, 3, 4} for i, w := range want { if got := view.physIndex(i); got != w { t.Errorf("view.physIndex(%d) = %d, want %d", i, got, w) } } } // TestStridedViewComplexAccessors pins complex and int views too, since // each dtype has its own payload field. func TestStridedViewComplexAccessors(t *testing.T) { base, err := FromComplexes([]complex128{ 1 + 1i, 2 + 2i, 3 + 3i, 4 + 4i, }, 2, 2) if err != nil { t.Fatal(err) } // Column 1 view of a 2x2 base. view := &Array{ shape: []int{2, 1}, dt: Complex, complexes: base.RawComplexes()[1:], strides: []int{2, 1}, } if got := view.ComplexAt(0); got != 2+2i { t.Errorf("complexAt(0) = %v, want (2+2i)", got) } if got := view.ComplexAt(1); got != 4+4i { t.Errorf("complexAt(1) = %v, want (4+4i)", got) } dense := view.materialise() if dense.Len() != 2 || dense.ComplexAt(1) != 4+4i { t.Errorf("materialised complex view: %v", dense) } } // TestStridedViewFloat32Accessors covers the float32 payload path. func TestStridedViewFloat32Accessors(t *testing.T) { base, err := FromFloat32s([]float32{1, 2, 3, 4, 5, 6}, 2, 3) if err != nil { t.Fatal(err) } // Columns 1..2 of a 3-wide base. view := &Array{ shape: []int{2, 2}, dt: Float32, floats32: base.RawFloat32s()[1:], strides: []int{3, 1}, } want := []float32{2, 3, 5, 6} for i, w := range want { if got := view.float32At(i); got != w { t.Errorf("float32At(%d) = %v, want %v", i, got, w) } if got := view.FloatAt(i); math.Abs(got-float64(w)) > 1e-12 { t.Errorf("floatAt(%d) = %v, want %v", i, got, w) } } } // TestSliceReturnsContiguousView pins stage (b): a leading-axis slice is // a view sharing the source's storage, not a copy. func TestSliceReturnsContiguousView(t *testing.T) { base, err := FromInts([]int64{ 1, 2, 3, 4, 5, 6, 7, 8, 9, }, 3, 3) if err != nil { t.Fatal(err) } view, err := Slice(base, 0, 1, 3) if err != nil { t.Fatal(err) } if view.Len() != 6 || view.Shape()[0] != 2 { t.Fatalf("slice shape %s len %d", shapeText(view.Shape()), view.Len()) } want := []int64{4, 5, 6, 7, 8, 9} for i, w := range want { if got := view.RawInts()[i]; got != w { t.Errorf("view payload[%d] = %d, want %d", i, got, w) } } // Aliasing proof: a write into the base's storage (which only this // test does; the library never writes through an array it did not // allocate) is visible through the view. The view starts at row 1, // so its payload is base.RawInts()[3:]. base.RawInts()[3] = 111 if got, _ := IntAt(view, 0, 0); got != 111 { t.Fatalf("view does not alias the base: got %d", got) } // And the view is indistinguishable from a dense array to a kernel. if !view.isContiguous() { t.Fatal("slice view is not contiguous") } } // TestSliceFullDimensionReturnsView pins the second contiguous case: a // slice that takes a dimension in full is a view too. func TestSliceFullDimensionReturnsView(t *testing.T) { base, err := FromFloats([]float64{1, 2, 3, 4, 5, 6}, 2, 3) if err != nil { t.Fatal(err) } view, err := Slice(base, 1, 0, 3) // the whole of dim 1 if err != nil { t.Fatal(err) } for i := range 6 { if got := view.RawFloats()[i]; got != float64(i+1) { t.Fatalf("view[%d] = %v, want %d", i, got, i+1) } } base.RawFloats()[2] = 42 if got := view.RawFloats()[2]; got != 42 { t.Fatalf("full-dimension slice does not alias: %v", got) } } // TestSliceInteriorRangeCopies pins the deliberate boundary: an interior // range is not a contiguous region, so Slice copies it: a strided view // there would need the kernel-boundary materialisation audit. func TestSliceInteriorRangeCopies(t *testing.T) { base, err := FromInts([]int64{ 1, 2, 3, 4, 5, 6, 7, 8, }, 2, 4) if err != nil { t.Fatal(err) } out, err := Slice(base, 1, 1, 3) if err != nil { t.Fatal(err) } if !out.isContiguous() { t.Fatal("interior slice is not contiguous") } // Columns 1..2: [[2,3],[6,7]]. want := []int64{2, 3, 6, 7} for i, w := range want { if got := out.RawInts()[i]; got != w { t.Errorf("interior slice[%d] = %d, want %d", i, got, w) } } base.RawInts()[1] = 99 if got := out.RawInts()[0]; got != 2 { t.Fatalf("copy aliases the base: %d", got) } } // TestSliceOfViewStaysCorrect pins that slicing a view materialises the // source first, so the copy path never reads the wrong payload slots. func TestSliceOfViewStaysCorrect(t *testing.T) { base, err := FromInts([]int64{1, 2, 3, 4, 5, 6}, 3, 2) if err != nil { t.Fatal(err) } view, err := Slice(base, 0, 1, 3) // rows 1..2, a view if err != nil { t.Fatal(err) } inner, err := Slice(view, 1, 0, 1) // first column of the view if err != nil { t.Fatal(err) } want := []int64{3, 5} for i, w := range want { if got := inner.RawInts()[i]; got != w { t.Errorf("slice of view[%d] = %d, want %d", i, got, w) } } }