From 67fe9f07c2a1580b3d4c63ac183f2771aebe9a66 Mon Sep 17 00:00:00 2001 From: openhands Date: Wed, 1 Jan 2025 03:37:22 +0000 Subject: [PATCH 1/3] Issue #25: Add bucketsort interface and documentation --- crates/cs/blocks-cs-sort/src/algorithms.rs | 4 +- .../src/algorithms/bucketsort.rs | 47 +++++++++++++++++++ 2 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 crates/cs/blocks-cs-sort/src/algorithms/bucketsort.rs diff --git a/crates/cs/blocks-cs-sort/src/algorithms.rs b/crates/cs/blocks-cs-sort/src/algorithms.rs index 7aecf48..d0fa495 100644 --- a/crates/cs/blocks-cs-sort/src/algorithms.rs +++ b/crates/cs/blocks-cs-sort/src/algorithms.rs @@ -1,5 +1,7 @@ // Sorting algorithms pub mod quicksort; +pub mod bucketsort; // Re-export commonly used functions for convenience -pub use self::quicksort::sort as quicksort; \ No newline at end of file +pub use self::quicksort::sort as quicksort; +pub use self::bucketsort::sort as bucketsort; \ No newline at end of file diff --git a/crates/cs/blocks-cs-sort/src/algorithms/bucketsort.rs b/crates/cs/blocks-cs-sort/src/algorithms/bucketsort.rs new file mode 100644 index 0000000..17fdb26 --- /dev/null +++ b/crates/cs/blocks-cs-sort/src/algorithms/bucketsort.rs @@ -0,0 +1,47 @@ +use std::fmt::Debug; + +/// Bucket Sort implementation for sorting slices of floating-point numbers in the range [0, 1). +/// +/// # Algorithm Overview +/// Bucket sort works by: +/// 1. Creating n empty buckets (where n is the length of the input) +/// 2. Putting each element into its corresponding bucket based on its value +/// 3. Sorting each non-empty bucket (using insertion sort) +/// 4. Concatenating all buckets in order +/// +/// # Time Complexity +/// - Best Case: Ω(n + k) when elements are uniformly distributed +/// - Average Case: Θ(n + k) when elements are uniformly distributed +/// - Worst Case: O(n²) when all elements go into the same bucket +/// +/// # Space Complexity +/// - O(n + k) auxiliary space where k is the number of buckets +/// +/// # Stability +/// - Stable if the underlying sort is stable (insertion sort in this case) +/// +/// # Advantages +/// - Linear time complexity for uniformly distributed data +/// - Works well with floating-point numbers +/// - Can be parallelized easily +/// - Good cache performance due to locality of reference +/// +/// # Limitations +/// - Requires uniformly distributed input for best performance +/// - Not in-place sorting algorithm +/// - Requires additional space +/// - Input must be in a known range (typically [0, 1)) +pub fn sort(slice: &mut [f64]) { + // Implementation will be added later +} + +/// Sorts a bucket using insertion sort +fn insertion_sort(bucket: &mut Vec) { + // Implementation will be added later +} + +/// Determines the appropriate bucket index for a value +fn get_bucket_index(value: f64, num_buckets: usize) -> usize { + // Implementation will be added later + 0 +} \ No newline at end of file From e46e2f5796bd527a278a9106026e7014c9d906f0 Mon Sep 17 00:00:00 2001 From: openhands Date: Wed, 1 Jan 2025 03:39:28 +0000 Subject: [PATCH 2/3] Issue #25: Add comprehensive unit tests for bucketsort --- .../src/algorithms/bucketsort.rs | 152 ++++++++++++++++++ 1 file changed, 152 insertions(+) diff --git a/crates/cs/blocks-cs-sort/src/algorithms/bucketsort.rs b/crates/cs/blocks-cs-sort/src/algorithms/bucketsort.rs index 17fdb26..de01999 100644 --- a/crates/cs/blocks-cs-sort/src/algorithms/bucketsort.rs +++ b/crates/cs/blocks-cs-sort/src/algorithms/bucketsort.rs @@ -44,4 +44,156 @@ fn insertion_sort(bucket: &mut Vec) { fn get_bucket_index(value: f64, num_buckets: usize) -> usize { // Implementation will be added later 0 +} + +#[cfg(test)] +mod tests { + use super::*; + use std::f64::EPSILON; + + #[test] + fn test_empty_slice() { + let mut arr: Vec = vec![]; + sort(&mut arr); + assert_eq!(arr, vec![]); + } + + #[test] + fn test_single_element() { + let mut arr = vec![0.5]; + sort(&mut arr); + assert_eq!(arr, vec![0.5]); + } + + #[test] + fn test_sorted_array() { + let mut arr = vec![0.1, 0.2, 0.3, 0.4, 0.5]; + let expected = arr.clone(); + sort(&mut arr); + assert_eq!(arr, expected); + } + + #[test] + fn test_reverse_sorted() { + let mut arr = vec![0.9, 0.7, 0.5, 0.3, 0.1]; + sort(&mut arr); + assert_eq!(arr, vec![0.1, 0.3, 0.5, 0.7, 0.9]); + } + + #[test] + fn test_random_order() { + let mut arr = vec![0.3, 0.1, 0.4, 0.1, 0.5, 0.9, 0.2, 0.6, 0.5, 0.3, 0.5]; + let mut expected = arr.clone(); + expected.sort_by(|a, b| a.partial_cmp(b).unwrap()); + sort(&mut arr); + assert_eq!(arr, expected); + } + + #[test] + fn test_duplicate_elements() { + let mut arr = vec![0.5, 0.5, 0.5, 0.5, 0.5]; + sort(&mut arr); + assert_eq!(arr, vec![0.5, 0.5, 0.5, 0.5, 0.5]); + } + + #[test] + fn test_large_array() { + let mut arr: Vec = (0..1000).map(|x| (x as f64) / 1000.0).rev().collect(); + let mut expected = arr.clone(); + expected.sort_by(|a, b| a.partial_cmp(b).unwrap()); + sort(&mut arr); + assert_eq!(arr, expected); + } + + #[test] + fn test_stability() { + // Test stability by sorting pairs and checking if relative order is preserved + #[derive(Debug, Clone, PartialEq)] + struct Pair { + key: f64, + original_index: usize, + } + + let mut pairs = vec![ + Pair { key: 0.5, original_index: 0 }, + Pair { key: 0.5, original_index: 1 }, + Pair { key: 0.7, original_index: 2 }, + Pair { key: 0.7, original_index: 3 }, + ]; + + let mut values: Vec = pairs.iter().map(|p| p.key).collect(); + sort(&mut values); + + // Verify that relative order is preserved for equal keys + for i in 0..pairs.len() - 1 { + for j in i + 1..pairs.len() { + if (pairs[i].key - pairs[j].key).abs() < EPSILON { + let pos_i = values.iter().position(|&x| (x - pairs[i].key).abs() < EPSILON).unwrap(); + let pos_j = values.iter().rposition(|&x| (x - pairs[j].key).abs() < EPSILON).unwrap(); + assert!(pos_i < pos_j, + "Stability violated for equal elements at original positions {} and {}", + pairs[i].original_index, pairs[j].original_index); + } + } + } + } + + #[test] + fn test_uniform_distribution() { + // Test with uniformly distributed values + let mut arr = vec![0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9]; + let expected = arr.clone(); + sort(&mut arr); + assert_eq!(arr, expected); + } + + #[test] + fn test_clustered_values() { + // Test with values clustered in a small range + let mut arr = vec![0.51, 0.52, 0.53, 0.54, 0.55]; + let expected = arr.clone(); + sort(&mut arr); + assert_eq!(arr, expected); + } + + #[test] + fn test_edge_values() { + // Test with values very close to 0 and 1 + let mut arr = vec![0.001, 0.999, 0.002, 0.998]; + sort(&mut arr); + assert_eq!(arr, vec![0.001, 0.002, 0.998, 0.999]); + } + + #[test] + fn test_bucket_index() { + let num_buckets = 10; + // Test bucket index calculation + assert_eq!(get_bucket_index(0.1, num_buckets), 1); + assert_eq!(get_bucket_index(0.5, num_buckets), 5); + assert_eq!(get_bucket_index(0.99, num_buckets), 9); + assert_eq!(get_bucket_index(0.0, num_buckets), 0); + } + + #[test] + fn test_insertion_sort() { + let mut bucket = vec![0.5, 0.3, 0.4, 0.2, 0.1]; + insertion_sort(&mut bucket); + assert_eq!(bucket, vec![0.1, 0.2, 0.3, 0.4, 0.5]); + } + + #[test] + fn test_sparse_distribution() { + // Test with sparsely distributed values + let mut arr = vec![0.1, 0.9, 0.2, 0.8, 0.3, 0.7]; + sort(&mut arr); + assert_eq!(arr, vec![0.1, 0.2, 0.3, 0.7, 0.8, 0.9]); + } + + #[test] + fn test_almost_sorted() { + // Test with almost sorted array + let mut arr = vec![0.1, 0.2, 0.4, 0.3, 0.5]; + sort(&mut arr); + assert_eq!(arr, vec![0.1, 0.2, 0.3, 0.4, 0.5]); + } } \ No newline at end of file From b5c8fdc0e79c1fdf88f815ba8bd23db2758945ca Mon Sep 17 00:00:00 2001 From: openhands Date: Wed, 1 Jan 2025 03:41:51 +0000 Subject: [PATCH 3/3] Issue #25: Implement bucketsort algorithm --- .../src/algorithms/bucketsort.rs | 46 +++++++++++++++++-- 1 file changed, 42 insertions(+), 4 deletions(-) diff --git a/crates/cs/blocks-cs-sort/src/algorithms/bucketsort.rs b/crates/cs/blocks-cs-sort/src/algorithms/bucketsort.rs index de01999..2b8ea69 100644 --- a/crates/cs/blocks-cs-sort/src/algorithms/bucketsort.rs +++ b/crates/cs/blocks-cs-sort/src/algorithms/bucketsort.rs @@ -32,18 +32,56 @@ use std::fmt::Debug; /// - Requires additional space /// - Input must be in a known range (typically [0, 1)) pub fn sort(slice: &mut [f64]) { - // Implementation will be added later + if slice.len() <= 1 { + return; + } + + let n = slice.len(); + + // Create n empty buckets + let mut buckets: Vec> = vec![Vec::new(); n]; + + // Put array elements in different buckets + for &num in slice.iter() { + let idx = get_bucket_index(num, n); + buckets[idx].push(num); + } + + // Sort individual buckets + for bucket in buckets.iter_mut() { + insertion_sort(bucket); + } + + // Concatenate all buckets into slice + let mut index = 0; + for bucket in buckets.iter() { + for &value in bucket { + slice[index] = value; + index += 1; + } + } } /// Sorts a bucket using insertion sort fn insertion_sort(bucket: &mut Vec) { - // Implementation will be added later + for i in 1..bucket.len() { + let key = bucket[i]; + let mut j = i; + + while j > 0 && bucket[j - 1] > key { + bucket[j] = bucket[j - 1]; + j -= 1; + } + + bucket[j] = key; + } } /// Determines the appropriate bucket index for a value fn get_bucket_index(value: f64, num_buckets: usize) -> usize { - // Implementation will be added later - 0 + let bucket_idx = (value * num_buckets as f64) as usize; + // Handle edge case where value = 1.0 + bucket_idx.min(num_buckets - 1) } #[cfg(test)]