hermes_simd_core/tensor/mod.rs
1//! Zero-copy, const-generic N-dimensional strided tensor view.
2//!
3//! # Design
4//!
5//! `TensorView<'a, T, const N: usize>` is a rank-`N` view over a borrowed slice.
6//! Shape and strides are `[usize; N]` arrays resolved at compile time — the const
7//! generic `N` is erased after monomorphization, leaving no runtime overhead vs.
8//! a hand-written 2-D or 3-D struct.
9//!
10//! # Layout Markers
11//!
12//! Two zero-sized layout markers tag contiguous storage assumptions:
13//! - [`RowMajor`] — row-major (C-order) storage; `strides[i] = ∏_{j>i} shape[j]`.
14//! - [`ColMajor`] — column-major (Fortran-order) storage.
15//!
16//! # Zero-Copy Contract
17//!
18//! - `new(data, shape)` — zero allocation; computes row-major strides from shape.
19//! - `with_strides(data, shape, strides)` — zero allocation; caller supplies strides.
20//! - `row_view(i)` — returns a `TensorView<'_, T, {N-1}>` sharing the same slice.
21//! - `reshape(new_shape)` — returns a new view if the layout is contiguous; no copy.
22//! - All `get` / `iter_rows` operations are also zero-copy.
23//!
24//! # Module Structure
25//!
26//! | Leaf module | Contents |
27//! |-------------------|------------------------------------------------------|
28//! | [`layout`] | `RowMajor`, `ColMajor` ZSTs; sealed `Layout` trait |
29//! | [`error`] | `TensorError` enum |
30//! | [`view`] | `TensorView` core + `rank_ops`/`simd_bridge` leaves |
31//! | [`cow`] | `TensorCow` enum + all impl blocks |
32//! | `helpers` (priv) | `row_major_strides`, `compute_offset` |
33
34pub mod cow;
35pub mod error;
36mod helpers;
37pub mod layout;
38pub mod view;
39
40pub use cow::TensorCow;
41pub use error::TensorError;
42pub use layout::{ColMajor, Layout, RowMajor};
43pub use view::TensorView;
44
45#[cfg(test)]
46mod tests {
47 use super::*;
48 use helpers::row_major_strides;
49
50 #[test]
51 fn test_row_major_strides_3d() {
52 let s = row_major_strides([2usize, 3, 4]);
53 assert_eq!(s, [12, 4, 1]);
54 }
55
56 #[test]
57 fn test_tensor_view_get_2d() {
58 let data: Vec<i32> = (0..12).collect();
59 let t = TensorView::<i32, 2>::new(&data, [3, 4]).unwrap();
60 assert_eq!(t.get([1, 2]).unwrap(), 6);
61 }
62
63 #[test]
64 fn test_reshape() {
65 let data: Vec<i32> = (0..12).collect();
66 let t2d = TensorView::<i32, 2>::new(&data, [3, 4]).unwrap();
67 let t1d = t2d.reshape([12]).unwrap();
68 assert_eq!(t1d.num_elements(), 12);
69 assert_eq!(t1d.get([11]).unwrap(), 11);
70 }
71
72 #[test]
73 fn test_row_view() {
74 let data: Vec<f32> = (0..9).map(|x| x as f32).collect();
75 let t = TensorView::<f32, 2>::new(&data, [3, 3]).unwrap();
76 let row1 = t.row_view(1).unwrap();
77 assert_eq!(row1.num_elements(), 3);
78 assert_eq!(row1.get([0]).unwrap(), 3.0);
79 assert_eq!(row1.get([2]).unwrap(), 5.0);
80 }
81}