## Coverage Report

#### Created: 2026-01-25 15:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)

    /home/noah/src/realizar/src/tensor.rs

    Line
    Count
    Source
    1
    //! Tensor implementation
    2
    //!
    3
    //! This module provides the core `Tensor` type, which is an N-dimensional array
    4
    //! with automatic backend selection for optimal performance.
    5
    6
    use std::fmt;
    7
    8
    use num_traits::Num;
    9
    use serde::{Deserialize, Serialize};
    10
    11
    use crate::error::{RealizarError, Result};
    12
    13
    /// N-dimensional tensor with automatic backend dispatch
    14
    ///
    15
    /// The tensor automatically selects the optimal execution backend (SIMD, GPU, WASM)
    16
    /// based on operation type, data size, and available hardware.
    17
    ///
    18
    /// # Examples
    19
    ///
    20
    /// ```
    21
    /// use realizar::Tensor;
    22
    ///
    23
    /// // Create a 2×3 tensor
    24
    /// let t = Tensor::from_vec(vec![2, 3], vec![
    25
    ///     1.0, 2.0, 3.0,
    26
    ///     4.0, 5.0, 6.0,
    27
    /// ]).expect("test");
    28
    ///
    29
    /// assert_eq!(t.shape(), &[2, 3]);
    30
    /// assert_eq!(t.ndim(), 2);
    31
    /// assert_eq!(t.size(), 6);
    32
    /// ```
    33
    #[derive(Debug, Clone, Serialize, Deserialize)]
    34
    pub struct Tensor<T: Num> {
    35
        /// Flattened data in row-major order
    36
        data: Vec<T>,
    37
        /// Shape of the tensor
    38
        shape: Vec<usize>,
    39
    }
    40
    41
    impl<T: Num + Clone> Tensor<T> {
    42
        /// Create a new tensor from a vector and shape
    43
        ///
    44
        /// # Arguments
    45
        ///
    46
        /// * `shape` - Dimensions of the tensor
    47
        /// * `data` - Flattened data in row-major order
    48
        ///
    49
        /// # Errors
    50
        ///
    51
        /// Returns `Err` if:
    52
        /// - Shape is empty
    53
        /// - Data size doesn't match shape
    54
        /// - Shape contains zero
    55
        ///
    56
        /// # Examples
    57
        ///
    58
        /// ```
    59
        /// use realizar::Tensor;
    60
        ///
    61
        /// let t = Tensor::from_vec(vec![2, 2], vec![1.0, 2.0, 3.0, 4.0]).expect("test");
    62
        /// assert_eq!(t.shape(), &[2, 2]);
    63
        /// ```
    64
    47.9k
        pub fn from_vec(shape: Vec<usize>, data: Vec<T>) -> Result<Self> {
    65
            // Validate shape
    66
    47.9k
            if shape.is_empty() {
    67
    6
                return Err(RealizarError::InvalidShape {
    68
    6
                    reason: "Shape cannot be empty".to_string(),
    69
    6
                });
    70
    47.9k
            }
    71
    72
    47.9k
            if shape.contains(&0) {
    73
    4
                return Err(RealizarError::InvalidShape {
    74
    4
                    reason: "Shape dimensions cannot be zero".to_string(),
    75
    4
                });
    76
    47.9k
            }
    77
    78
            // Calculate expected size
    79
    47.9k
            let expected_size = shape.iter().product();
    80
    81
            // Validate data size
    82
    47.9k
            if data.len() != expected_size {
    83
    2
                return Err(RealizarError::DataShapeMismatch {
    84
    2
                    data_size: data.len(),
    85
    2
                    shape,
    86
    2
                    expected: expected_size,
    87
    2
                });
    88
    47.9k
            }
    89
    90
    47.9k
            Ok(Self { data, shape })
    91
    47.9k
        }
    92
    93
        /// Get the shape of the tensor
    94
        ///
    95
        /// # Examples
    96
        ///
    97
        /// ```
    98
        /// use realizar::Tensor;
    99
        ///
    100
        /// let t = Tensor::from_vec(vec![3, 4], vec![0.0; 12]).expect("test");
    101
        /// assert_eq!(t.shape(), &[3, 4]);
    102
        /// ```
    103
        #[must_use]
    104
    36.8k
        pub fn shape(&self) -> &[usize] {
    105
    36.8k
            &self.shape
    106
    36.8k
        }
    107
    108
        /// Get the number of dimensions
    109
        ///
    110
        /// # Examples
    111
        ///
    112
        /// ```
    113
        /// use realizar::Tensor;
    114
        ///
    115
        /// let t = Tensor::from_vec(vec![2, 3, 4], vec![0.0; 24]).expect("test");
    116
        /// assert_eq!(t.ndim(), 3);
    117
        /// ```
    118
        #[must_use]
    119
    1
        pub fn ndim(&self) -> usize {
    120
    1
            self.shape.len()
    121
    1
        }
    122
    123
        /// Get the total number of elements
    124
        ///
    125
        /// # Examples
    126
        ///
    127
        /// ```
    128
        /// use realizar::Tensor;
    129
        ///
    130
        /// let t = Tensor::from_vec(vec![2, 3], vec![0.0; 6]).expect("test");
    131
        /// assert_eq!(t.size(), 6);
    132
        /// ```
    133
        #[must_use]
    134
    1.21k
        pub fn size(&self) -> usize {
    135
    1.21k
            self.data.len()
    136
    1.21k
        }
    137
    138
        /// Get a reference to the underlying data
    139
        ///
    140
        /// # Examples
    141
        ///
    142
        /// ```
    143
        /// use realizar::Tensor;
    144
        ///
    145
        /// let t = Tensor::from_vec(vec![2], vec![1.0, 2.0]).expect("test");
    146
        /// assert_eq!(t.data(), &[1.0, 2.0]);
    147
        /// ```
    148
        #[must_use]
    149
    7.63M
        pub fn data(&self) -> &[T] {
    150
    7.63M
            &self.data
    151
    7.63M
        }
    152
    }
    153
    154
    impl<T: Num + Clone + fmt::Display> fmt::Display for Tensor<T> {
    155
    1
        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
    156
    1
            write!(f, "Tensor(shape={:?}, data=[", self.shape)?0;
    157
    2
            for (i, val) in self.data.iter()1.enumerate1() {
    158
    2
                if i > 0 {
    159
    1
                    write!(f, ", ")?0;
    160
    1
                }
    161
    2
                write!(f, "{val}")?0;
    162
            }
    163
    1
            write!(f, "])")
    164
    1
        }
    165
    }
    166
    167
    #[cfg(test)]
    168
    mod tests {
    169
        use super::*;
    170
    171
        #[test]
    172
    1
        fn test_create_tensor() {
    173
    1
            let t = Tensor::from_vec(vec![2, 3], vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0]).expect("test");
    174
    1
            assert_eq!(t.shape(), &[2, 3]);
    175
    1
            assert_eq!(t.ndim(), 2);
    176
    1
            assert_eq!(t.size(), 6);
    177
    1
        }
    178
    179
        #[test]
    180
    1
        fn test_empty_shape_error() {
    181
    1
            let result = Tensor::from_vec(vec![], vec![1.0, 2.0]);
    182
    1
            assert!(result.is_err());
    183
    1
            assert!(matches!0(
    184
    1
                result.unwrap_err(),
    185
                RealizarError::InvalidShape { .. }
    186
            ));
    187
    1
        }
    188
    189
        #[test]
    190
    1
        fn test_zero_dimension_error() {
    191
    1
            let result = Tensor::<f32>::from_vec(vec![2, 0], vec![]);
    192
    1
            assert!(result.is_err());
    193
    1
        }
    194
    195
        #[test]
    196
    1
        fn test_size_mismatch_error() {
    197
    1
            let result = Tensor::from_vec(vec![2, 3], vec![1.0, 2.0]);
    198
    1
            assert!(result.is_err());
    199
    1
            assert!(matches!0(
    200
    1
                result.unwrap_err(),
    201
                RealizarError::DataShapeMismatch { .. }
    202
            ));
    203
    1
        }
    204
    205
        #[test]
    206
    1
        fn test_display() {
    207
    1
            let t = Tensor::from_vec(vec![2], vec![1.0, 2.0]).expect("test");
    208
    1
            let display = format!("{t}");
    209
    1
            assert!(display.contains("shape=[2]"));
    210
    1
            assert!(display.contains('1'));
    211
    1
            assert!(display.contains('2'));
    212
    1
        }
    213
    }