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