Skip to content

Commit 05b87b4

Browse files
committed
Make sampling public and test it.
1 parent 4c3ae67 commit 05b87b4

File tree

2 files changed

+107
-28
lines changed

2 files changed

+107
-28
lines changed

src/sort.rs

+60-28
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,41 @@ where
154154
A: Ord + Clone,
155155
S: DataMut;
156156

157+
/// Equally spaces `sample` indexes around the center of `array` and sorts them by their values.
158+
///
159+
/// `sample` content is ignored but its length defines the sample size and sample space divider.
160+
///
161+
/// **Panics** if `self.len() < sample.len() + 2`.
162+
///
163+
/// ```
164+
/// use ndarray::Array1;
165+
/// use ndarray_stats::Sort1dExt;
166+
/// use noisy_float::types::n64;
167+
///
168+
/// // Define sample size of 5.
169+
/// let mut sample = [0; 5];
170+
///
171+
/// // Create array from 100 down to 1;
172+
/// let mut array = Array1::range(n64(100.0), n64(0.0), n64(-1.0));
173+
/// assert_eq!(array.len(), 100);
174+
///
175+
/// // Find `sample` indices and sort their values `array[sample[s]]`.
176+
/// array.sample_mut(&mut sample);
177+
///
178+
/// // Equally spaced by 13 non-sample elements around center of 50.
179+
/// let assert = [22, 36, 50, 64, 78];
180+
/// assert_eq!(sample, &assert[..]);
181+
/// // Ensure `array[sample[s]]` is sorted.
182+
/// assert_eq!(sample.map(|s| array[s]), assert.map(|s| s as f64));
183+
/// // Ensure reverse order of non-sample elements is preserved.
184+
/// assert_eq!(array[49], n64(51.0));
185+
/// assert_eq!(array[51], n64(49.0));
186+
/// ```
187+
fn sample_mut(&mut self, sample: &mut [usize])
188+
where
189+
A: Ord + Clone,
190+
S: DataMut;
191+
157192
private_decl! {}
158193
}
159194

@@ -179,7 +214,7 @@ where
179214
} else {
180215
// Sorted sample of 5 equally spaced elements around the center.
181216
let mut sample = [0; 5];
182-
sample_mut(self, &mut sample);
217+
self.sample_mut(&mut sample);
183218
// Adapt pivot sampling to relative sought rank and switch from dual-pivot to
184219
// single-pivot partitioning for extreme sought ranks.
185220
let sought_rank = i as f64 / n as f64;
@@ -344,6 +379,29 @@ where
344379
(lower, upper)
345380
}
346381

382+
fn sample_mut(&mut self, sample: &mut [usize])
383+
where
384+
A: Ord + Clone,
385+
S: DataMut,
386+
{
387+
// Assumes arrays of at least `sample.len() + 2` elements.
388+
assert!(self.len() >= sample.len() + 2);
389+
// Space between sample indexes.
390+
let space = self.len() / (sample.len() + 2);
391+
// Lowermost sample index.
392+
let lowermost = self.len() / 2 - (sample.len() / 2) * space;
393+
// Equally space sample indexes and sort them by their values by looking up their indexes.
394+
for mut index in 0..sample.len() {
395+
// Equally space sample indexes based on their lowermost index.
396+
sample[index] = lowermost + index * space;
397+
// Insertion sort looking up only the already equally spaced sample indexes.
398+
while index > 0 && self[sample[index - 1]] > self[sample[index]] {
399+
self.swap(sample[index - 1], sample[index]);
400+
index -= 1;
401+
}
402+
}
403+
}
404+
347405
private_impl! {}
348406
}
349407

