1pub trait TensorIndex<const N: usize, const R: usize> {
2 type Indices: IndexIterator<R>;
4 fn offset_from_index(index: [usize; R]) -> usize;
6 fn indices() -> Self::Indices;
9 fn count() -> usize {
11 Self::indices().count()
12 }
13 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
24pub 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
87pub 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 return None;
105 }
106
107 if self.cursor[0] >= N {
109 return None;
110 }
111
112 let result = self.cursor;
114
115 for slot in (0..R).rev() {
116 self.cursor[slot] += 1;
118 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
140pub 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 if col > row {
157 let tmp = col;
159 col = row;
160 row = tmp;
161 }
162
163 let row_offset = (row * (row + 1)) / 2; 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 self.cursor[1] += 1; let inc_row = self.cursor[1] / (self.cursor[0] + 1); self.cursor[1] %= self.cursor[0] + 1; 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}