Skip to main content

cubecl_core/frontend/container/tensor/
base.rs

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