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}