Skip to main content

aeon_tensor/
indices.rs

1pub trait TensorIndex<const N: usize, const R: usize> {
2    /// Type of iterator over valid tensor indices.
3    type Indices: IndexIterator<R>;
4    /// Converts a valid index into a buffer offset for tensor storage.
5    fn offset_from_index(index: [usize; R]) -> usize;
6    /// Iterates over all (unique) indices in the tensor.
7    /// This must index the tensor in the same order as `Self::offset_from_index`.
8    fn indices() -> Self::Indices;
9    /// Counts all unique indices used to store the tensor.
10    fn count() -> usize {
11        Self::indices().count()
12    }
13    /// Calls a function for each index in the tensor.
14    /// Must index over the tensor in the same order as `Self::indices`.
15    fn for_each_index(f: impl FnMut([usize; R])) {
16        Self::indices().for_each(f);
17    }
18}
19
20pub trait IndexIterator<const R: usize>: Iterator<Item = [usize; R]> {
21    fn zero() -> Self;
22}
23
24/// General tensor implementation with no symmetries of the form Tᵢⱼₖ...
25pub struct Gen;
26
27impl<const N: usize, const R: usize> TensorIndex<N, R> for Gen {
28    type Indices = GenIndices<N, R>;
29
30    fn offset_from_index(index: [usize; R]) -> usize {
31        let mut result = 0;
32        let mut stride = 1;
33
34        for i in (0..R).rev() {
35            result += stride * index[i];
36            stride *= N;
37        }
38
39        result
40    }
41
42    fn indices() -> Self::Indices {
43        GenIndices { cursor: [0; R] }
44    }
45
46    fn for_each_index(mut f: impl FnMut([usize; R])) {
47        if const { R == 0 } {
48            f([0; R]);
49            return;
50        }
51
52        let mut cursor = [0; R];
53
54        f(cursor);
55
56        'l: loop {
57            for slot in (0..R).rev() {
58                cursor[slot] += 1;
59
60                if cursor[slot] < N {
61                    f(cursor);
62                    continue 'l;
63                }
64
65                cursor[slot] = 0;
66            }
67
68            break;
69        }
70    }
71
72    fn count() -> usize {
73        const {
74            let mut result = 1;
75            let mut i = 0;
76
77            while i < R {
78                result *= N;
79                i += 1;
80            }
81
82            result
83        }
84    }
85}
86
87/// Iterate indices in row-major (or left-slot major more generally) order.
88pub struct GenIndices<const N: usize, const R: usize> {
89    cursor: [usize; R],
90}
91
92impl<const N: usize, const R: usize> Default for GenIndices<N, R> {
93    fn default() -> Self {
94        Self { cursor: [0; R] }
95    }
96}
97
98impl<const N: usize, const R: usize> Iterator for GenIndices<N, R> {
99    type Item = [usize; R];
100
101    fn next(&mut self) -> Option<Self::Item> {
102        if const { N == 0 } {
103            // Short circuit if the dimension is zero.
104            return None;
105        }
106
107        // Last index was incremented, iteration is complete
108        if self.cursor[0] >= N {
109            return None;
110        }
111
112        // Store current cursor value (this is what we will return)
113        let result = self.cursor;
114
115        for slot in (0..R).rev() {
116            // If we need to increment this axis, we add to the cursor value
117            self.cursor[slot] += 1;
118            // If the cursor is equal to size, we wrap.
119            // However, if we have reached the final axis,
120            // this indicates we are at the end of iteration,
121            // and will return None on the next call of next().
122            if self.cursor[slot] == N && slot > 0 {
123                self.cursor[slot] = 0;
124                continue;
125            }
126
127            break;
128        }
129
130        Some(result)
131    }
132}
133
134impl<const N: usize, const R: usize> IndexIterator<R> for GenIndices<N, R> {
135    fn zero() -> Self {
136        Self { cursor: [0; R] }
137    }
138}
139
140/// A tensor of the form T₍ᵢⱼ₎
141pub struct Sym;
142
143impl<const N: usize> TensorIndex<N, 2> for Sym {
144    type Indices = SymIndices<N>;
145
146    fn offset_from_index([mut row, mut col]: [usize; 2]) -> usize {
147        if const { N == 1 } {
148            return 0;
149        }
150
151        if const { N == 2 } {
152            return row + col;
153        }
154
155        // Make sure numbers are
156        if col > row {
157            // Swap col and row
158            let tmp = col;
159            col = row;
160            row = tmp;
161        }
162
163        let row_offset = (row * (row + 1)) / 2; // Use gaussian addition to find row offset
164        row_offset + col
165    }
166
167    fn count() -> usize {
168        const { N * (N + 1) / 2 }
169    }
170
171    fn indices() -> Self::Indices {
172        SymIndices::default()
173    }
174
175    fn for_each_index(mut f: impl FnMut([usize; 2])) {
176        if const { N == 1 } {
177            f([0, 0]);
178            return;
179        }
180
181        if const { N == 2 } {
182            f([0, 0]);
183            f([1, 0]);
184            f([1, 1]);
185            return;
186        }
187
188        for row in 0..N {
189            for col in 0..=row {
190                f([row, col]);
191            }
192        }
193    }
194}
195
196#[derive(Default)]
197pub struct SymIndices<const N: usize> {
198    cursor: [usize; 2],
199}
200
201impl<const N: usize> Iterator for SymIndices<N> {
202    type Item = [usize; 2];
203
204    fn next(&mut self) -> Option<Self::Item> {
205        if self.cursor[0] >= N {
206            return None;
207        }
208
209        let result = self.cursor;
210        // Start at (i, j)
211        self.cursor[1] += 1; // Now at (i, j + 1)
212        let inc_row = self.cursor[1] / (self.cursor[0] + 1); // If j > i then 1 else 0
213        self.cursor[1] %= self.cursor[0] + 1; // Make sure j = 0
214        self.cursor[0] += inc_row;
215
216        Some(result)
217    }
218}
219
220impl<const N: usize> IndexIterator<2> for SymIndices<N> {
221    fn zero() -> Self {
222        Self { cursor: [0; 2] }
223    }
224}