Skip to main content

burn_std/data/tensor/
view.rs

1use core::ops::{Index, IndexMut};
2
3use crate::Shape;
4use crate::element::Element;
5use crate::indexing::AsIndex;
6use crate::tensor::{DType, ravel_index};
7
8use super::{DataError, TensorData};
9
10impl TensorData {
11    /// Returns an [`Index`] view wrapper of the [`TensorData`].
12    ///
13    /// # Example
14    /// ```rust,no_run
15    /// use burn_std::*;
16    ///
17    /// let data = TensorData::from([[1.0, 2.0], [3.0, 4.0]]);
18    /// let shape = data.shape.clone();
19    /// let view: TensorDataView<f64> = data.try_view().unwrap();
20    ///
21    /// assert_eq!(view[&[0, 0]], 1.0);
22    /// assert_eq!(view[&[0, 1]], 2.0);
23    /// assert_eq!(view[&[1, 0]], 3.0);
24    /// assert_eq!(view[&[1, 1]], 4.0);
25    /// ```
26    ///
27    /// # Errors
28    ///
29    /// Returns an error if storage access fails or the dtype, byte representation, or element
30    /// count is incompatible with the requested view.
31    pub fn try_view<E: Element>(&self) -> Result<TensorDataView<'_, E>, DataError> {
32        TensorDataView::<E>::try_view(self)
33    }
34
35    /// Returns a [`TensorDataView<E>`] of the [`TensorData`].
36    ///
37    /// # Example
38    /// ```rust,no_run
39    /// use burn_std::*;
40    ///
41    /// let data = TensorData::from([[1.0, 2.0], [3.0, 4.0]]);
42    /// let shape = data.shape.clone();
43    /// let view: TensorDataView<f64> = data.view();
44    ///
45    /// assert_eq!(view[&[0, 0]], 1.0);
46    /// assert_eq!(view[&[0, 1]], 2.0);
47    /// assert_eq!(view[&[1, 0]], 3.0);
48    /// assert_eq!(view[&[1, 1]], 4.0);
49    /// ```
50    ///
51    /// # Returns
52    /// The view.
53    ///
54    /// # Panics
55    ///
56    /// Panics if the view can't be created because storage access fails or the dtype, byte
57    /// representation, or element count is incompatible with `E`.
58    #[track_caller]
59    pub fn view<E: Element>(&self) -> TensorDataView<'_, E> {
60        self.try_view()
61            .unwrap_or_else(|err| panic!("Failed to create TensorData view: {err}"))
62    }
63
64    /// Returns a [`TensorDataViewMut<E>`] of the [`TensorData`].
65    ///
66    /// # Example
67    /// ```rust,no_run
68    /// use burn_std::*;
69    ///
70    /// let mut data = TensorData::from([[1.0, 2.0], [3.0, 4.0]]);
71    /// let shape = data.shape.clone();
72    /// let mut view: TensorDataViewMut<f64> = data.try_mut_view().unwrap();
73    ///
74    /// assert_eq!(view[&[0, 0]], 1.0);
75    /// assert_eq!(view[&[0, 1]], 2.0);
76    /// assert_eq!(view[&[1, 0]], 3.0);
77    /// assert_eq!(view[&[1, 1]], 4.0);
78    ///
79    /// view[&[0, 0]] = 10.0;
80    /// assert_eq!(view[&[0, 0]], 10.0);
81    /// ```
82    ///
83    /// # Errors
84    ///
85    /// Returns an error if storage access fails or the dtype, byte representation, or element
86    /// count is incompatible with the requested view.
87    pub fn try_mut_view<E: Element>(&mut self) -> Result<TensorDataViewMut<'_, E>, DataError> {
88        TensorDataViewMut::<E>::try_mut_view(self)
89    }
90
91    /// Returns a [`TensorDataViewMut<E>`] of the [`TensorData`].
92    ///
93    /// # Example
94    /// ```rust,no_run
95    /// use burn_std::*;
96    ///
97    /// let mut data = TensorData::from([[1.0, 2.0], [3.0, 4.0]]);
98    /// let shape = data.shape.clone();
99    /// let mut view: TensorDataViewMut<f64> = data.mut_view();
100    ///
101    /// assert_eq!(view[&[0, 0]], 1.0);
102    /// assert_eq!(view[&[0, 1]], 2.0);
103    /// assert_eq!(view[&[1, 0]], 3.0);
104    /// assert_eq!(view[&[1, 1]], 4.0);
105    ///
106    /// view[&[0, 0]] = 10.0;
107    /// assert_eq!(view[&[0, 0]], 10.0);
108    /// ```
109    ///
110    /// # Returns
111    /// The mut view.
112    ///
113    /// # Panics
114    ///
115    /// Panics if the view can't be created because storage access fails or the dtype, byte
116    /// representation, or element count is incompatible with `E`.
117    #[track_caller]
118    pub fn mut_view<E: Element>(&mut self) -> TensorDataViewMut<'_, E> {
119        self.try_mut_view()
120            .unwrap_or_else(|err| panic!("Failed to create mutable TensorData view: {err}"))
121    }
122}
123
124/// Typed [`Index`] view over a [`TensorData`].
125///
126/// Creating a view materializes lazy storage into host-accessible memory when necessary. It does
127/// not perform dtype conversion.
128///
129/// # Example
130/// ```rust,no_run
131/// use burn_std::*;
132///
133/// let data = TensorData::from([[1.0, 2.0], [3.0, 4.0]]);
134/// let view: TensorDataView<f64> = data.view();
135///
136/// assert_eq!(view.shape(), &data.shape);
137/// assert_eq!(&view.dtype(), &data.dtype);
138///
139/// assert_eq!(view[&[0, 0]], 1.0);
140/// assert_eq!(view[&[0, 1]], 2.0);
141/// assert_eq!(view[&[1, 0]], 3.0);
142/// assert_eq!(view[&[1, 1]], 4.0);
143/// ```
144#[derive(Debug)]
145pub struct TensorDataView<'a, E: Element> {
146    values: &'a [E],
147    shape: &'a Shape,
148    dtype: DType,
149}
150
151impl<'a, E: Element> TensorDataView<'a, E> {
152    /// Creates a typed indexed view over `data`.
153    ///
154    /// # Example
155    /// ```rust,no_run
156    /// use burn_std::*;
157    ///
158    /// let data = TensorData::from([[1.0, 2.0], [3.0, 4.0]]);
159    /// let view: TensorDataView<f64> = data.try_view().unwrap();
160    ///
161    /// assert_eq!(view.shape(), &data.shape);
162    /// assert_eq!(&view.dtype(), &data.dtype);
163    ///
164    /// assert_eq!(view[&[0, 0]], 1.0);
165    /// assert_eq!(view[&[0, 1]], 2.0);
166    /// assert_eq!(view[&[1, 0]], 3.0);
167    /// assert_eq!(view[&[1, 1]], 4.0);
168    /// ```
169    ///
170    /// # Errors
171    ///
172    /// Returns an error if storage access fails or the dtype, byte representation, or element
173    /// count is incompatible with `E`.
174    pub fn try_view(data: &'a TensorData) -> Result<TensorDataView<'a, E>, DataError> {
175        let shape = &data.shape;
176        let dtype = data.dtype;
177        let expected = shape.num_elements();
178        let values = data.as_slice::<E>()?;
179        let actual = values.len();
180
181        if actual != expected {
182            return Err(DataError::ElementCountMismatch { expected, actual });
183        }
184
185        Ok(TensorDataView {
186            values,
187            shape,
188            dtype,
189        })
190    }
191
192    /// Returns the shape of the view.
193    pub fn shape(&self) -> &Shape {
194        self.shape
195    }
196
197    /// Returns the dtype of the view.
198    pub fn dtype(&self) -> DType {
199        self.dtype
200    }
201
202    /// Ravels the index via [`ravel_index`] and the view's shape.
203    pub fn ravel_index<I: AsIndex>(&self, index: &[I]) -> usize {
204        ravel_index(index, self.shape)
205    }
206}
207
208impl<'a, I: AsIndex, E: Element> Index<&[I]> for TensorDataView<'a, E> {
209    type Output = E;
210
211    fn index(&self, index: &[I]) -> &Self::Output {
212        let o = self.ravel_index(index);
213        &self.values[o]
214    }
215}
216
217/// Typed mutable [`IndexMut`] view over a [`TensorData`].
218///
219/// Creating a mutable view materializes lazy storage and performs copy-on-write when necessary.
220/// It does not perform dtype conversion.
221///
222/// # Example
223/// ```rust,no_run
224/// use burn_std::*;
225///
226/// let mut data = TensorData::from([[1.0, 2.0], [3.0, 4.0]]);
227/// let shape = data.shape.clone();
228/// let dtype = data.dtype;
229/// let mut view: TensorDataViewMut<f64> = data.mut_view();
230///
231/// assert_eq!(view.shape(), &shape);
232/// assert_eq!(&view.dtype(), &dtype);
233///
234/// assert_eq!(view[&[0, 0]], 1.0);
235/// assert_eq!(view[&[0, 1]], 2.0);
236/// assert_eq!(view[&[1, 0]], 3.0);
237/// assert_eq!(view[&[1, 1]], 4.0);
238///
239/// view[&[0, 0]] = 10.0;
240/// assert_eq!(view[&[0, 0]], 10.0);
241/// ```
242#[derive(Debug)]
243pub struct TensorDataViewMut<'a, E: Element> {
244    values: &'a mut [E],
245    // `as_mut_slice` borrows the entire `TensorData`, so the view can't also retain a reference to
246    // its shape. Keep an owned copy until storage and metadata can be borrowed as disjoint fields.
247    shape: Shape,
248    dtype: DType,
249}
250
251impl<'a, E: Element> TensorDataViewMut<'a, E> {
252    /// Creates a typed mutable indexed view over `data`.
253    ///
254    /// # Example
255    /// ```rust,no_run
256    /// use burn_std::*;
257    ///
258    /// let mut data = TensorData::from([[1.0, 2.0], [3.0, 4.0]]);
259    /// let shape = data.shape.clone();
260    /// let dtype = data.dtype;
261    ///
262    /// let mut view: TensorDataViewMut<f64> =
263    ///     TensorDataViewMut::try_mut_view(&mut data).unwrap();
264    ///
265    /// assert_eq!(view.shape(), &shape);
266    /// assert_eq!(&view.dtype(), &dtype);
267    ///
268    /// assert_eq!(view[&[0, 0]], 1.0);
269    /// assert_eq!(view[&[0, 1]], 2.0);
270    /// assert_eq!(view[&[1, 0]], 3.0);
271    /// assert_eq!(view[&[1, 1]], 4.0);
272    ///
273    /// view[&[0, 0]] = 10.0;
274    /// assert_eq!(view[&[0, 0]], 10.0);
275    /// ```
276    ///
277    /// # Errors
278    ///
279    /// Returns an error if storage access fails or the dtype, byte representation, or element
280    /// count is incompatible with `E`.
281    pub fn try_mut_view(data: &'a mut TensorData) -> Result<TensorDataViewMut<'a, E>, DataError> {
282        let shape = data.shape.clone();
283        let dtype = data.dtype;
284        let expected = shape.num_elements();
285        let values = data.as_mut_slice::<E>()?;
286        let actual = values.len();
287
288        if actual != expected {
289            return Err(DataError::ElementCountMismatch { expected, actual });
290        }
291
292        Ok(TensorDataViewMut {
293            values,
294            shape,
295            dtype,
296        })
297    }
298
299    /// Returns the shape of the view.
300    pub fn shape(&self) -> &Shape {
301        &self.shape
302    }
303
304    /// Returns the dtype of the view.
305    pub fn dtype(&self) -> DType {
306        self.dtype
307    }
308
309    /// Ravels the dims via [`ravel_index`] and the view's shape.
310    pub fn ravel_index<I: AsIndex>(&self, index: &[I]) -> usize {
311        ravel_index(index, &self.shape)
312    }
313}
314
315impl<'a, I, E> Index<&[I]> for TensorDataViewMut<'a, E>
316where
317    I: AsIndex,
318    E: Element,
319{
320    type Output = E;
321
322    fn index(&self, index: &[I]) -> &Self::Output {
323        let o = self.ravel_index::<I>(index);
324        &self.values[o]
325    }
326}
327
328impl<'a, I, E> IndexMut<&[I]> for TensorDataViewMut<'a, E>
329where
330    I: AsIndex,
331    E: Element,
332{
333    fn index_mut(&mut self, index: &[I]) -> &mut Self::Output {
334        let o = self.ravel_index::<I>(index);
335        &mut self.values[o]
336    }
337}