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