1use core::hash::Hash;
10use std::collections::HashMap;
11use std::fmt::Debug;
12use std::ops::Range;
13
14#[derive(Debug, PartialEq, Eq)]
18pub struct PermutationResult {
19 pub perm: Vec<usize>,
20 pub unmatched_source_indices: Vec<usize>,
21 pub unmatched_target_indices: Vec<usize>,
22}
23
24#[derive(Debug)]
28pub struct ExpandedPermResult {
29 pub perm: Vec<Option<usize>>,
30 pub unmatched_source_indices: Vec<usize>,
31 pub unmatched_target_indices: Vec<usize>,
32}
33
34impl ExpandedPermResult {
35 fn collapse(self) -> PermutationResult {
38 let Self {
39 perm,
40 unmatched_source_indices,
41 unmatched_target_indices,
42 } = self;
43
44 PermutationResult {
45 perm: perm.into_iter().flatten().collect(),
46 unmatched_source_indices,
47 unmatched_target_indices,
48 }
49 }
50}
51pub fn generate_expanded_permutation<T>(source: &[T], target: &[T]) -> ExpandedPermResult
55where
56 T: Hash + Eq,
57{
58 let mut index_source: HashMap<&T, Vec<usize>> = Default::default();
59 let mut unmatched_target_indices: Vec<usize> = Default::default();
60 let mut unmatched_source_indices: Vec<usize>;
61
62 source
63 .iter()
64 .enumerate()
65 .for_each(|(i, v)| index_source.entry(v).or_default().push(i));
66
67 index_source.values_mut().for_each(|vec| vec.reverse());
68
69 let result_perm = target
70 .iter()
71 .enumerate()
72 .map(|(i, v)| (i, index_source.get_mut(v).and_then(|tp| tp.pop())))
73 .map(|(i, v)| {
74 v.is_none().then(|| unmatched_target_indices.push(i));
75 v
76 })
77 .collect::<Vec<_>>();
78
79 unmatched_source_indices = index_source
80 .values()
81 .flat_map(|v| v.iter())
82 .cloned()
83 .collect();
84
85 unmatched_source_indices.sort();
86
87 ExpandedPermResult {
88 perm: result_perm,
89 unmatched_source_indices,
90 unmatched_target_indices,
91 }
92}
93
94pub fn generate_permutation<T>(source: &[T], target: &[T]) -> PermutationResult
101where
102 T: Hash + Eq,
103{
104 generate_expanded_permutation(source, target).collapse()
105}
106
107fn find_sortable_range(perm: &[usize], max_index: usize) -> Range<usize> {
117 let prefix_len = perm
118 .iter()
119 .enumerate()
120 .take_while(|(expected, value)| *expected == **value)
121 .count();
122
123 let postfix_len = if prefix_len < perm.len() {
127 perm.iter()
128 .rev()
129 .enumerate()
130 .take_while(|(index_from_end, value)| (max_index - *index_from_end) == **value)
131 .count()
132 } else {
133 0
134 };
135
136 Range {
137 start: prefix_len,
138 end: perm.len() - postfix_len,
139 }
140}
141
142pub struct BubbleSortIter<'a, T> {
158 perm: Vec<usize>,
159 source: &'a [T],
160 sortable: Range<usize>,
162 ranked: Vec<usize>,
165 larger_before: Vec<usize>,
168 at_least: Vec<usize>,
171 swap_count: usize,
172 cursor: usize,
173 unused_value_count: usize,
174}
175
176impl<'a, T> BubbleSortIter<'a, T>
177where
178 T: Hash + Eq,
179{
180 fn new(mut perm: Vec<usize>, source: &'a [T], unused_value_count: usize) -> Self {
182 let sortable = find_sortable_range(&perm, source.len().saturating_sub(1));
183 let unsorted = &mut perm[sortable.clone()];
184 let mut ranked = unsorted.to_vec();
185 ranked.sort_unstable();
186 let mut larger_before = vec![0; unsorted.len()];
187 let mut seen = Fenwick::zeros(unsorted.len());
188 for (preceding, value) in unsorted.iter().enumerate() {
189 let rank = ranked
190 .binary_search(value)
191 .expect("every value of the permutation is ranked");
192 larger_before[rank] = preceding - seen.count_before(rank);
193 seen.add(rank);
194 }
195 let deepest = larger_before.iter().copied().max().unwrap_or(0);
196 let mut at_least = vec![0; deepest + 2];
197 for &larger in &larger_before {
198 at_least[larger] += 1;
199 }
200 for p in (0..=deepest).rev() {
201 at_least[p] += at_least[p + 1];
202 }
203 let swap_count = larger_before.iter().sum();
204 unsorted.copy_from_slice(&ranked);
205 BubbleSortIter {
206 perm,
207 source,
208 sortable,
209 ranked,
210 larger_before,
211 at_least,
212 swap_count,
213 cursor: swap_count,
214 unused_value_count,
215 }
216 }
217
218 pub fn edit_distance(&self) -> usize {
222 self.swap_count + self.unused_value_count
223 }
224
225 pub fn swap_distance(&self) -> usize {
228 self.swap_count
229 }
230
231 pub fn next<'b>(&'b mut self) -> Option<Perm<'a, 'b, T>> {
234 (self.cursor < self.swap_count).then(|| {
235 self.seek(self.cursor + 1);
236 self.current()
237 })
238 }
239
240 pub fn skip(&mut self, distance: usize) {
241 self.seek(self.cursor.saturating_add(distance));
242 }
243
244 pub fn next_back<'b>(&'b mut self) -> Option<Perm<'a, 'b, T>> {
246 (self.cursor > 0).then(|| {
247 self.seek(self.cursor - 1);
248 self.current()
249 })
250 }
251
252 pub fn skip_back(&mut self, distance: usize) {
253 self.seek(self.cursor.saturating_sub(distance));
254 }
255
256 pub fn current<'b>(&'b self) -> Perm<'a, 'b, T> {
257 Perm::new(self)
258 }
259
260 pub fn midpoint<'b>(&'b mut self) -> Perm<'a, 'b, T> {
261 self.seek(self.swap_count / 2);
262 self.current()
263 }
264
265 pub fn interpolate<'b>(&'b mut self, interpolate_percentage: u8) -> Perm<'a, 'b, T> {
266 self.seek((self.swap_count * (interpolate_percentage as usize)) / 100);
267 self.current()
268 }
269
270 pub fn history_size(&self) -> usize {
271 self.swap_count
272 }
273
274 fn seek(&mut self, swaps: usize) {
277 let swaps = swaps.min(self.swap_count);
278 if swaps == self.cursor {
279 return;
280 }
281 let (passes, partial) = self.passes_within(swaps);
282 let state = &mut self.perm[self.sortable.clone()];
283 let mut free = Fenwick::ones(state.len());
287 for (rank, &value) in self.ranked.iter().enumerate() {
288 let larger = self.larger_before[rank].saturating_sub(passes);
289 let slot = free.nth(larger);
290 free.remove(slot);
291 state[slot] = value;
292 }
293 let mut left = partial;
294 let mut j = 0;
295 while left > 0 {
296 if state[j] > state[j + 1] {
297 state.swap(j, j + 1);
298 left -= 1;
299 }
300 j += 1;
301 }
302 self.cursor = swaps;
303 }
304
305 fn passes_within(&self, swaps: usize) -> (usize, usize) {
309 let deepest = self.at_least.len() - 2;
310 let (mut passes, mut done) = (0, 0);
311 while passes < deepest && done + self.at_least[passes + 1] <= swaps {
312 done += self.at_least[passes + 1];
313 passes += 1;
314 }
315 (passes, swaps - done)
316 }
317}
318
319pub struct Perm<'a, 'b, T> {
320 perm: &'b Vec<usize>,
321 source: &'a [T],
322 i: usize,
323}
324
325impl<'a, 'b, T> Perm<'a, 'b, T> {
326 fn new(parent: &'b BubbleSortIter<'a, T>) -> Self {
327 Perm {
328 perm: &parent.perm,
329 source: parent.source,
330 i: 0,
331 }
332 }
333}
334
335impl<'a, 'b, T> Iterator for Perm<'a, 'b, T>
336where
337 T: Hash + Eq,
338{
339 type Item = &'a T;
340
341 fn next(&mut self) -> Option<Self::Item> {
342 (self.i < self.perm.len()).then(|| {
343 let result = &self.source[self.perm[self.i]];
344 self.i += 1;
345 result
346 })
347 }
348}
349
350struct Fenwick(Vec<usize>);
354
355fn lowest_bit(node: usize) -> usize {
358 1 << node.trailing_zeros()
359}
360
361impl Fenwick {
362 fn zeros(len: usize) -> Self {
364 Fenwick(vec![0; len + 1])
365 }
366
367 fn ones(len: usize) -> Self {
369 let mut tree = vec![1; len + 1];
370 tree[0] = 0;
371 for node in 1..=len {
372 let parent = node + lowest_bit(node);
373 if parent <= len {
374 tree[parent] += tree[node];
375 }
376 }
377 Fenwick(tree)
378 }
379
380 fn add(&mut self, slot: usize) {
381 let mut node = slot + 1;
382 while node < self.0.len() {
383 self.0[node] += 1;
384 node += lowest_bit(node);
385 }
386 }
387
388 fn remove(&mut self, slot: usize) {
389 let mut node = slot + 1;
390 while node < self.0.len() {
391 self.0[node] -= 1;
392 node += lowest_bit(node);
393 }
394 }
395
396 fn count_before(&self, slot: usize) -> usize {
398 let mut node = slot;
399 let mut count = 0;
400 while node > 0 {
401 count += self.0[node];
402 node -= lowest_bit(node);
403 }
404 count
405 }
406
407 fn nth(&self, n: usize) -> usize {
409 let mut slot = 0;
410 let mut rest = n;
411 let mut step = (self.0.len() - 1).checked_ilog2().map_or(0, |log| 1 << log);
412 while step > 0 {
413 if slot + step < self.0.len() && self.0[slot + step] <= rest {
414 slot += step;
415 rest -= self.0[slot];
416 }
417 step >>= 1;
418 }
419 slot
420 }
421}
422
423pub fn bubble_sort_distance<T>(source: &[T], target: &[T]) -> usize
424where
425 T: PartialEq + Hash + Eq + Debug + Clone + Copy + 'static,
426{
427 iterable_bubble_sort(source, target).swap_count
428}
429
430pub fn iterable_bubble_sort_from_perm<T>(
431 source: &[T],
432 permutation_result: PermutationResult,
433) -> BubbleSortIter<'_, T>
434where
435 T: Hash + Eq,
436{
437 let PermutationResult {
438 perm,
439 unmatched_source_indices,
440 unmatched_target_indices,
441 } = permutation_result;
442
443 let unused_values = unmatched_source_indices.len() + unmatched_target_indices.len();
444
445 BubbleSortIter::new(perm, source, unused_values)
446}
447
448pub fn iterable_bubble_sort<'a, T>(source: &'a [T], target: &'a [T]) -> BubbleSortIter<'a, T>
449where
450 T: Hash + Eq,
451{
452 iterable_bubble_sort_from_perm(source, generate_permutation(source, target))
453}
454
455#[cfg(test)]
456mod tests {
457 use std::str::from_utf8;
458
459 use super::*;
460
461 #[test]
462 fn test_get_permutations() {
463 assert_eq!(
464 generate_permutation(b"abaca", b"aaacb"),
465 PermutationResult {
466 perm: vec![0, 2, 4, 3, 1],
467 unmatched_source_indices: vec![],
468 unmatched_target_indices: vec![],
469 }
470 );
471 }
472
473 #[test]
474 fn test_get_permutations_with_mismatch() {
475 assert_eq!(
476 generate_permutation(b"abacaF", b"aaaacb"),
477 PermutationResult {
478 perm: vec![0, 2, 4, 3, 1],
479 unmatched_source_indices: vec![5],
480 unmatched_target_indices: vec![3],
481 }
482 );
483 }
484
485 #[test]
486 fn test_get_permutations_with_lots_of_mismatches() {
487 assert_eq!(
489 generate_permutation(b"AabcefGHijmNNp", b"abcDefijKLmOpQRST"),
490 PermutationResult {
491 perm: vec![1, 2, 3, 4, 5, 8, 9, 10, 13],
492 unmatched_source_indices: vec![0, 6, 7, 11, 12],
493 unmatched_target_indices: vec![3, 8, 9, 11, 13, 14, 15, 16],
494 }
495 );
496
497 assert_eq!(
500 generate_permutation(b"fceaiGHNpbAjmN", b"abcDefijKLmOpQRST"),
501 PermutationResult {
502 perm: vec![3, 9, 1, 2, 0, 4, 11, 12, 8],
503 unmatched_source_indices: vec![5, 6, 7, 10, 13],
504 unmatched_target_indices: vec![3, 8, 9, 11, 13, 14, 15, 16],
505 }
506 );
507 }
508 macro_rules! assert_sortable_range_eq {
509 ([$($full:expr),*], [$($expected_sortable_range:expr),*]; where max_index = $max_index:expr) => {
510 let full_perm : &[usize] = &[$($full),*];
511 let range = find_sortable_range(full_perm, $max_index);
512 let actual_sortable_range = &full_perm[range];
513 let expected_sortable_range: &[usize] = &[$($expected_sortable_range),*];
514 assert_eq!(actual_sortable_range, expected_sortable_range);
515 };
516 }
517
518 #[test]
519 fn test_find_sortable_range() {
520 assert_sortable_range_eq!([0, 1, 2, 3, 4, 5, 6], []; where max_index = 6);
521 assert_sortable_range_eq!([0, 1, 2, 4, 3, 5, 6], [4, 3]; where max_index = 6);
522 assert_sortable_range_eq!([0, 1, 2, 4, 3, 5, 6], [4, 3, 5, 6]; where max_index = 7);
523 assert_sortable_range_eq!([1, 2, 4, 3, 5, 6], [1, 2, 4, 3]; where max_index = 6);
524 }
525
526 #[test]
527 fn test_bubble_sort_distance() {
528 assert_eq!(bubble_sort_distance(b"abaca", b"aaacb"), 4);
529 }
530
531 macro_rules! assert_perm_eq {
532 ($expected:expr, $perm:expr) => {
533 assert_eq!(
534 Ok($expected),
535 from_utf8(&$perm.cloned().collect::<Vec<u8>>())
536 );
537 };
538 }
539
540 #[test]
541 fn test_bubble_sort_iterator() {
542 let mut it = iterable_bubble_sort(b"abaca", b"aaacb");
543
544 assert_perm_eq!("abaca", it.current());
547 assert_perm_eq!("aabca", it.next_back().expect("Should be 1 of 4"));
548 assert_perm_eq!("aacba", it.next_back().expect("Should be 2 of 4"));
549 assert_perm_eq!("aacab", it.next_back().expect("Should be 3 of 4"));
550 assert_perm_eq!("aaacb", it.next_back().expect("Should be 4 of 4"));
551
552 assert_perm_eq!("aaacb", it.current());
555 assert_perm_eq!("aacab", it.next().expect("Should be 1 of 4"));
556 assert_perm_eq!("aacba", it.next().expect("Should be 2 of 4"));
557 assert_perm_eq!("aabca", it.next().expect("Should be 3 of 4"));
558 assert_perm_eq!("abaca", it.next().expect("Should be 4 of 4"));
559 }
560
561 #[test]
562 fn test_bubble_sort_distance_mismatch() {
563 assert_eq!(bubble_sort_distance(b"afbaca", b"aadacb"), 4);
564 }
565
566 #[test]
567 fn test_bubble_sort_iterator_mismatch() {
568 let mut it = iterable_bubble_sort(b"afbaca", b"aadacb");
569
570 assert_eq!(it.edit_distance(), it.swap_distance() + 2);
571
572 assert_perm_eq!("abaca", it.current());
575 assert_perm_eq!("aabca", it.next_back().expect("Should be 1 of 4"));
576 assert_perm_eq!("aacba", it.next_back().expect("Should be 2 of 4"));
577 assert_perm_eq!("aacab", it.next_back().expect("Should be 3 of 4"));
578 assert_perm_eq!("aaacb", it.next_back().expect("Should be 4 of 4"));
579
580 assert_perm_eq!("aaacb", it.current());
583 assert_perm_eq!("aacab", it.next().expect("Should be 1 of 4"));
584 assert_perm_eq!("aacba", it.next().expect("Should be 2 of 4"));
585 assert_perm_eq!("aabca", it.next().expect("Should be 3 of 4"));
586 assert_perm_eq!("abaca", it.next().expect("Should be 4 of 4"));
587 }
588
589 #[test]
590 pub fn test_midpoint() {
591 let mut it = iterable_bubble_sort(b"baaaa", b"aaaab");
592
593 assert_perm_eq!("aabaa", it.midpoint());
594 }
595
596 fn recorded_states(perm: &[usize]) -> Vec<Vec<usize>> {
599 let mut perm = perm.to_vec();
600 let mut states = vec![perm.clone()];
601 for pass in 0..perm.len().saturating_sub(1) {
602 let mut swapped = false;
603 for j in 0..perm.len() - pass - 1 {
604 if perm[j] > perm[j + 1] {
605 perm.swap(j, j + 1);
606 states.push(perm.clone());
607 swapped = true;
608 }
609 }
610 if !swapped {
611 break;
612 }
613 }
614 states
615 }
616
617 fn orders(values: &[usize]) -> Vec<Vec<usize>> {
619 if values.is_empty() {
620 return vec![vec![]];
621 }
622 (0..values.len())
623 .flat_map(|first| {
624 let mut rest = values.to_vec();
625 let head = rest.remove(first);
626 orders(&rest).into_iter().map(move |mut order| {
627 order.insert(0, head);
628 order
629 })
630 })
631 .collect()
632 }
633
634 fn assert_states_are_the_recorded_sorts(source: &[()], perm: Vec<usize>) {
638 let states = recorded_states(&perm);
639 let swaps = states.len() - 1;
640 let mut sort = iterable_bubble_sort_from_perm(
641 source,
642 PermutationResult {
643 perm: perm.clone(),
644 unmatched_source_indices: vec![],
645 unmatched_target_indices: vec![],
646 },
647 );
648 assert_eq!(sort.swap_distance(), swaps, "{perm:?}");
649 assert_eq!(sort.perm, states[swaps], "{perm:?}");
650 for state in states.iter().rev().skip(1) {
651 sort.next_back().expect("a swap is left to undo");
652 assert_eq!(&sort.perm, state, "{perm:?}");
653 }
654 assert!(sort.next_back().is_none(), "{perm:?}");
655 for state in &states[1..] {
656 sort.next().expect("a swap is left");
657 assert_eq!(&sort.perm, state, "{perm:?}");
658 }
659 assert!(sort.next().is_none(), "{perm:?}");
660 for percentage in 0..=100 {
661 sort.interpolate(percentage);
662 let expected = &states[swaps * usize::from(percentage) / 100];
663 assert_eq!(&sort.perm, expected, "{perm:?} at {percentage}%");
664 }
665 sort.midpoint();
666 assert_eq!(sort.perm, states[swaps / 2], "{perm:?}");
667 }
668
669 #[test]
677 fn every_state_is_the_recorded_sorts() {
678 for len in 0..=7 {
679 let dense: Vec<usize> = (0..len).collect();
680 let sparse: Vec<usize> = (0..len).map(|value| 2 * value + 1).collect();
681 for (values, source_len) in [(dense, len), (sparse, 2 * len + 2)] {
682 let source = vec![(); source_len];
683 for order in orders(&values) {
684 assert_states_are_the_recorded_sorts(&source, order);
685 }
686 }
687 }
688 let mut state: u64 = 0x9e37_79b9_7f4a_7c15;
689 let mut random = move |bound: usize| {
690 state ^= state << 13;
691 state ^= state >> 7;
692 state ^= state << 17;
693 state as usize % bound
694 };
695 for len in [20, 41, 64] {
696 for _ in 0..10 {
697 let mut order: Vec<usize> = (0..len).collect();
698 for last in (1..len).rev() {
699 order.swap(last, random(last + 1));
700 }
701 assert_states_are_the_recorded_sorts(&vec![(); len], order);
702 }
703 }
704 }
705
706 const BOUNDED_MEMORY_CHILD_ENV: &str = "HERMIT_BUBBLE_SORT_BOUNDED_MEMORY_CHILD";
709
710 #[test]
716 fn a_long_reversal_sorts_in_bounded_memory() {
717 let (_, module) = module_path!().split_once("::").unwrap();
719 let name = format!("{module}::a_long_reversal_sorts_in_bounded_memory");
720 if std::env::var(BOUNDED_MEMORY_CHILD_ENV).as_deref() == Ok(name.as_str()) {
721 sort_a_long_reversal_under_a_data_cap();
722 return;
723 }
724 let output = std::process::Command::new(std::env::current_exe().unwrap())
725 .args([name.as_str(), "--exact", "--nocapture", "--test-threads=1"])
726 .env(BOUNDED_MEMORY_CHILD_ENV, &name)
727 .output()
728 .unwrap();
729 let stdout = String::from_utf8_lossy(&output.stdout);
730 let rendered = format!(
731 "status {}\nstdout:\n{stdout}\nstderr:\n{}",
732 output.status,
733 String::from_utf8_lossy(&output.stderr)
734 );
735 assert!(output.status.success(), "{rendered}");
736 let peak_kib: u64 = stdout
738 .split("peak resident KiB: ")
739 .nth(1)
740 .and_then(|rest| rest.split_whitespace().next())
741 .unwrap_or_else(|| panic!("the sort did not run:\n{rendered}"))
742 .parse()
743 .unwrap();
744 assert!(
745 peak_kib < 256 << 10,
746 "peaked at {peak_kib} KiB:\n{rendered}"
747 );
748 }
749
750 fn sort_a_long_reversal_under_a_data_cap() {
752 use nix::sys::resource::Resource;
753 use nix::sys::resource::getrlimit;
754 use nix::sys::resource::setrlimit;
755 let (_, core_hard) = getrlimit(Resource::RLIMIT_CORE).unwrap();
760 setrlimit(Resource::RLIMIT_CORE, core_hard.min(1), core_hard.min(1)).unwrap();
761 let (_, data_hard) = getrlimit(Resource::RLIMIT_DATA).unwrap();
762 let data_cap = data_hard.min(1 << 30);
763 setrlimit(Resource::RLIMIT_DATA, data_cap, data_cap).unwrap();
764 let len = 200_000;
765 let source: Vec<usize> = (0..len).collect();
766 let target: Vec<usize> = source.iter().rev().copied().collect();
767 let mut sort = iterable_bubble_sort(&source, &target);
768 let swaps = len * (len - 1) / 2;
769 assert_eq!(sort.swap_distance(), swaps);
770 let midpoint: Vec<usize> = sort.midpoint().copied().collect();
773 assert_eq!(inversions(&midpoint), swaps - swaps / 2);
774 let status = std::fs::read_to_string("/proc/self/status").unwrap();
775 let peak = status
776 .lines()
777 .find_map(|line| line.strip_prefix("VmHWM:"))
778 .and_then(|kib| kib.trim().strip_suffix("kB"))
779 .expect("/proc/self/status reports VmHWM");
780 println!("peak resident KiB: {}", peak.trim());
781 }
782
783 fn inversions(values: &[usize]) -> usize {
786 let mut seen = Fenwick::zeros(values.len());
787 values
788 .iter()
789 .enumerate()
790 .map(|(preceding, &value)| {
791 let larger = preceding - seen.count_before(value);
792 seen.add(value);
793 larger
794 })
795 .sum()
796 }
797
798 macro_rules! assert_expanded_target_eq {
803 ($expected:expr, expand_target($src:expr, $target:expr)) => {
804 assert_eq!(
805 Ok($expected),
806 from_utf8(
807 &generate_expanded_permutation($src, $target)
808 .perm
809 .into_iter()
810 .map(|i_opt| i_opt.map(|i| $src[i]).unwrap_or(b'_'))
811 .collect::<Vec<u8>>()
812 )
813 );
814 };
815 }
816
817 #[test]
818 pub fn test_expanted_perm() {
819 assert_expanded_target_eq!("a_", expand_target(b"a", b"ab"));
820 assert_expanded_target_eq!("aaacb", expand_target(b"abaca", b"aaacb"));
821 assert_expanded_target_eq!("_aa_ac_b", expand_target(b"aVbaFGcaER", b"PaaAacTb"));
822 }
823}