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}