Skip to content

Commit fc13897

Browse files
committed
Make sampling an implementation detail.
1 parent 0919c2b commit fc13897

File tree

1 file changed

+31
-36
lines changed

1 file changed

+31
-36
lines changed

src/sort.rs

Lines changed: 31 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,7 @@ where
2020
/// No other assumptions should be made on the ordering of the
2121
/// elements after this computation.
2222
///
23-
/// This method performs a variant of [Sesquickselect] with pivot samples of 5 equally spaced
24-
/// elements around the center.
23+
/// This method performs [Sesquickselect].
2524
///
2625
/// [Sesquickselect]: https://www.wild-inter.net/publications/martinez-nebel-wild-2019.pdf
2726
///
@@ -48,14 +47,6 @@ where
4847
S: DataMut,
4948
S2: Data<Elem = usize>;
5049

51-
/// Sorts a sample of 5 equally spaced elements around the center and returns their indexes.
52-
///
53-
/// **Panics** for arrays of less than 7 elements.
54-
fn sample_mut(&mut self) -> [usize; 5]
55-
where
56-
A: Ord + Clone,
57-
S: DataMut;
58-
5950
/// Partitions the array in increasing order based on the value initially
6051
/// located at `pivot_index` and returns the new index of the value.
6152
///
@@ -182,6 +173,8 @@ where
182173
} else {
183174
// Adapt pivot sampling to relative sought rank and switch from dual-pivot to
184175
// single-pivot partitioning for extreme sought ranks.
176+
let mut sample = [0; 5];
177+
sample_mut(self, &mut sample);
185178
let sought_rank = i as f64 / n as f64;
186179
if (0.036..=0.964).contains(&sought_rank) {
187180
let (lower_index, upper_index) = if sought_rank <= 0.5 {
@@ -197,7 +190,6 @@ where
197190
(3, 4) // (3, 0, 0)
198191
}
199192
};
200-
let sample = self.sample_mut();
201193
let (lower_index, upper_index) =
202194
self.dual_partition_mut(sample[lower_index], sample[upper_index]);
203195
if i < lower_index {
@@ -215,7 +207,6 @@ where
215207
.get_from_sorted_mut(i - (upper_index + 1))
216208
}
217209
} else {
218-
let sample = self.sample_mut();
219210
let pivot_index = if sought_rank <= 0.5 {
220211
0 // (0, 4)
221212
} else {
@@ -248,29 +239,6 @@ where
248239
get_many_from_sorted_mut_unchecked(self, &deduped_indexes)
249240
}
250241

251-
fn sample_mut(&mut self) -> [usize; 5]
252-
where
253-
A: Ord + Clone,
254-
S: DataMut,
255-
{
256-
// Space between sample indexes.
257-
let space = self.len() / 7;
258-
assert!(space > 0, "Cannot sample array of less then 7 elements");
259-
// Initialize sample indexes with their lowermost index.
260-
let mut samples = [self.len() / 2 - 2 * space; 5];
261-
// Equally space sample indexes and sort by their values by looking up their indexes.
262-
for mut index in 1..samples.len() {
263-
// Equally space sample indexes based on their lowermost index.
264-
samples[index] += index * space;
265-
// Insertion sort looking up only the already equally spaced sample indexes.
266-
while index > 0 && self[samples[index - 1]] > self[samples[index]] {
267-
self.swap(samples[index - 1], samples[index]);
268-
index -= 1;
269-
}
270-
}
271-
samples
272-
}
273-
274242
fn partition_mut(&mut self, pivot_index: usize) -> usize
275243
where
276244
A: Ord + Clone,
@@ -434,7 +402,8 @@ fn _get_many_from_sorted_mut_unchecked<A>(
434402

435403
// Since there is no single sought rank to adapt pivot sampling to, the recommended skewed pivot
436404
// sampling of dual-pivot Quicksort is used.
437-
let sample = array.sample_mut();
405+
let mut sample = [0; 5];
406+
sample_mut(&mut array, &mut sample);
438407
let (lower_index, upper_index) = (sample[0], sample[2]); // (0, 1, 2)
439408

440409
// We partition the array with respect to the two pivot values. The pivot values move to the new
@@ -506,3 +475,29 @@ fn _get_many_from_sorted_mut_unchecked<A>(
506475
upper_values,
507476
);
508477
}
478+
479+
/// Equally space `sample` indexes around the center of `array` and sort them by their values.
480+
///
481+
/// `sample` content is ignored but its length defines the sample size and the sample space divider.
482+
///
483+
/// Assumes arrays of at least `sample.len() + 2` elements.
484+
pub(crate) fn sample_mut<A, S>(array: &mut ArrayBase<S, Ix1>, sample: &mut [usize])
485+
where
486+
A: Ord + Clone,
487+
S: DataMut<Elem = A>,
488+
{
489+
// Space between sample indexes.
490+
let space = array.len() / (sample.len() + 2);
491+
// Lowermost sample index.
492+
let lowermost = array.len() / 2 - (sample.len() / 2) * space;
493+
// Equally space sample indexes and sort them by their values by looking up their indexes.
494+
for mut index in 1..sample.len() {
495+
// Equally space sample indexes based on their lowermost index.
496+
sample[index] = lowermost + index * space;
497+
// Insertion sort looking up only the already equally spaced sample indexes.
498+
while index > 0 && array[sample[index - 1]] > array[sample[index]] {
499+
array.swap(sample[index - 1], sample[index]);
500+
index -= 1;
501+
}
502+
}
503+
}

0 commit comments

Comments
 (0)