@@ -423,7 +481,7 @@ fn _get_many_from_sorted_mut_unchecked<A>(
423481

424482
// Sorted sample of 5 equally spaced elements around the center.
425483
let mut sample = [0; 5];
426-
sample_mut(&mut array, &mut sample);
484+
array.sample_mut(&mut sample);
427485
// Since there is no single sought rank to adapt pivot sampling to, the recommended skewed
428486
// pivot sampling of dual-pivot Quicksort is used in the assumption that multiple indexes
429487
// change characteristics from Quickselect towards Quicksort.
@@ -505,29 +563,3 @@ fn _get_many_from_sorted_mut_unchecked<A>(
505563
);
506564
});
507565
}
508-
509-
/// Equally space `sample` indexes around the center of `array` and sort them by their values.
510-
///
511-
/// `sample` content is ignored but its length defines the sample size and the sample space divider.
512-
///
513-
/// Assumes arrays of at least `sample.len() + 2` elements.
514-
pub(crate) fn sample_mut<A, S>(array: &mut ArrayBase<S, Ix1>, sample: &mut [usize])
515-
where
516-
A: Ord + Clone,
517-
S: DataMut<Elem = A>,
518-
{
519-
// Space between sample indexes.
520-
let space = array.len() / (sample.len() + 2);
521-
// Lowermost sample index.
522-
let lowermost = array.len() / 2 - (sample.len() / 2) * space;
523-
// Equally space sample indexes and sort them by their values by looking up their indexes.
524-
for mut index in 0..sample.len() {
525-
// Equally space sample indexes based on their lowermost index.
526-
sample[index] = lowermost + index * space;
527-
// Insertion sort looking up only the already equally spaced sample indexes.
528-
while index > 0 && array[sample[index - 1]] > array[sample[index]] {
529-
array.swap(sample[index - 1], sample[index]);
530-
index -= 1;
531-
}
532-
}
533-
}

tests/sort.rs

+47
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,53 @@ fn test_dual_partition_mut() {
6565
}
6666
}
6767

68+
#[test]
69+
fn test_sample_mut() {
70+
let mut sample = [0; 5];
71+
72+
let assert = [1, 2, 3, 4, 5];
73+
let mut array = Array1::range(n64(0.0), n64(7.0), n64(1.0));
74+
assert_eq!(array.len(), 7);
75+
array.sample_mut(&mut sample);
76+
assert_eq!(sample, &assert[..]);
77+
78+
let assert = [2, 3, 4, 5, 6];
79+
let mut array = Array1::range(n64(0.0), n64(8.0), n64(1.0));
80+
assert_eq!(array.len(), 8);
81+
array.sample_mut(&mut sample);
82+
assert_eq!(sample, &assert[..]);
83+
let mut array = Array1::range(n64(0.0), n64(9.0), n64(1.0));
84+
assert_eq!(array.len(), 9);
85+
array.sample_mut(&mut sample);
86+
assert_eq!(sample, &assert[..]);
87+
88+
let assert = [3, 4, 5, 6, 7];
89+
let mut array = Array1::range(n64(0.0), n64(10.0), n64(1.0));
90+
assert_eq!(array.len(), 10);
91+
array.sample_mut(&mut sample);
92+
assert_eq!(sample, &assert[..]);
93+
94+
let assert = [3, 5, 7, 9, 11];
95+
let mut array = Array1::range(n64(0.0), n64(14.0), n64(1.0));
96+
assert_eq!(array.len(), 14);
97+
array.sample_mut(&mut sample);
98+
assert_eq!(sample, &assert[..]);
99+
100+
let assert = [22, 36, 50, 64, 78];
101+
let mut array = Array1::range(n64(0.0), n64(100.0), n64(1.0));
102+
assert_eq!(array.len(), 100);
103+
array.sample_mut(&mut sample);
104+
assert_eq!(sample, &assert[..]);
105+
assert_eq!(sample.map(|s| array[s]), assert.map(|s| s as f64));
106+
107+
let assert = [22, 36, 50, 64, 78];
108+
let mut array = Array1::range(n64(100.0), n64(0.0), n64(-1.0));
109+
assert_eq!(array.len(), 100);
110+
array.sample_mut(&mut sample);
111+
assert_eq!(sample, &assert[..]);
112+
assert_eq!(sample.map(|s| array[s]), assert.map(|s| s as f64));
113+
}
114+
68115
#[test]
69116
fn test_quantile_mut_with_large_array_of_equal_floats() {
70117
let mut array: Array1<N64> = Array1::ones(1_000_000);

0 commit comments

Comments
 (0)