Skip to main content

tenferro_tensor_core/
rank.rs

1use crate::{IntoShapeVec, Result, ShapeVec, StrideVec, ValidationError};
2use std::fmt::Debug;
3
4/// Convert a shape container into the representation required by a tensor rank.
5///
6/// Dynamic rank accepts any [`IntoShapeVec`] input. For a static [`Rank<N>`],
7/// arrays and array references of exactly `N` elements convert without a
8/// runtime rank check; vectors, slices, and [`ShapeVec`] values are checked by
9/// [`TensorRank::shape_from_vec`].
10///
11/// # Examples
12///
13/// ```rust
14/// use tenferro_tensor_core::{IntoRankShape, Rank};
15///
16/// let shape = <[usize; 2] as IntoRankShape<Rank<2>>>::into_rank_shape([2, 3])?;
17/// assert_eq!(shape, [2, 3]);
18/// # Ok::<(), tenferro_tensor_core::ValidationError>(())
19/// ```
20///
21/// ```compile_fail
22/// use tenferro_tensor_core::{IntoRankShape, Rank};
23///
24/// let _ = <[usize; 2] as IntoRankShape<Rank<3>>>::into_rank_shape([2, 3]);
25/// ```
26pub trait IntoRankShape<R: TensorRank> {
27    /// Convert this shape container into `R`'s shape representation.
28    ///
29    /// # Examples
30    ///
31    /// ```
32    /// use tenferro_tensor_core::{IntoRankShape, Rank};
33    /// let shape = <Vec<usize> as IntoRankShape<Rank<2>>>::into_rank_shape(vec![2, 3])?;
34    /// assert_eq!(shape, [2, 3]);
35    /// # Ok::<(), tenferro_tensor_core::ValidationError>(())
36    /// ```
37    ///
38    /// # Errors
39    ///
40    /// Returns [`ValidationError::RankMismatch`] when a vector or slice has
41    /// a length different from the static rank.
42    fn into_rank_shape(self) -> Result<R::Shape>;
43}
44
45/// Rank contract for tensor metadata shapes and strides.
46///
47/// # Examples
48///
49/// ```rust
50/// use tenferro_tensor_core::{Rank, TensorRank};
51/// let shape = <Rank<2> as TensorRank>::shape_from_vec(vec![2, 3].into())?;
52/// assert_eq!(shape.as_ref(), &[2, 3]);
53/// # Ok::<(), tenferro_tensor_core::ValidationError>(())
54/// ```
55pub trait TensorRank: private::Sealed + Clone + Copy + Debug + Eq + Send + Sync + 'static {
56    /// Static rank when known at compile time.
57    ///
58    /// # Examples
59    ///
60    /// ```rust
61    /// use tenferro_tensor_core::{DynRank, Rank, TensorRank};
62    ///
63    /// assert_eq!(DynRank::RANK, None);
64    /// assert_eq!(Rank::<2>::RANK, Some(2));
65    /// ```
66    const RANK: Option<usize>;
67
68    /// Shape representation for this rank.
69    ///
70    /// # Examples
71    ///
72    /// ```rust
73    /// use tenferro_tensor_core::{DynRank, TensorRank};
74    ///
75    /// let shape: <DynRank as TensorRank>::Shape = vec![2, 3].into();
76    /// assert_eq!(shape.as_ref(), &[2, 3]);
77    /// ```
78    type Shape: Clone + Debug + PartialEq + Eq + AsRef<[usize]> + IntoRankShape<Self>;
79
80    /// Stride representation for this rank.
81    ///
82    /// # Examples
83    ///
84    /// ```rust
85    /// use tenferro_tensor_core::{DynRank, TensorRank};
86    ///
87    /// let strides: <DynRank as TensorRank>::Strides = vec![1, 2].into();
88    /// assert_eq!(strides.as_ref(), &[1, 2]);
89    /// ```
90    type Strides: Clone + Debug + PartialEq + Eq + AsRef<[isize]>;
91
92    /// Convert a dynamic shape vector into this rank's shape representation.
93    ///
94    /// # Examples
95    ///
96    /// ```rust
97    /// use tenferro_tensor_core::{Rank, TensorRank};
98    ///
99    /// let shape = <Rank<1> as TensorRank>::shape_from_vec(vec![4].into())?;
100    /// assert_eq!(shape.as_ref(), &[4]);
101    /// # Ok::<(), tenferro_tensor_core::ValidationError>(())
102    /// ```
103    ///
104    /// # Errors
105    ///
106    /// Returns [`ValidationError::RankMismatch`] when the shape length does
107    /// not equal the compile-time rank.
108    fn shape_from_vec(shape: ShapeVec) -> Result<Self::Shape>;
109
110    /// Convert this rank's shape representation into a dynamic shape vector.
111    ///
112    /// # Examples
113    ///
114    /// ```rust
115    /// use tenferro_tensor_core::{Rank, TensorRank};
116    ///
117    /// let shape = <Rank<2> as TensorRank>::shape_from_vec(vec![2, 3].into())?;
118    /// assert_eq!(<Rank<2> as TensorRank>::shape_into_vec(shape).as_slice(), &[2, 3]);
119    /// # Ok::<(), tenferro_tensor_core::ValidationError>(())
120    /// ```
121    fn shape_into_vec(shape: Self::Shape) -> ShapeVec;
122
123    /// Convert a dynamic stride vector into this rank's stride representation.
124    ///
125    /// # Examples
126    ///
127    /// ```rust
128    /// use tenferro_tensor_core::{Rank, TensorRank};
129    ///
130    /// let strides = <Rank<2> as TensorRank>::strides_from_vec(vec![1, 2].into())?;
131    /// assert_eq!(strides.as_ref(), &[1, 2]);
132    /// # Ok::<(), tenferro_tensor_core::ValidationError>(())
133    /// ```
134    ///
135    /// # Errors
136    ///
137    /// Returns [`ValidationError::RankMismatch`] when the stride length does
138    /// not equal the compile-time rank.
139    fn strides_from_vec(strides: StrideVec) -> Result<Self::Strides>;
140
141    /// Convert this rank's stride representation into a dynamic stride vector.
142    ///
143    /// # Examples
144    ///
145    /// ```rust
146    /// use tenferro_tensor_core::{Rank, TensorRank};
147    ///
148    /// let strides = <Rank<2> as TensorRank>::strides_from_vec(vec![1, 2].into())?;
149    /// assert_eq!(<Rank<2> as TensorRank>::strides_into_vec(strides).as_slice(), &[1, 2]);
150    /// # Ok::<(), tenferro_tensor_core::ValidationError>(())
151    /// ```
152    fn strides_into_vec(strides: Self::Strides) -> StrideVec;
153}
154
155/// Dynamic tensor rank marker.
156///
157/// # Examples
158///
159/// ```rust
160/// use tenferro_tensor_core::{DynRank, TensorRank};
161///
162/// assert_eq!(DynRank::RANK, None);
163/// ```
164#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
165pub struct DynRank;
166
167/// Static tensor rank marker.
168///
169/// # Examples
170///
171/// ```rust
172/// use tenferro_tensor_core::{Rank, TensorRank};
173///
174/// assert_eq!(Rank::<3>::RANK, Some(3));
175/// ```
176#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
177pub struct Rank<const N: usize>;
178
179impl<S> IntoRankShape<DynRank> for S
180where
181    S: IntoShapeVec,
182{
183    fn into_rank_shape(self) -> Result<ShapeVec> {
184        Ok(self.into_shape_vec())
185    }
186}
187
188impl<const N: usize> IntoRankShape<Rank<N>> for [usize; N] {
189    fn into_rank_shape(self) -> Result<[usize; N]> {
190        Ok(self)
191    }
192}
193
194impl<const N: usize> IntoRankShape<Rank<N>> for &[usize; N] {
195    fn into_rank_shape(self) -> Result<[usize; N]> {
196        Ok(*self)
197    }
198}
199
200impl<const N: usize> IntoRankShape<Rank<N>> for Vec<usize> {
201    fn into_rank_shape(self) -> Result<[usize; N]> {
202        Rank::<N>::shape_from_vec(self.into())
203    }
204}
205
206impl<const N: usize> IntoRankShape<Rank<N>> for &[usize] {
207    fn into_rank_shape(self) -> Result<[usize; N]> {
208        Rank::<N>::shape_from_vec(self.into_shape_vec())
209    }
210}
211
212impl<const N: usize> IntoRankShape<Rank<N>> for ShapeVec {
213    fn into_rank_shape(self) -> Result<[usize; N]> {
214        Rank::<N>::shape_from_vec(self)
215    }
216}
217
218impl TensorRank for DynRank {
219    const RANK: Option<usize> = None;
220
221    type Shape = ShapeVec;
222    type Strides = StrideVec;
223
224    fn shape_from_vec(shape: ShapeVec) -> Result<Self::Shape> {
225        Ok(shape)
226    }
227
228    fn shape_into_vec(shape: Self::Shape) -> ShapeVec {
229        shape
230    }
231
232    fn strides_from_vec(strides: StrideVec) -> Result<Self::Strides> {
233        Ok(strides)
234    }
235
236    fn strides_into_vec(strides: Self::Strides) -> StrideVec {
237        strides
238    }
239}
240
241impl<const N: usize> TensorRank for Rank<N> {
242    const RANK: Option<usize> = Some(N);
243
244    type Shape = [usize; N];
245    type Strides = [isize; N];
246
247    fn shape_from_vec(shape: ShapeVec) -> Result<Self::Shape> {
248        let actual = shape.len();
249        shape
250            .into_vec()
251            .try_into()
252            .map_err(|_| ValidationError::RankMismatch {
253                expected: N,
254                actual,
255            })
256    }
257
258    fn shape_into_vec(shape: Self::Shape) -> ShapeVec {
259        ShapeVec::from_iter(shape)
260    }
261
262    fn strides_from_vec(strides: StrideVec) -> Result<Self::Strides> {
263        let actual = strides.len();
264        strides
265            .into_vec()
266            .try_into()
267            .map_err(|_| ValidationError::RankMismatch {
268                expected: N,
269                actual,
270            })
271    }
272
273    fn strides_into_vec(strides: Self::Strides) -> StrideVec {
274        StrideVec::from_iter(strides)
275    }
276}
277
278mod private {
279    pub trait Sealed {}
280
281    impl Sealed for super::DynRank {}
282    impl<const N: usize> Sealed for super::Rank<N> {}
283}