Skip to main content

cubecl_core/frontend/container/tensor/
base.rs

1use crate::{ir::Scope, prelude::*, unexpanded};
2use alloc::boxed::Box;
3use core::ops::{Deref, DerefMut};
4use cubecl_ir::VectorSize;
5
6use crate as cubecl;
7
8/// The tensor type is a wrapper around `[T]` that comes with more
9/// metadata such as [stride](Tensor::stride) and [shape](Tensor::shape).
10#[derive(CubeType)]
11pub struct Tensor<T: CubePrimitive> {
12    pub(super) meta: TensorMeta,
13    pub(super) buffer: [T],
14}
15
16#[derive(CubeType, Clone)]
17#[expand(derive(Clone))]
18pub struct OwnedTensor<T: CubePrimitive> {
19    #[allow(unused)]
20    pub(super) meta: TensorMeta,
21    pub(super) buffer: Box<[T]>,
22}
23
24impl<T: CubePrimitive> TensorExpand<T> {
25    /// Expand only because `[T]` can't be passed to a function
26    pub fn __expand_from_parts(meta: TensorMetaExpand, buffer: NativeExpand<[T]>) -> Self {
27        Self { meta, buffer }
28    }
29}
30
31#[cube]
32impl<T: CubePrimitive> OwnedTensor<T> {
33    pub fn from_parts(meta: TensorMeta, buffer: Box<[T]>) -> Self {
34        OwnedTensor::<T> { meta, buffer }
35    }
36}
37
38#[cube]
39impl<T: CubePrimitive> OwnedTensor<T> {
40    pub fn as_slice(&self) -> &[T] {
41        &self.buffer
42    }
43
44    pub fn as_mut_slice(&mut self) -> &mut [T] {
45        &mut self.buffer
46    }
47}
48
49#[cube]
50impl<T: CubePrimitive> Tensor<T> {
51    pub fn as_slice(&self) -> &[T] {
52        &self.buffer
53    }
54
55    pub fn as_mut_slice(&mut self) -> &mut [T] {
56        &mut self.buffer
57    }
58}
59
60/// Module that contains the implementation details of the metadata functions.
61mod metadata {
62    use cubecl_ir::dialect::general::{ShapeOp, StrideOp};
63
64    use super::*;
65
66    #[cube]
67    impl<T: CubePrimitive> Tensor<T> {
68        /// Obtain the stride of input at dimension dim
69        pub fn stride(&self, dim: usize) -> usize {
70            intrinsic!(|scope| {
71                let dim = dim.read_value(scope);
72                let buffer_idx = ext_meta_idx(scope, self.__extract_list(scope));
73                let op = StrideOp::new(scope.ctx_mut(), dim, buffer_idx);
74                scope.register_with_result(&op).into()
75            })
76        }
77
78        /// Obtain the shape of input at dimension dim
79        pub fn shape(&self, dim: usize) -> usize {
80            intrinsic!(|scope| {
81                let dim = dim.read_value(scope);
82                let buffer_idx = ext_meta_idx(scope, self.__extract_list(scope));
83                let op = ShapeOp::new(scope.ctx_mut(), dim, buffer_idx);
84                scope.register_with_result(&op).into()
85            })
86        }
87
88        /// Obtain the coordinate corresponding to the given `index` of the tensor at dimension `dim`.
89        ///
90        /// A coordinate is a list of indices corresponding to the multi-dimensional position of an element in the tensor.
91        /// The `dim` element in a coordinate is the position along the `dim` dimension of the tensor.
92        pub fn coordinate(&self, index: usize, dim: usize) -> usize {
93            let stride = self.stride(dim);
94            let shape = self.shape(dim);
95            (index / stride) % shape
96        }
97
98        /// The number of vectorized elements in the tensor.
99        ///
100        /// # Warning
101        ///
102        /// The length will be affected by the vectorization factor. To obtain the number of elements,
103        /// you should multiply the length by the vectorization factor.
104        #[allow(clippy::len_without_is_empty)]
105        pub fn len(&self) -> usize {
106            self.meta.len
107        }
108
109        /// The length of the buffer representing the tensor in terms of vectorized elements.
110        ///
111        /// # Warning
112        ///
113        /// The buffer length will be affected by the vectorization factor. To obtain the number of
114        /// elements, you should multiply the length by the vectorization factor.
115        #[allow(clippy::len_without_is_empty)]
116        pub fn buffer_len(&self) -> usize {
117            intrinsic!(|scope| { self.__extract_length(scope) })
118        }
119
120        /// Returns the rank of the tensor.
121        pub fn rank(&self) -> usize {
122            self.meta.rank
123        }
124    }
125}
126
127/// Module that contains the implementation details of the `vector_size` function.
128mod vector {
129    use super::*;
130
131    impl<P: Scalar, N: Size> Tensor<Vector<P, N>> {
132        /// Get the size of each vector contained in the tensor.
133        ///
134        /// Same as the following:
135        ///
136        /// ```rust, ignore
137        /// let size = tensor[0].size();
138        /// ```
139        pub fn vector_size(&self) -> VectorSize {
140            N::value()
141        }
142
143        // Expand function of [size](Tensor::vector_size).
144        pub fn __expand_vector_size(
145            expand: <Self as CubeType>::ExpandType,
146            scope: &Scope,
147        ) -> VectorSize {
148            expand.__expand_vector_size_method(scope)
149        }
150    }
151}
152
153impl<'a, E: CubePrimitive> From<&'a OwnedTensorExpand<E>> for &'a TensorExpand<E> {
154    fn from(value: &'a OwnedTensorExpand<E>) -> Self {
155        value.deref()
156    }
157}
158
159impl<'a, E: CubePrimitive> From<&'a mut OwnedTensorExpand<E>> for &'a mut TensorExpand<E> {
160    fn from(value: &'a mut OwnedTensorExpand<E>) -> Self {
161        value.deref_mut()
162    }
163}
164
165impl<'a, E: CubePrimitive> From<&'a TensorExpand<E>> for &'a SliceExpand<E> {
166    fn from(value: &'a TensorExpand<E>) -> Self {
167        value.deref()
168    }
169}
170
171impl<'a, E: CubePrimitive> From<&'a mut TensorExpand<E>> for &'a mut SliceExpand<E> {
172    fn from(value: &'a mut TensorExpand<E>) -> Self {
173        value.deref_mut()
174    }
175}
176
177impl<T: CubePrimitive> SizedContainer<usize> for Tensor<T> {
178    fn len(&self) -> usize {
179        unexpanded!()
180    }
181}
182
183impl<T: CubePrimitive> SizedContainerExpand<usize> for TensorExpand<T> {
184    fn __expand_len_method(&self, scope: &Scope) -> NativeExpand<usize> {
185        self.__expand_len_method(scope)
186    }
187}
188
189impl<T: CubePrimitive> Iterator for &Tensor<T> {
190    type Item = T;
191
192    fn next(&mut self) -> Option<Self::Item> {
193        unexpanded!()
194    }
195}
196
197impl<T: CubePrimitive> List<T> for Tensor<T> {}
198
199impl<T: CubePrimitive> Deref for Tensor<T> {
200    type Target = [T];
201
202    fn deref(&self) -> &Self::Target {
203        unexpanded!()
204    }
205}
206
207impl<T: CubePrimitive> DerefMut for Tensor<T> {
208    fn deref_mut(&mut self) -> &mut Self::Target {
209        unexpanded!()
210    }
211}
212
213impl<T: CubePrimitive> Deref for TensorExpand<T> {
214    type Target = SliceExpand<T>;
215
216    fn deref(&self) -> &Self::Target {
217        &self.buffer
218    }
219}
220
221impl<T: CubePrimitive> DerefMut for TensorExpand<T> {
222    fn deref_mut(&mut self) -> &mut Self::Target {
223        &mut self.buffer
224    }
225}
226
227impl<T: CubePrimitive> Deref for OwnedTensor<T> {
228    type Target = Tensor<T>;
229
230    fn deref(&self) -> &Self::Target {
231        unexpanded!()
232    }
233}
234
235impl<T: CubePrimitive> DerefMut for OwnedTensor<T> {
236    fn deref_mut(&mut self) -> &mut Self::Target {
237        unexpanded!()
238    }
239}
240
241impl<T: CubePrimitive> Deref for OwnedTensorExpand<T> {
242    type Target = TensorExpand<T>;
243
244    fn deref(&self) -> &Self::Target {
245        // SAFETY: Expand type has compatible layout since the type of the buffer is just a marker
246        unsafe { core::mem::transmute(self) }
247    }
248}
249
250impl<T: CubePrimitive> DerefMut for OwnedTensorExpand<T> {
251    fn deref_mut(&mut self) -> &mut Self::Target {
252        // SAFETY: Expand type has compatible layout since the type of the buffer is just a marker
253        unsafe { core::mem::transmute(self) }
254    }
255}
256
257impl<T: CubePrimitive> ListExpand<T> for TensorExpand<T> {
258    fn __expand_len_method(&self, scope: &Scope) -> NativeExpand<usize> {
259        Self::__expand_len_method(self, scope)
260    }
261}
262
263impl<T: CubePrimitive> Vectorized for Tensor<T> {}
264impl<T: CubePrimitive> VectorizedExpand for TensorExpand<T> {
265    fn __expand_vector_size_method(&self, scope: &Scope) -> VectorSize {
266        self.buffer.__expand_vector_size_method(scope)
267    }
268}