rstsr_core/tensor/manuplication/into_dim.rs
1use crate::prelude_dev::*;
2
3/* #region into_dim */
4
5/// Convert layout to the other dimension.
6///
7/// # See also
8///
9/// Refer to [`into_dim`] for more detailed documentation.
10pub fn into_dim_f<S, D, D2>(tensor: TensorBase<S, D>) -> Result<TensorBase<S, D2>>
11where
12 D: DimAPI + DimIntoAPI<D2>,
13 D2: DimAPI,
14{
15 let (storage, layout) = tensor.into_raw_parts();
16 let layout = layout.into_dim::<D2>()?;
17 unsafe { Ok(TensorBase::new_unchecked(storage, layout)) }
18}
19
20/// Convert layout to the other dimension.
21///
22/// This function is intended to be used as associated method [`TensorAny::into_dim`]. We just
23/// provide the API document here.
24///
25/// # Parameters
26///
27/// - `tensor`: [`&TensorAny<R, T, B, D>`](TensorAny)
28///
29/// - The input tensor.
30///
31/// - generic parameter `D2`: [`DimAPI`]
32///
33/// - Target dimension type.
34/// - [`IxD`] or [`IxDyn`] (equilvalent to [`Vec<usize>`]) can be used for dynamic dimension.
35/// - [`Ix<N>`] (given `const N: usize`, equilvalent to [`[usize; N]`](https://doc.rust-lang.org/core/primitive.array.html))
36/// can be used for static dimension.
37/// - Dynamic dimensionality is usually more preferred for general use cases, while static
38/// dimensionality is more suitable for performance-critical code, especially frequent indexing
39/// and non-contiguous memory access.
40///
41/// # Returns
42///
43/// - [`TensorView<'_, T, B, D2>`](TensorView)
44///
45/// - A view of the input tensor with the layout converted to the target dimension type.
46/// - The underlying data is not copied; only the layout of the view is modified.
47/// - If you want to convert the tensor itself (taking the ownership instead of returning view),
48/// use [`into_dim`](TensorAny::into_dim) instead.
49///
50/// # Examples
51///
52/// In most cases, RSTSR will generate dynamic dimension ([`IxD`]) in most cases, including indexing
53/// [`slice`](slice()), reshaping [`reshape`], creation [`asarray`].
54///
55/// You can debug print tensor or it's layout to verify the dimensionality, or call `const_ndim` to
56/// check whether the dimension is static or dynamic.
57///
58/// ```rust
59/// use rstsr::prelude::*;
60/// let a = rt::arange(6).into_shape([2, 3]); // shape: (2, 3), IxD
61/// println!("a: {:?}", a);
62/// // `None` here indicates dynamic dimension
63/// assert_eq!(a.shape().const_ndim(), None);
64/// ```
65///
66/// You can convert the dimension to static dimension by associate method:
67///
68/// ```rust
69/// # use rstsr::prelude::*;
70/// # let a = rt::arange(6).into_shape([2, 3]); // shape: (2, 3), IxD
71/// let b = a.to_dim::<Ix2>(); // shape: (2, 3), Ix2
72/// assert_eq!(b.shape().const_ndim(), Some(2));
73/// ```
74///
75/// You can use `.to_dim::<IxD>()` or `.to_dyn()` to convert back to dynamic dimension:
76///
77/// ```rust
78/// # use rstsr::prelude::*;
79/// # let a = rt::arange(6).into_shape([2, 3]); // shape: (2, 3), IxD
80/// # let b = a.to_dim::<Ix2>(); // shape: (2, 3), Ix2
81/// let c = b.to_dyn(); // shape: (2, 3), IxD
82/// assert_eq!(c.shape().const_ndim(), None);
83/// ```
84///
85/// # Panics
86///
87/// - The shape of the tensor is not compatible with the target dimension type.
88///
89/// ```rust
90/// use rstsr::prelude::*;
91/// let a = rt::arange(6).into_shape([2, 3]); // shape: (2, 3), IxD
92/// let b = a.to_dim::<Ix3>(); // shape: (2, 3), Ix3, panics
93/// ```
94///
95/// # See also
96///
97/// ## Similar functions from other crates/libraries
98///
99/// - ndarray: [`into_dimensionality`](https://docs.rs/ndarray/latest/ndarray/struct.ArrayBase.html#method.into_dimensionality)
100/// - ndarray: [`into_dyn`](https://docs.rs/ndarray/latest/ndarray/struct.ArrayBase.html#method.into_dyn)
101///
102/// ## Variants of this function
103///
104/// - [`to_dim`]: Borrowing version.
105/// - [`to_dim_f`]: Fallible borrowing version.
106/// - [`into_dim`]: Consuming version.
107/// - [`into_dim_f`]: Consuming and fallible version, actual implementation.
108/// - [`to_dyn`]: Convert to dynamic dimension, borrowing version (infallible by definition).
109/// - [`into_dyn`]: Convert to dynamic dimension, consuming version (infallible by definition).
110/// - Associated methods on [`TensorAny`]:
111///
112/// - [`to_dim`]
113/// - [`to_dim_f`]
114/// - [`into_dim`]
115/// - [`into_dim_f`]
116/// - [`to_dyn`]
117/// - [`into_dyn`]
118pub fn to_dim<R, T, B, D, D2>(tensor: &TensorAny<R, T, B, D>) -> TensorView<'_, T, B, D2>
119where
120 D: DimAPI,
121 D2: DimAPI,
122 D: DimIntoAPI<D2>,
123 R: DataAPI<Data = B::Raw>,
124 B: DeviceAPI<T>,
125{
126 into_dim_f(tensor.view()).rstsr_unwrap()
127}
128
129/// Convert layout to the other dimension.
130///
131/// # See also
132///
133/// Refer to [`into_dim`] for more detailed documentation.
134pub fn to_dim_f<R, T, B, D, D2>(tensor: &TensorAny<R, T, B, D>) -> Result<TensorView<'_, T, B, D2>>
135where
136 D: DimAPI,
137 D2: DimAPI,
138 D: DimIntoAPI<D2>,
139 R: DataAPI<Data = B::Raw>,
140 B: DeviceAPI<T>,
141{
142 into_dim_f(tensor.view())
143}
144
145/// Convert layout to the other dimension.
146///
147/// # See also
148///
149/// Refer to [`into_dim`] for more detailed documentation.
150pub fn into_dim<S, D, D2>(tensor: TensorBase<S, D>) -> TensorBase<S, D2>
151where
152 D: DimAPI,
153 D2: DimAPI,
154 D: DimIntoAPI<D2>,
155{
156 into_dim_f(tensor).rstsr_unwrap()
157}
158
159/// Convert layout to the dynamic dimension [`IxD`].
160///
161/// # See also
162///
163/// Refer to [`into_dim`] for more detailed documentation.
164pub fn to_dyn<R, T, B, D>(tensor: &TensorAny<R, T, B, D>) -> TensorView<'_, T, B, IxD>
165where
166 D: DimAPI,
167 R: DataAPI<Data = B::Raw>,
168 B: DeviceAPI<T>,
169{
170 into_dim_f(tensor.view()).rstsr_unwrap()
171}
172
173/// Convert layout to the dynamic dimension [`IxD`].
174///
175/// # See also
176///
177/// Refer to [`into_dim`] for more detailed documentation.
178pub fn into_dyn<S, D>(tensor: TensorBase<S, D>) -> TensorBase<S, IxD>
179where
180 D: DimAPI,
181{
182 into_dim_f(tensor).rstsr_unwrap()
183}
184
185impl<R, T, B, D> TensorAny<R, T, B, D>
186where
187 D: DimAPI,
188 R: DataAPI<Data = B::Raw>,
189 B: DeviceAPI<T>,
190{
191 /// Convert layout to the other dimension.
192 ///
193 /// # See also
194 ///
195 /// Refer to [`into_dim`] for more detailed documentation.
196 pub fn to_dim<D2>(&self) -> TensorView<'_, T, B, D2>
197 where
198 D2: DimAPI,
199 D: DimIntoAPI<D2>,
200 {
201 to_dim(self)
202 }
203
204 /// Convert layout to the other dimension.
205 ///
206 /// # See also
207 ///
208 /// Refer to [`into_dim`] for more detailed documentation.
209 pub fn to_dim_f<D2>(&self) -> Result<TensorView<'_, T, B, D2>>
210 where
211 D2: DimAPI,
212 D: DimIntoAPI<D2>,
213 {
214 to_dim_f(self)
215 }
216
217 /// Convert layout to the other dimension.
218 ///
219 /// # See also
220 ///
221 /// Refer to [`into_dim`] for more detailed documentation.
222 pub fn into_dim<D2>(self) -> TensorAny<R, T, B, D2>
223 where
224 D2: DimAPI,
225 D: DimIntoAPI<D2>,
226 {
227 into_dim(self)
228 }
229
230 /// Convert layout to the other dimension.
231 ///
232 /// # See also
233 ///
234 /// Refer to [`into_dim`] for more detailed documentation.
235 pub fn into_dim_f<D2>(self) -> Result<TensorAny<R, T, B, D2>>
236 where
237 D2: DimAPI,
238 D: DimIntoAPI<D2>,
239 {
240 into_dim_f(self)
241 }
242
243 /// Convert layout to the dynamic dimension [`IxD`].
244 ///
245 /// # See also
246 ///
247 /// Refer to [`into_dim`] for more detailed documentation.
248 pub fn to_dyn(&self) -> TensorView<'_, T, B, IxD> {
249 to_dyn(self)
250 }
251
252 /// Convert layout to the dynamic dimension [`IxD`].
253 ///
254 /// # See also
255 ///
256 /// Refer to [`into_dim`] for more detailed documentation.
257 pub fn into_dyn(self) -> TensorAny<R, T, B, IxD> {
258 into_dyn(self)
259 }
260}
261
262/* #endregion */
263
264#[cfg(test)]
265mod tests {
266
267 #[test]
268 fn doc_to_dim() {
269 use rstsr::prelude::*;
270
271 let a = rt::arange(6).into_shape([2, 3]); // shape: (2, 3), IxD
272
273 // you can debug print tensor or it's layout to verify this
274 println!("a: {:?}", a);
275 // you can also call `const_ndim` to verify the dimension type
276 // `None` here indicates dynamic dimension
277 assert_eq!(a.shape().const_ndim(), None);
278
279 let b = a.to_dim::<Ix2>(); // shape: (2, 3), Ix2
280 println!("b: {:?}", b);
281 assert_eq!(b.shape().const_ndim(), Some(2));
282
283 // use `.to_dim::<IxD>()` or `.to_dyn()` to convert back to dynamic dimension
284 let c = b.to_dyn(); // shape: (2, 3), IxD
285 println!("c: {:?}", c);
286 assert_eq!(c.shape().const_ndim(), None);
287 }
288
289 #[test]
290 #[should_panic]
291 fn doc_to_dim_panic() {
292 use rstsr::prelude::*;
293
294 let a = rt::arange(6).into_shape([2, 3]); // shape: (2, 3), IxD
295 let b = a.to_dim::<Ix3>(); // shape: (2, 3), Ix3, panics
296 println!("b: {:?}", b);
297 }
298}