radiate_core/domain/math/
indexes.rs1use crate::{RdRand, random_provider};
2
3pub enum SubsetMode<'a> {
4 StratifiedCorrect,
5 FastRandom,
6 Exclude(&'a [usize]),
7 RangeList(&'a [(usize, usize)]),
8}
9
10pub fn create_individual_indexes(index: usize, max_index: usize, num_indices: usize) -> Vec<usize> {
15 let mut scratch = vec![0; num_indices];
16 subset(
17 max_index,
18 num_indices,
19 &mut scratch,
20 SubsetMode::StratifiedCorrect,
21 );
22 let mut i = 0;
23 while i < scratch.len() && scratch[i] < index {
24 i += 1;
25 }
26 if i < scratch.len() {
27 scratch[i] = index;
28 }
29
30 scratch.sort_unstable();
31 scratch
32}
33
34pub fn individual_indexes(index: usize, max_index: usize, num_indices: usize, buff: &mut [usize]) {
35 subset(max_index, num_indices, buff, SubsetMode::StratifiedCorrect);
36 let mut i = 0;
37 while i < buff.len() && buff[i] < index {
38 i += 1;
39 }
40 if i < buff.len() {
41 buff[i] = index;
42 }
43
44 buff.sort_unstable();
45}
46pub fn subset(max_index: usize, num_indicies: usize, buffer: &mut [usize], mode: SubsetMode) {
49 if max_index < num_indicies {
50 panic!("n smaller than k: {} < {}.", max_index, num_indicies);
51 }
52
53 random_provider::with_rng(|rand| match mode {
54 SubsetMode::StratifiedCorrect => {
55 next(max_index, buffer, rand);
56 }
57 SubsetMode::FastRandom => {
58 for i in 0..num_indicies {
59 buffer[i] = rand.range(0..max_index);
60 }
61 }
62 SubsetMode::Exclude(exclude) => {
63 for i in 0..num_indicies {
64 loop {
65 let index = rand.range(0..max_index);
66 if !exclude.contains(&index) {
67 buffer[i] = index;
68 break;
69 }
70 }
71 }
72 }
73 SubsetMode::RangeList(range_list) => {
74 for i in 0..num_indicies {
75 let (start, end) = range_list[i % range_list.len()];
76 buffer[i] = rand.range(start..end);
77 }
78 }
79 })
80}
81
82fn next(max_index: usize, sub_set: &mut [usize], rand: &mut RdRand<'_>) {
91 let k = sub_set.len();
92 if k == max_index {
93 for i in 0..k {
94 sub_set[i] = i;
95 }
96 return;
97 }
98 build_subset(max_index, sub_set, rand);
99 if k > max_index - k {
100 invert(max_index, sub_set);
101 }
102}
103
104fn build_subset(max_index: usize, sub: &mut [usize], rand: &mut RdRand<'_>) {
107 let k = sub.len();
108 check_subset(max_index, k);
109
110 for i in 0..k {
111 sub[i] = i * max_index / k;
112 }
113
114 for _ in 0..k {
115 let mut ix;
116 let mut l;
117 loop {
118 ix = rand.range(1..max_index);
119 l = (ix * k - 1) / max_index;
120 if sub[l] < ix {
121 break;
122 }
123 }
124 sub[l] += 1;
125 }
126
127 let mut ip = 0;
128 let mut is_ = k;
129 for i in 0..k {
130 let m = sub[i];
131 sub[i] = 0;
132 if m != i * max_index / k {
133 ip += 1;
134 sub[ip - 1] = m;
135 }
136 }
137
138 let ihi = ip;
139 for i in 1..=ihi {
140 ip = ihi + 1 - i;
141 let l = 1 + (sub[ip - 1] * k - 1) / max_index;
142 let ids = sub[ip - 1] - (l - 1) * max_index / k;
143 sub[ip - 1] = 0;
144 sub[is_ - 1] = l;
145 is_ -= ids;
146 }
147
148 for ll in 1..=k {
149 let l = k + 1 - ll;
150 if sub[l - 1] != 0 {
151 let ir = l;
152 let m0 = 1 + (sub[l - 1] - 1) * max_index / k;
153 let m = sub[l - 1] * max_index / k - m0 + 1;
154
155 let ix = rand.range(m0..m0 + m - 1);
156 let mut i = l + 1;
157 while i <= ir && ix >= sub[i - 1] {
158 sub[i - 2] = sub[i - 1];
159 i += 1;
160 }
161 sub[i - 2] = ix;
162 }
163 }
164}
165
166fn invert(n: usize, a: &mut [usize]) {
169 let k = a.len();
170 let mut v = n - 1;
171 let j = n - k - 1;
172 let mut ac = vec![0; k];
173 ac.copy_from_slice(a);
174
175 for i in (0..k).rev() {
176 while let Some(_) = index_of(&ac, j, v) {
177 v -= 1;
178 }
179 a[i] = v;
180 v -= 1;
181 }
182}
183
184fn index_of(a: &[usize], start: usize, value: usize) -> Option<usize> {
185 for i in (0..=start).rev() {
186 if a[i] == value {
187 return Some(i);
188 }
189 }
190
191 None
192}
193
194fn check_subset(n: usize, k: usize) {
195 if n < k {
196 panic!("n smaller than k: {} < {}.", n, k);
197 }
198}
199
200#[cfg(test)]
201mod tests {
202 use super::*;
203
204 #[test]
205 fn test_fast_random_subset() {
206 let n = 50;
207 let k = 20;
208 let mut result = vec![0; k];
209 subset(n, k, &mut result, SubsetMode::FastRandom);
210 assert_eq!(result.len(), k);
211 assert!(result.iter().all(|&x| x < n));
212 }
213
214 #[test]
215 fn test_exclude_subset() {
216 let n = 10;
217 let k = 5;
218 let blacklist = vec![2, 3, 4];
219 let mut result = vec![0; k];
220 subset(n, k, &mut result, SubsetMode::Exclude(&blacklist));
221 assert_eq!(result.len(), k);
222 assert!(result.iter().all(|&x| !blacklist.contains(&x)));
223 }
224
225 #[test]
226 fn test_range_list_subset() {
227 let ranges = vec![(0, 5), (10, 15)];
228 let mut result = vec![0; 6];
229 subset(20, 6, &mut result, SubsetMode::RangeList(&ranges));
230 assert_eq!(result.len(), 6);
231 assert!(
232 result
233 .iter()
234 .all(|&x| (0..5).contains(&x) || (10..15).contains(&x))
235 );
236 }
237
238 #[test]
239 fn test_individual_indexes_includes_index() {
240 let result = create_individual_indexes(7, 20, 5);
241 assert_eq!(result.len(), 5);
242 assert!(result.contains(&7));
243 let mut sorted = result.clone();
244 sorted.sort_unstable();
245 assert_eq!(sorted, result); }
247}