Skip to main content

tropical_gemm/mat/
mut_.rs

1//! Mutable matrix reference type.
2
3use crate::types::TropicalSemiring;
4
5/// Mutable view over semiring data.
6///
7/// Unlike `MatRef`, this holds mutable references to semiring values,
8/// not scalars. This is used for in-place operations.
9#[derive(Debug)]
10pub struct MatMut<'a, S: TropicalSemiring> {
11    data: &'a mut [S],
12    nrows: usize,
13    ncols: usize,
14}
15
16impl<'a, S: TropicalSemiring> MatMut<'a, S> {
17    /// Create a mutable matrix reference from a slice.
18    pub fn from_slice(data: &'a mut [S], nrows: usize, ncols: usize) -> Self {
19        assert_eq!(
20            data.len(),
21            nrows
22                .checked_mul(ncols)
23                .expect("matrix dimensions overflow"),
24            "data length {} != nrows {} * ncols {}",
25            data.len(),
26            nrows,
27            ncols
28        );
29        Self { data, nrows, ncols }
30    }
31
32    /// Number of rows.
33    #[inline]
34    pub fn nrows(&self) -> usize {
35        self.nrows
36    }
37
38    /// Number of columns.
39    #[inline]
40    pub fn ncols(&self) -> usize {
41        self.ncols
42    }
43
44    /// Get the underlying data as a mutable slice.
45    #[inline]
46    pub fn as_mut_slice(&mut self) -> &mut [S] {
47        self.data
48    }
49
50    /// Get a mutable pointer to the data.
51    #[inline]
52    pub fn as_mut_ptr(&mut self) -> *mut S {
53        self.data.as_mut_ptr()
54    }
55
56    /// Get a reference to the value at position (i, j).
57    #[inline]
58    pub fn get(&self, i: usize, j: usize) -> &S {
59        debug_assert!(
60            i < self.nrows,
61            "row index {} out of bounds {}",
62            i,
63            self.nrows
64        );
65        debug_assert!(
66            j < self.ncols,
67            "col index {} out of bounds {}",
68            j,
69            self.ncols
70        );
71        // Column-major indexing
72        &self.data[j * self.nrows + i]
73    }
74
75    /// Get a mutable reference to the value at position (i, j).
76    #[inline]
77    pub fn get_mut(&mut self, i: usize, j: usize) -> &mut S {
78        debug_assert!(
79            i < self.nrows,
80            "row index {} out of bounds {}",
81            i,
82            self.nrows
83        );
84        debug_assert!(
85            j < self.ncols,
86            "col index {} out of bounds {}",
87            j,
88            self.ncols
89        );
90        // Column-major indexing
91        &mut self.data[j * self.nrows + i]
92    }
93}
94
95#[cfg(test)]
96mod tests {
97    use super::*;
98    use crate::TropicalMaxPlus;
99
100    #[test]
101    fn test_matmut_from_slice() {
102        let mut data = vec![
103            TropicalMaxPlus(1.0f64),
104            TropicalMaxPlus(2.0),
105            TropicalMaxPlus(3.0),
106            TropicalMaxPlus(4.0),
107        ];
108        let m = MatMut::from_slice(&mut data, 2, 2);
109        assert_eq!(m.nrows(), 2);
110        assert_eq!(m.ncols(), 2);
111    }
112
113    #[test]
114    fn test_matmut_get() {
115        // Column-major: data stored column-by-column
116        // For 2×2 matrix [[1,2],[3,4]], col-major is [1,3,2,4]
117        let mut data = vec![
118            TropicalMaxPlus(1.0f64),
119            TropicalMaxPlus(3.0),
120            TropicalMaxPlus(2.0),
121            TropicalMaxPlus(4.0),
122        ];
123        let m = MatMut::from_slice(&mut data, 2, 2);
124        assert_eq!(m.get(0, 0).0, 1.0);
125        assert_eq!(m.get(0, 1).0, 2.0);
126        assert_eq!(m.get(1, 0).0, 3.0);
127        assert_eq!(m.get(1, 1).0, 4.0);
128    }
129
130    #[test]
131    fn test_matmut_get_mut() {
132        let mut data = vec![
133            TropicalMaxPlus(1.0f64),
134            TropicalMaxPlus(2.0),
135            TropicalMaxPlus(3.0),
136            TropicalMaxPlus(4.0),
137        ];
138        let mut m = MatMut::from_slice(&mut data, 2, 2);
139        *m.get_mut(0, 0) = TropicalMaxPlus(10.0);
140        assert_eq!(m.get(0, 0).0, 10.0);
141    }
142
143    #[test]
144    fn test_matmut_as_mut_slice() {
145        let mut data = vec![
146            TropicalMaxPlus(1.0f64),
147            TropicalMaxPlus(2.0),
148            TropicalMaxPlus(3.0),
149            TropicalMaxPlus(4.0),
150        ];
151        let mut m = MatMut::from_slice(&mut data, 2, 2);
152        let slice = m.as_mut_slice();
153        slice[0] = TropicalMaxPlus(100.0);
154        assert_eq!(data[0].0, 100.0);
155    }
156
157    #[test]
158    fn test_matmut_as_mut_ptr() {
159        let mut data = vec![
160            TropicalMaxPlus(1.0f64),
161            TropicalMaxPlus(2.0),
162            TropicalMaxPlus(3.0),
163            TropicalMaxPlus(4.0),
164        ];
165        let mut m = MatMut::from_slice(&mut data, 2, 2);
166        let ptr = m.as_mut_ptr();
167        assert!(!ptr.is_null());
168    }
169
170    #[test]
171    fn test_matmut_debug() {
172        let mut data = vec![TropicalMaxPlus(1.0f64), TropicalMaxPlus(2.0)];
173        let m = MatMut::from_slice(&mut data, 1, 2);
174        let debug_str = format!("{:?}", m);
175        assert!(debug_str.contains("MatMut"));
176    }
177
178    #[test]
179    #[should_panic(expected = "data length")]
180    fn test_matmut_size_mismatch() {
181        let mut data = vec![TropicalMaxPlus(1.0f64), TropicalMaxPlus(2.0)];
182        let _ = MatMut::from_slice(&mut data, 2, 2); // Should panic
183    }
184}