Skip to main content

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;
36pub mod layout;
37mod strides;
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 strides::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}