diff --git a/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/README.md b/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/README.md new file mode 100644 index 000000000..e69de29bb -- 2.51.2 From 215be3254393868a04231c3edeebdcd25b6e0bd7 Mon Sep 17 00:00:00 2001 From: Anson Biggs Date: Tue, 29 Mar 2022 11:32:12 -0700 Subject: [PATCH 02/15] init --- .../Go-v-Rust-Quicksort/gogogog/main.go | 112 ++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/gogogog/main.go diff --git a/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/gogogog/main.go b/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/gogogog/main.go new file mode 100644 index 000000000..870bf8d5c --- /dev/null +++ b/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/gogogog/main.go @@ -0,0 +1,112 @@ +package main + +import ( + "fmt" + "math/rand" + "time" +) + +// var MAXGOROUTINES = 10000 + +func Cqsort(s []int, MAXGOROUTINES int) { + if len(s) <= 1 { + return + } + workers := make(chan int, MAXGOROUTINES-1) + for i := 0; i < (MAXGOROUTINES - 1); i++ { + workers <- 1 + } + cqsort(s, nil, workers) +} + +func cqsort(s []int, done chan int, workers chan int) { + // report to caller that we're finished + if done != nil { + defer func() { done <- 1 }() + } + + if len(s) <= 1 { + return + } + // since we may use the doneChannel synchronously + // we need to buffer it so the synchronous code will + // continue executing and not block waiting for a read + doneChannel := make(chan int, 1) + + pivotIdx := partition(s) + + select { + case <-workers: + // if we have spare workers, use a goroutine + // for parallelization + go cqsort(s[:pivotIdx+1], doneChannel, workers) + default: + // if no spare workers, sort synchronously + cqsort(s[:pivotIdx+1], nil, workers) + // calling this here as opposed to using the defer + doneChannel <- 1 + } + // use the existing goroutine to sort above the pivot + cqsort(s[pivotIdx+1:], nil, workers) + // if we used a goroutine we'll need to wait for + // the async signal on this channel, if not there + // will already be a value in the channel and it shouldn't block + <-doneChannel + return +} + +func partition(s []int) (swapIdx int) { + pivotIdx, pivot := pickPivot(s) + // swap right-most element and pivot + s[len(s)-1], s[pivotIdx] = s[pivotIdx], s[len(s)-1] + // sort elements keeping track of pivot's idx + for i := 0; i < len(s)-1; i++ { + if s[i] < pivot { + s[i], s[swapIdx] = s[swapIdx], s[i] + swapIdx++ + } + } + // swap pivot back to its place and return + s[swapIdx], s[len(s)-1] = s[len(s)-1], s[swapIdx] + return +} + +func pickPivot(s []int) (pivotIdx int, pivot int) { + pivotIdx = rand.Intn(len(s)) + pivot = s[pivotIdx] + return +} + +func Qsort(s []int) { + if len(s) <= 1 { + return + } + pivotIdx := partition(s) + Qsort(s[:pivotIdx+1]) + Qsort(s[pivotIdx+1:]) + return +} + +func main() { + + sortSize := 1000000 + // MAXGOROUTINES := 1 + unsorted := make([]int, 0, sortSize) + + // MAXGOROUTINES = 100000 + start := time.Now() + unsorted = rand.Perm(sortSize) + Cqsort(unsorted, 8) + duration := time.Since(start) + + fmt.Println("goroutines", duration) + + // MAXGOROUTINES = 1 + start = time.Now() + unsorted = rand.Perm(sortSize) + Cqsort(unsorted, 1) + duration = time.Since(start) + + fmt.Println(duration) + +} -- 2.51.2 From 42639cadd39f3d9c8a9f090c142cc2a6e2913337 Mon Sep 17 00:00:00 2001 From: Anson Biggs Date: Tue, 29 Mar 2022 11:32:57 -0700 Subject: [PATCH 03/15] renaming --- .../anson-stuff/Go-v-Rust-Quicksort/{gogogog => golang}/main.go | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/{gogogog => golang}/main.go (100%) diff --git a/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/gogogog/main.go b/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/golang/main.go similarity index 100% rename from Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/gogogog/main.go rename to Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/golang/main.go -- 2.51.2 From 1a56eca4c801c90edfe02b29924ba90e4c77314e Mon Sep 17 00:00:00 2001 From: Anson Biggs Date: Thu, 31 Mar 2022 11:02:52 -0700 Subject: [PATCH 04/15] updated code borrowed from internet --- .../Go-v-Rust-Quicksort/.gitignore | 3 + .../Go-v-Rust-Quicksort/rust/Cargo.toml | 13 ++ .../Go-v-Rust-Quicksort/rust/src/main.rs | 156 ++++++++++++++++++ 3 files changed, 172 insertions(+) create mode 100644 Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/.gitignore create mode 100644 Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/rust/Cargo.toml create mode 100644 Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/rust/src/main.rs diff --git a/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/.gitignore b/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/.gitignore new file mode 100644 index 000000000..2280feb9f --- /dev/null +++ b/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/.gitignore @@ -0,0 +1,3 @@ +target/ +debug/ +rust/Cargo.lock \ No newline at end of file diff --git a/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/rust/Cargo.toml b/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/rust/Cargo.toml new file mode 100644 index 000000000..37355f63f --- /dev/null +++ b/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/rust/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "rust" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +rayon = "1.5.1" +rand = "0.8.5" + +[dev-dependencies] +quickcheck = "0.8.0" \ No newline at end of file diff --git a/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/rust/src/main.rs b/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/rust/src/main.rs new file mode 100644 index 000000000..6eafc201c --- /dev/null +++ b/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/rust/src/main.rs @@ -0,0 +1,156 @@ +use rayon::join; + +fn partition(d: &mut [T], is_less: &F) -> usize +where + F: Fn(&T, &T) -> bool, +{ + d.swap(0, d.len() / 2); + let mut mid = 0; + for i in 1..d.len() { + if is_less(&d[i], &d[0]) { + mid += 1; + d.swap(i, mid); + } + } + d.swap(0, mid); + mid +} + +fn insert_sort(d: &mut [T], is_less: &F) +where + F: Fn(&T, &T) -> bool, +{ + for i in 1..d.len() { + let mut n = i; + while n > 0 && is_less(&d[n], &d[n - 1]) { + d.swap(n, n - 1); + n -= 1; + } + } +} + +fn quick_sort(d: &mut [T], is_less: &F) +where + F: Fn(&T, &T) -> bool, +{ + if d.len() > 30 { + let mut mid = partition(d, is_less); + if mid < d.len() / 2 { + mid += 1; + } + let (left, right) = d.split_at_mut(mid); + quick_sort(left, is_less); + quick_sort(right, is_less); + } else { + insert_sort(d, is_less); + } +} + +fn par_quick_sort(d: &mut [T], is_less: &F) +where + F: Fn(&T, &T) -> bool + Send + Sync, + T: Send, +{ + if d.len() > 30 { + let mut mid = partition(d, is_less); + if mid < d.len() / 2 { + mid += 1; + } + let (left, right) = d.split_at_mut(mid); + + if right.len() > 100_000 { + join( + || par_quick_sort(left, is_less), + || par_quick_sort(right, is_less), + ); + } else { + quick_sort(left, is_less); + quick_sort(right, is_less); + } + } else { + insert_sort(d, is_less); + } +} + +pub trait QSort { + fn qsort(&mut self); + + fn is_sorted(&self) -> bool; +} + +impl QSort for [T] +where + T: Ord, +{ + fn qsort(&mut self) { + quick_sort(self, &|a: &T, b: &T| a.lt(b)); + } + + fn is_sorted(&self) -> bool { + self.windows(2).all(|w| w[0] <= w[1]) + } +} + +pub trait ParQSort { + fn par_qsort(&mut self); +} + +impl ParQSort for [T] +where + T: Ord + Send, +{ + fn par_qsort(&mut self) { + par_quick_sort(self, &|a: &T, b: &T| a.lt(b)); + } +} + +use rand::distributions::{Distribution, Uniform}; +use rand::thread_rng; +use rayon::prelude::*; +use std::time::Instant; + +fn main() { + let len = 50_000_000; + let orig: Vec = Uniform::from(0..1_000_000_000) + .sample_iter(&mut thread_rng()) + .take(len) + .collect(); + + macro_rules! test_sort { + ($name:expr, $sort:ident) => { + println!( + "Sorting {} million numbers with {} in Rust ...", + len / 1_000_000, + $name + ); + let mut data = orig.clone(); + let start = Instant::now(); + data.$sort(); + println!("Time: {:.2?}", start.elapsed()); + assert!(data.is_sorted()); + } + } + + test_sort!("naive quicksort", qsort); + test_sort!("stdlib quicksort", sort_unstable); + test_sort!("naive parallel quicksort", par_qsort); + test_sort!("Rayon quicksort", par_sort_unstable); +} + +#[cfg(test)] +mod test { + use super::*; + use quickcheck::quickcheck; + + quickcheck! { + fn test_all(d: Vec) -> bool { + let mut d = d; + + let mut expected = d.clone(); + expected.sort_unstable(); + d.par_qsort(); + + expected == d + } + } +} \ No newline at end of file -- 2.51.2 From e97fdb2834daca1056791dd86e8c66e66ad23b92 Mon Sep 17 00:00:00 2001 From: Anson Biggs Date: Thu, 31 Mar 2022 11:06:30 -0700 Subject: [PATCH 05/15] added references --- Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/README.md b/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/README.md index e69de29bb..fa5a9b3d8 100644 --- a/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/README.md +++ b/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/README.md @@ -0,0 +1,5 @@ +# Rust v. Go Quicksort using Concurrency + +## References + +- https://github.com/Freaky/par_qsort \ No newline at end of file -- 2.51.2 From e9a1404abaa5467780070e09b37928c04ebedf21 Mon Sep 17 00:00:00 2001 From: Anson Biggs Date: Thu, 31 Mar 2022 22:35:11 -0700 Subject: [PATCH 06/15] generated random data --- .../Go-v-Rust-Quicksort/data_generation/Cargo.toml | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/data_generation/Cargo.toml diff --git a/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/data_generation/Cargo.toml b/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/data_generation/Cargo.toml new file mode 100644 index 000000000..62bbb0a57 --- /dev/null +++ b/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/data_generation/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "data_generation" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +rand = "0.8.5" \ No newline at end of file -- 2.51.2 From b0c3cce3545963b0207138036b64ce28e0574f9c Mon Sep 17 00:00:00 2001 From: Anson Biggs Date: Fri, 1 Apr 2022 13:45:28 -0700 Subject: [PATCH 07/15] generated dataset, cant commit due to size --- .../Go-v-Rust-Quicksort/.gitignore | 4 +- .../data_generation/src/main.rs | 67 +++++++++++++++++++ .../Go-v-Rust-Quicksort/golang/main.go | 4 +- 3 files changed, 72 insertions(+), 3 deletions(-) create mode 100644 Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/data_generation/src/main.rs diff --git a/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/.gitignore b/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/.gitignore index 2280feb9f..33db10981 100644 --- a/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/.gitignore +++ b/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/.gitignore @@ -1,3 +1,5 @@ target/ debug/ -rust/Cargo.lock \ No newline at end of file +rust/Cargo.lock +data_generation/Cargo.lock +data/ \ No newline at end of file diff --git a/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/data_generation/src/main.rs b/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/data_generation/src/main.rs new file mode 100644 index 000000000..04663bb6f --- /dev/null +++ b/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/data_generation/src/main.rs @@ -0,0 +1,67 @@ +use rand::distributions::{Distribution, Uniform}; +use rand::seq::SliceRandom; +use rand::thread_rng; + +use std::fs::File; +use std::io::Write; + +fn main() { + { + let mut nums = (0..(50e3 as usize)).collect::>(); + nums.shuffle(&mut thread_rng()); + + let num_str = nums + .iter() + .map(|n| n.to_string()) + .collect::>() + .join("\n"); + + let mut fp = File::create("../data/perm50e3.txt").expect("unable to create file"); + fp.write_all(num_str.as_bytes()).expect("failed to write"); + } + + { + let mut nums = (0..(50e6 as usize)).collect::>(); + nums.shuffle(&mut thread_rng()); + + let num_str = nums + .iter() + .map(|n| n.to_string()) + .collect::>() + .join("\n"); + + let mut fp = File::create("../data/perm50e6.txt").expect("unable to create file"); + fp.write_all(num_str.as_bytes()).expect("failed to write"); + } + + { + let nums: Vec = Uniform::from(0..1_000_000_000) + .sample_iter(&mut thread_rng()) + .take(50e6 as usize) + .collect(); + + let num_str = nums + .iter() + .map(|n| n.to_string()) + .collect::>() + .join("\n"); + + let mut fp = File::create("../data/billion50e6.txt").expect("unable to create file"); + fp.write_all(num_str.as_bytes()).expect("failed to write"); + } + { + let nums: Vec = Uniform::from(0.0..10.0) + .sample_iter(&mut thread_rng()) + .take(50e3 as usize) + .collect(); + + let num_str = nums + .iter() + .map(|n| n.to_string()) + .collect::>() + .join("\n"); + + let mut fp = File::create("../data/floats50e3.txt").expect("unable to create file"); + fp.write_all(num_str.as_bytes()).expect("failed to write"); + } +} diff --git a/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/golang/main.go b/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/golang/main.go index 870bf8d5c..ea502208c 100644 --- a/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/golang/main.go +++ b/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/golang/main.go @@ -89,7 +89,7 @@ func Qsort(s []int) { func main() { - sortSize := 1000000 + sortSize := 50000000 // MAXGOROUTINES := 1 unsorted := make([]int, 0, sortSize) @@ -103,7 +103,7 @@ func main() { // MAXGOROUTINES = 1 start = time.Now() - unsorted = rand.Perm(sortSize) + // unsorted = rand.Perm(sortSize) Cqsort(unsorted, 1) duration = time.Since(start) -- 2.51.2 From 1da17ec3692ec7a8739294fdbbf25a4310b64615 Mon Sep 17 00:00:00 2001 From: Anson Biggs Date: Tue, 19 Apr 2022 18:48:43 -0700 Subject: [PATCH 08/15] read data into rust --- .../Go-v-Rust-Quicksort/rust/src/main.rs | 159 +----------------- 1 file changed, 7 insertions(+), 152 deletions(-) diff --git a/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/rust/src/main.rs b/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/rust/src/main.rs index 6eafc201c..db8d6245e 100644 --- a/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/rust/src/main.rs +++ b/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/rust/src/main.rs @@ -1,156 +1,11 @@ -use rayon::join; - -fn partition(d: &mut [T], is_less: &F) -> usize -where - F: Fn(&T, &T) -> bool, -{ - d.swap(0, d.len() / 2); - let mut mid = 0; - for i in 1..d.len() { - if is_less(&d[i], &d[0]) { - mid += 1; - d.swap(i, mid); - } - } - d.swap(0, mid); - mid -} - -fn insert_sort(d: &mut [T], is_less: &F) -where - F: Fn(&T, &T) -> bool, -{ - for i in 1..d.len() { - let mut n = i; - while n > 0 && is_less(&d[n], &d[n - 1]) { - d.swap(n, n - 1); - n -= 1; - } - } -} - -fn quick_sort(d: &mut [T], is_less: &F) -where - F: Fn(&T, &T) -> bool, -{ - if d.len() > 30 { - let mut mid = partition(d, is_less); - if mid < d.len() / 2 { - mid += 1; - } - let (left, right) = d.split_at_mut(mid); - quick_sort(left, is_less); - quick_sort(right, is_less); - } else { - insert_sort(d, is_less); - } -} - -fn par_quick_sort(d: &mut [T], is_less: &F) -where - F: Fn(&T, &T) -> bool + Send + Sync, - T: Send, -{ - if d.len() > 30 { - let mut mid = partition(d, is_less); - if mid < d.len() / 2 { - mid += 1; - } - let (left, right) = d.split_at_mut(mid); - - if right.len() > 100_000 { - join( - || par_quick_sort(left, is_less), - || par_quick_sort(right, is_less), - ); - } else { - quick_sort(left, is_less); - quick_sort(right, is_less); - } - } else { - insert_sort(d, is_less); - } -} - -pub trait QSort { - fn qsort(&mut self); - - fn is_sorted(&self) -> bool; -} - -impl QSort for [T] -where - T: Ord, -{ - fn qsort(&mut self) { - quick_sort(self, &|a: &T, b: &T| a.lt(b)); - } - - fn is_sorted(&self) -> bool { - self.windows(2).all(|w| w[0] <= w[1]) - } -} - -pub trait ParQSort { - fn par_qsort(&mut self); -} - -impl ParQSort for [T] -where - T: Ord + Send, -{ - fn par_qsort(&mut self) { - par_quick_sort(self, &|a: &T, b: &T| a.lt(b)); - } -} - -use rand::distributions::{Distribution, Uniform}; -use rand::thread_rng; -use rayon::prelude::*; -use std::time::Instant; +use std::fs; fn main() { - let len = 50_000_000; - let orig: Vec = Uniform::from(0..1_000_000_000) - .sample_iter(&mut thread_rng()) - .take(len) - .collect(); - - macro_rules! test_sort { - ($name:expr, $sort:ident) => { - println!( - "Sorting {} million numbers with {} in Rust ...", - len / 1_000_000, - $name - ); - let mut data = orig.clone(); - let start = Instant::now(); - data.$sort(); - println!("Time: {:.2?}", start.elapsed()); - assert!(data.is_sorted()); - } - } + let input = fs::read_to_string("../data/perm50e3.txt") + .expect("Could not read file") + .lines() + .map(|s| s.parse::().unwrap()) + .collect::>(); - test_sort!("naive quicksort", qsort); - test_sort!("stdlib quicksort", sort_unstable); - test_sort!("naive parallel quicksort", par_qsort); - test_sort!("Rayon quicksort", par_sort_unstable); + println!("{}", input.len()); } - -#[cfg(test)] -mod test { - use super::*; - use quickcheck::quickcheck; - - quickcheck! { - fn test_all(d: Vec) -> bool { - let mut d = d; - - let mut expected = d.clone(); - expected.sort_unstable(); - d.par_qsort(); - - expected == d - } - } -} \ No newline at end of file -- 2.51.2 From 806442890babc70fa08da652a0be978a259e2655 Mon Sep 17 00:00:00 2001 From: Anson Biggs Date: Tue, 19 Apr 2022 20:42:08 -0700 Subject: [PATCH 09/15] where it be --- .../Go-v-Rust-Quicksort/golang/main.go | 48 +++--- .../Go-v-Rust-Quicksort/rust/src/main.rs | 11 +- .../Go-v-Rust-Quicksort/rust/src/original.rs | 156 ++++++++++++++++++ .../Go-v-Rust-Quicksort/rust/src/test.scm.txt | 8 + 4 files changed, 201 insertions(+), 22 deletions(-) create mode 100644 Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/rust/src/original.rs create mode 100644 Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/rust/src/test.scm.txt diff --git a/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/golang/main.go b/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/golang/main.go index ea502208c..42689e216 100644 --- a/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/golang/main.go +++ b/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/golang/main.go @@ -2,12 +2,12 @@ package main import ( "fmt" + "io" "math/rand" + "os" "time" ) -// var MAXGOROUTINES = 10000 - func Cqsort(s []int, MAXGOROUTINES int) { if len(s) <= 1 { return @@ -77,34 +77,42 @@ func pickPivot(s []int) (pivotIdx int, pivot int) { return } -func Qsort(s []int) { - if len(s) <= 1 { - return +func main() { + + file, err := os.Open("data/perm50e6.txt") + if err != nil { + fmt.Println(err) + os.Exit(1) } - pivotIdx := partition(s) - Qsort(s[:pivotIdx+1]) - Qsort(s[pivotIdx+1:]) - return -} -func main() { + var perline int + var nums1 []int + var nums2 []int + fmt.Println("Reading File:...") + for { + _, err := fmt.Fscanf(file, "%d\n", &perline) // give a patter to scan - sortSize := 50000000 - // MAXGOROUTINES := 1 - unsorted := make([]int, 0, sortSize) + if err != nil { + + if err == io.EOF { + break // stop reading the file + } + fmt.Println(err) + os.Exit(1) + } + nums1 = append(nums1, perline) + nums2 = append(nums2, perline) + } + fmt.Println("Sorting!") - // MAXGOROUTINES = 100000 start := time.Now() - unsorted = rand.Perm(sortSize) - Cqsort(unsorted, 8) + Cqsort(nums1, 16) duration := time.Since(start) fmt.Println("goroutines", duration) - // MAXGOROUTINES = 1 start = time.Now() - // unsorted = rand.Perm(sortSize) - Cqsort(unsorted, 1) + Cqsort(nums2, 1) duration = time.Since(start) fmt.Println(duration) diff --git a/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/rust/src/main.rs b/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/rust/src/main.rs index db8d6245e..bf77eb88b 100644 --- a/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/rust/src/main.rs +++ b/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/rust/src/main.rs @@ -1,11 +1,18 @@ use std::fs; fn main() { - let input = fs::read_to_string("../data/perm50e3.txt") + let input = fs::read_to_string("../data/perm50e6.txt") .expect("Could not read file") .lines() .map(|s| s.parse::().unwrap()) .collect::>(); - println!("{}", input.len()); + // println!("{}", input.len()); + // let input = vec![100, 32, 57, 10]; +} + +fn Cqsort(s: &Vec) { + if s.len() <= 1 { + return; + } } diff --git a/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/rust/src/original.rs b/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/rust/src/original.rs new file mode 100644 index 000000000..6eafc201c --- /dev/null +++ b/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/rust/src/original.rs @@ -0,0 +1,156 @@ +use rayon::join; + +fn partition(d: &mut [T], is_less: &F) -> usize +where + F: Fn(&T, &T) -> bool, +{ + d.swap(0, d.len() / 2); + let mut mid = 0; + for i in 1..d.len() { + if is_less(&d[i], &d[0]) { + mid += 1; + d.swap(i, mid); + } + } + d.swap(0, mid); + mid +} + +fn insert_sort(d: &mut [T], is_less: &F) +where + F: Fn(&T, &T) -> bool, +{ + for i in 1..d.len() { + let mut n = i; + while n > 0 && is_less(&d[n], &d[n - 1]) { + d.swap(n, n - 1); + n -= 1; + } + } +} + +fn quick_sort(d: &mut [T], is_less: &F) +where + F: Fn(&T, &T) -> bool, +{ + if d.len() > 30 { + let mut mid = partition(d, is_less); + if mid < d.len() / 2 { + mid += 1; + } + let (left, right) = d.split_at_mut(mid); + quick_sort(left, is_less); + quick_sort(right, is_less); + } else { + insert_sort(d, is_less); + } +} + +fn par_quick_sort(d: &mut [T], is_less: &F) +where + F: Fn(&T, &T) -> bool + Send + Sync, + T: Send, +{ + if d.len() > 30 { + let mut mid = partition(d, is_less); + if mid < d.len() / 2 { + mid += 1; + } + let (left, right) = d.split_at_mut(mid); + + if right.len() > 100_000 { + join( + || par_quick_sort(left, is_less), + || par_quick_sort(right, is_less), + ); + } else { + quick_sort(left, is_less); + quick_sort(right, is_less); + } + } else { + insert_sort(d, is_less); + } +} + +pub trait QSort { + fn qsort(&mut self); + + fn is_sorted(&self) -> bool; +} + +impl QSort for [T] +where + T: Ord, +{ + fn qsort(&mut self) { + quick_sort(self, &|a: &T, b: &T| a.lt(b)); + } + + fn is_sorted(&self) -> bool { + self.windows(2).all(|w| w[0] <= w[1]) + } +} + +pub trait ParQSort { + fn par_qsort(&mut self); +} + +impl ParQSort for [T] +where + T: Ord + Send, +{ + fn par_qsort(&mut self) { + par_quick_sort(self, &|a: &T, b: &T| a.lt(b)); + } +} + +use rand::distributions::{Distribution, Uniform}; +use rand::thread_rng; +use rayon::prelude::*; +use std::time::Instant; + +fn main() { + let len = 50_000_000; + let orig: Vec = Uniform::from(0..1_000_000_000) + .sample_iter(&mut thread_rng()) + .take(len) + .collect(); + + macro_rules! test_sort { + ($name:expr, $sort:ident) => { + println!( + "Sorting {} million numbers with {} in Rust ...", + len / 1_000_000, + $name + ); + let mut data = orig.clone(); + let start = Instant::now(); + data.$sort(); + println!("Time: {:.2?}", start.elapsed()); + assert!(data.is_sorted()); + } + } + + test_sort!("naive quicksort", qsort); + test_sort!("stdlib quicksort", sort_unstable); + test_sort!("naive parallel quicksort", par_qsort); + test_sort!("Rayon quicksort", par_sort_unstable); +} + +#[cfg(test)] +mod test { + use super::*; + use quickcheck::quickcheck; + + quickcheck! { + fn test_all(d: Vec) -> bool { + let mut d = d; + + let mut expected = d.clone(); + expected.sort_unstable(); + d.par_qsort(); + + expected == d + } + } +} \ No newline at end of file diff --git a/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/rust/src/test.scm.txt b/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/rust/src/test.scm.txt new file mode 100644 index 000000000..c1fad1595 --- /dev/null +++ b/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/rust/src/test.scm.txt @@ -0,0 +1,8 @@ +(define mycount + (lambda (x lst) + (cond ((null? lst) 0) + ((= x (car lst)) (+ 1 (mycount x (cdr lst)))) + (else (mycount x (cdr lst)))))) + +;(mycount 5 '((5 2) (2 (4 2) 6) 2)) +(mycount 3 '(1 2 3 4 3 2 3)) \ No newline at end of file -- 2.51.2 From f4570e45f8ca44eb126451ed7d6d1f3da5304fa7 Mon Sep 17 00:00:00 2001 From: Anson Date: Mon, 25 Apr 2022 00:23:46 -0700 Subject: [PATCH 10/15] finished rust impl --- .../Go-v-Rust-Quicksort/rust/Cargo.toml | 2 - .../Go-v-Rust-Quicksort/rust/src/main.rs | 138 ++++++++++++++-- .../Go-v-Rust-Quicksort/rust/src/original.rs | 156 ------------------ .../Go-v-Rust-Quicksort/rust/src/test.scm.txt | 8 - 4 files changed, 127 insertions(+), 177 deletions(-) delete mode 100644 Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/rust/src/original.rs delete mode 100644 Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/rust/src/test.scm.txt diff --git a/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/rust/Cargo.toml b/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/rust/Cargo.toml index 37355f63f..5b3eaf7b2 100644 --- a/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/rust/Cargo.toml +++ b/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/rust/Cargo.toml @@ -9,5 +9,3 @@ edition = "2021" rayon = "1.5.1" rand = "0.8.5" -[dev-dependencies] -quickcheck = "0.8.0" \ No newline at end of file diff --git a/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/rust/src/main.rs b/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/rust/src/main.rs index bf77eb88b..9372a20a1 100644 --- a/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/rust/src/main.rs +++ b/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/rust/src/main.rs @@ -1,18 +1,134 @@ -use std::fs; +#![feature(test)] -fn main() { - let input = fs::read_to_string("../data/perm50e6.txt") - .expect("Could not read file") - .lines() - .map(|s| s.parse::().unwrap()) - .collect::>(); +use rayon::join; + +fn choose_pivot(slice: &[T]) -> usize { + // if slice.len() <= 2 {return slice.len() - 1;}; + let (mut ismall, imid, mut ibig) = (0, slice.len() / 2, slice.len() - 1); + if slice[ibig] < slice[ismall] { + std::mem::swap(&mut ibig, &mut ismall); + } + if slice[imid] <= slice[ismall] { + ismall + } else if slice[ibig] <= slice[imid] { + ibig + } else { + imid + } +} + +/// choose a pivot, then reorder so that everything to the left of the pivot is smaller, and +/// everything to the right is greater +/// Assumes slice.len() > 2 +fn partition(slice: &mut [T], pivot: usize) -> usize { + let mxix = slice.len() - 1; + slice.swap(pivot, mxix); + let (mut left, mut right) = (0, mxix - 1); + + while left < right { + if slice[left] <= slice[mxix] { + left += 1; + } else if slice[right] >= slice[mxix] { + right -= 1; + } else { + slice.swap(left, right); + left += 1; + right -= 1; + } + } + + if left > right { + // We just swapped the final two. + slice.swap(left, mxix); + return left; + } + + // Left and right met. + if slice[left] >= slice[mxix] { + slice.swap(left, mxix); + return left; + } else if slice[left] <= slice[mxix] { + slice.swap(left + 1, mxix); + return left + 1; + } - // println!("{}", input.len()); - // let input = vec![100, 32, 57, 10]; + panic!( + "This should be unreachable. Indices: {}, {} / {}", + left, right, mxix + ); } -fn Cqsort(s: &Vec) { - if s.len() <= 1 { +fn quicksort(slice: &mut [T]) { + if slice.len() <= 1 { + return; + } else if slice.len() == 2 { + if slice[0] >= slice[1] { + slice.swap(0, 1); + } return; } + + let pivot = choose_pivot(slice); + let pivot = partition(slice, pivot); + let (left_slice, right_slice) = slice.split_at_mut(pivot); + + let right_slice = &mut right_slice[1..]; + + quicksort(left_slice); + quicksort(right_slice); +} + +fn par_quicksort(slice: &mut [T]) { + if slice.len() <= 1 { + return; + } else if slice.len() == 2 { + if slice[0] >= slice[1] { + slice.swap(0, 1); + } + return; + } + + let pivot = choose_pivot(slice); + let pivot = partition(slice, pivot); + let (left_slice, right_slice) = slice.split_at_mut(pivot); + // left_slice is [0 - pivot-1], right_slice is [pivot, end]. We don't want to include the + // pivot, so reassign right_slice + let right_slice = &mut right_slice[1..]; + + join(|| quicksort(left_slice), || quicksort(right_slice)); +} + +use rand::distributions::{Distribution, Uniform}; +use rand::thread_rng; +fn main() { + let mut s: Vec = Uniform::from(0..1_000_000_000) + .sample_iter(&mut thread_rng()) + .take(100_000) + .collect(); + + quicksort(&mut s); +} + +extern crate test; +use test::Bencher; +fn get_bench_vec() -> Vec { + let s = Uniform::from(0..1_000_000_000) + .sample_iter(&mut thread_rng()) + .take(500_000) + .collect(); + return s; +} + +#[bench] +fn par_qs(b: &mut Bencher) { + let mut test_vec = get_bench_vec(); + + b.iter(|| par_quicksort(&mut test_vec)) +} + +#[bench] +fn qs(b: &mut Bencher) { + let mut test_vec = get_bench_vec(); + + b.iter(|| quicksort(&mut test_vec)) } diff --git a/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/rust/src/original.rs b/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/rust/src/original.rs deleted file mode 100644 index 6eafc201c..000000000 --- a/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/rust/src/original.rs +++ /dev/null @@ -1,156 +0,0 @@ -use rayon::join; - -fn partition(d: &mut [T], is_less: &F) -> usize -where - F: Fn(&T, &T) -> bool, -{ - d.swap(0, d.len() / 2); - let mut mid = 0; - for i in 1..d.len() { - if is_less(&d[i], &d[0]) { - mid += 1; - d.swap(i, mid); - } - } - d.swap(0, mid); - mid -} - -fn insert_sort(d: &mut [T], is_less: &F) -where - F: Fn(&T, &T) -> bool, -{ - for i in 1..d.len() { - let mut n = i; - while n > 0 && is_less(&d[n], &d[n - 1]) { - d.swap(n, n - 1); - n -= 1; - } - } -} - -fn quick_sort(d: &mut [T], is_less: &F) -where - F: Fn(&T, &T) -> bool, -{ - if d.len() > 30 { - let mut mid = partition(d, is_less); - if mid < d.len() / 2 { - mid += 1; - } - let (left, right) = d.split_at_mut(mid); - quick_sort(left, is_less); - quick_sort(right, is_less); - } else { - insert_sort(d, is_less); - } -} - -fn par_quick_sort(d: &mut [T], is_less: &F) -where - F: Fn(&T, &T) -> bool + Send + Sync, - T: Send, -{ - if d.len() > 30 { - let mut mid = partition(d, is_less); - if mid < d.len() / 2 { - mid += 1; - } - let (left, right) = d.split_at_mut(mid); - - if right.len() > 100_000 { - join( - || par_quick_sort(left, is_less), - || par_quick_sort(right, is_less), - ); - } else { - quick_sort(left, is_less); - quick_sort(right, is_less); - } - } else { - insert_sort(d, is_less); - } -} - -pub trait QSort { - fn qsort(&mut self); - - fn is_sorted(&self) -> bool; -} - -impl QSort for [T] -where - T: Ord, -{ - fn qsort(&mut self) { - quick_sort(self, &|a: &T, b: &T| a.lt(b)); - } - - fn is_sorted(&self) -> bool { - self.windows(2).all(|w| w[0] <= w[1]) - } -} - -pub trait ParQSort { - fn par_qsort(&mut self); -} - -impl ParQSort for [T] -where - T: Ord + Send, -{ - fn par_qsort(&mut self) { - par_quick_sort(self, &|a: &T, b: &T| a.lt(b)); - } -} - -use rand::distributions::{Distribution, Uniform}; -use rand::thread_rng; -use rayon::prelude::*; -use std::time::Instant; - -fn main() { - let len = 50_000_000; - let orig: Vec = Uniform::from(0..1_000_000_000) - .sample_iter(&mut thread_rng()) - .take(len) - .collect(); - - macro_rules! test_sort { - ($name:expr, $sort:ident) => { - println!( - "Sorting {} million numbers with {} in Rust ...", - len / 1_000_000, - $name - ); - let mut data = orig.clone(); - let start = Instant::now(); - data.$sort(); - println!("Time: {:.2?}", start.elapsed()); - assert!(data.is_sorted()); - } - } - - test_sort!("naive quicksort", qsort); - test_sort!("stdlib quicksort", sort_unstable); - test_sort!("naive parallel quicksort", par_qsort); - test_sort!("Rayon quicksort", par_sort_unstable); -} - -#[cfg(test)] -mod test { - use super::*; - use quickcheck::quickcheck; - - quickcheck! { - fn test_all(d: Vec) -> bool { - let mut d = d; - - let mut expected = d.clone(); - expected.sort_unstable(); - d.par_qsort(); - - expected == d - } - } -} \ No newline at end of file diff --git a/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/rust/src/test.scm.txt b/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/rust/src/test.scm.txt deleted file mode 100644 index c1fad1595..000000000 --- a/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/rust/src/test.scm.txt +++ /dev/null @@ -1,8 +0,0 @@ -(define mycount - (lambda (x lst) - (cond ((null? lst) 0) - ((= x (car lst)) (+ 1 (mycount x (cdr lst)))) - (else (mycount x (cdr lst)))))) - -;(mycount 5 '((5 2) (2 (4 2) 6) 2)) -(mycount 3 '(1 2 3 4 3 2 3)) \ No newline at end of file -- 2.51.2 From f23dd5e3c248851671e7d3f8d7d225b95c66ed54 Mon Sep 17 00:00:00 2001 From: Anson Date: Mon, 25 Apr 2022 15:12:22 -0700 Subject: [PATCH 11/15] THE RUST ALGO --- .../Go-v-Rust-Quicksort/rust/src/main.rs | 51 ++++++++++--------- 1 file changed, 27 insertions(+), 24 deletions(-) diff --git a/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/rust/src/main.rs b/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/rust/src/main.rs index 9372a20a1..a0817d6db 100644 --- a/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/rust/src/main.rs +++ b/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/rust/src/main.rs @@ -3,23 +3,19 @@ use rayon::join; fn choose_pivot(slice: &[T]) -> usize { - // if slice.len() <= 2 {return slice.len() - 1;}; - let (mut ismall, imid, mut ibig) = (0, slice.len() / 2, slice.len() - 1); - if slice[ibig] < slice[ismall] { - std::mem::swap(&mut ibig, &mut ismall); + let (mut left, mid, mut right) = (0, slice.len() / 2, slice.len() - 1); + if slice[right] < slice[left] { + std::mem::swap(&mut right, &mut left); } - if slice[imid] <= slice[ismall] { - ismall - } else if slice[ibig] <= slice[imid] { - ibig + if slice[mid] <= slice[left] { + return left; + } else if slice[right] <= slice[mid] { + return right; } else { - imid + return mid; } } -/// choose a pivot, then reorder so that everything to the left of the pivot is smaller, and -/// everything to the right is greater -/// Assumes slice.len() > 2 fn partition(slice: &mut [T], pivot: usize) -> usize { let mxix = slice.len() - 1; slice.swap(pivot, mxix); @@ -52,10 +48,7 @@ fn partition(slice: &mut [T], pivot: usize) -> usize { return left + 1; } - panic!( - "This should be unreachable. Indices: {}, {} / {}", - left, right, mxix - ); + panic!("partition failed.") } fn quicksort(slice: &mut [T]) { @@ -68,11 +61,10 @@ fn quicksort(slice: &mut [T]) { return; } - let pivot = choose_pivot(slice); - let pivot = partition(slice, pivot); + let pivot = partition(slice, choose_pivot(slice)); let (left_slice, right_slice) = slice.split_at_mut(pivot); - let right_slice = &mut right_slice[1..]; + let right_slice = &mut right_slice[1..]; // want to exclude pivot quicksort(left_slice); quicksort(right_slice); @@ -88,12 +80,9 @@ fn par_quicksort(slice: &mut [T]) { return; } - let pivot = choose_pivot(slice); - let pivot = partition(slice, pivot); + let pivot = partition(slice, choose_pivot(slice)); let (left_slice, right_slice) = slice.split_at_mut(pivot); - // left_slice is [0 - pivot-1], right_slice is [pivot, end]. We don't want to include the - // pivot, so reassign right_slice - let right_slice = &mut right_slice[1..]; + let right_slice = &mut right_slice[1..]; // want to exclude pivot join(|| quicksort(left_slice), || quicksort(right_slice)); } @@ -132,3 +121,17 @@ fn qs(b: &mut Bencher) { b.iter(|| quicksort(&mut test_vec)) } + +#[test] +fn qs_comp() { + let bv = get_bench_vec(); + let mut par = bv.clone(); + let mut basic = bv.clone(); + + par_quicksort(&mut par); + quicksort(&mut basic); + + for (l, r) in par.iter().zip(basic.iter()) { + assert_eq!(l, r) + } +} -- 2.51.2 From 17e61458a4e80365447991d130af361b612cbf1a Mon Sep 17 00:00:00 2001 From: Anson Date: Mon, 25 Apr 2022 15:31:18 -0700 Subject: [PATCH 12/15] no longer correct --- Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/README.md | 5 ----- 1 file changed, 5 deletions(-) delete mode 100644 Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/README.md diff --git a/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/README.md b/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/README.md deleted file mode 100644 index fa5a9b3d8..000000000 --- a/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Rust v. Go Quicksort using Concurrency - -## References - -- https://github.com/Freaky/par_qsort \ No newline at end of file -- 2.51.2 From 1a9e71dc79c861f3548152f9b4008de62adac1db Mon Sep 17 00:00:00 2001 From: Anson Biggs Date: Mon, 25 Apr 2022 17:44:42 -0700 Subject: [PATCH 13/15] both works --- .../Go-v-Rust-Quicksort/golang/main.go | 164 +++++++++--------- .../Go-v-Rust-Quicksort/rust/src/main.rs | 20 +-- 2 files changed, 92 insertions(+), 92 deletions(-) diff --git a/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/golang/main.go b/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/golang/main.go index 42689e216..32c468c7e 100644 --- a/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/golang/main.go +++ b/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/golang/main.go @@ -2,117 +2,117 @@ package main import ( "fmt" - "io" "math/rand" - "os" "time" ) -func Cqsort(s []int, MAXGOROUTINES int) { - if len(s) <= 1 { +func quicksort(slice []int) { + + if len(slice) <= 1 { return } - workers := make(chan int, MAXGOROUTINES-1) - for i := 0; i < (MAXGOROUTINES - 1); i++ { - workers <- 1 - } - cqsort(s, nil, workers) + + pivot := partition(slice, choose_pivot(slice)) + left := slice[0:pivot] + right := slice[pivot+1:] + + quicksort(left) + quicksort(right) } -func cqsort(s []int, done chan int, workers chan int) { - // report to caller that we're finished - if done != nil { - defer func() { done <- 1 }() - } +func par_quicksort(slice []int) { - if len(s) <= 1 { + if len(slice) <= 1 { return } - // since we may use the doneChannel synchronously - // we need to buffer it so the synchronous code will - // continue executing and not block waiting for a read - doneChannel := make(chan int, 1) - - pivotIdx := partition(s) - - select { - case <-workers: - // if we have spare workers, use a goroutine - // for parallelization - go cqsort(s[:pivotIdx+1], doneChannel, workers) - default: - // if no spare workers, sort synchronously - cqsort(s[:pivotIdx+1], nil, workers) - // calling this here as opposed to using the defer - doneChannel <- 1 - } - // use the existing goroutine to sort above the pivot - cqsort(s[pivotIdx+1:], nil, workers) - // if we used a goroutine we'll need to wait for - // the async signal on this channel, if not there - // will already be a value in the channel and it shouldn't block - <-doneChannel - return + + pivot := partition(slice, choose_pivot(slice)) + left := slice[0:pivot] + right := slice[pivot+1:] + + go quicksort(left) + go quicksort(right) } -func partition(s []int) (swapIdx int) { - pivotIdx, pivot := pickPivot(s) - // swap right-most element and pivot - s[len(s)-1], s[pivotIdx] = s[pivotIdx], s[len(s)-1] - // sort elements keeping track of pivot's idx - for i := 0; i < len(s)-1; i++ { - if s[i] < pivot { - s[i], s[swapIdx] = s[swapIdx], s[i] - swapIdx++ +func partition(slice []int, pivot int) int { + if len(slice) == 1 { + return 0 + } + + mid := len(slice) - 1 + swap(slice, pivot, mid) + left := 0 + right := mid - 1 + + for left < right { + if slice[left] <= slice[mid] { + left = left + 1 + } else if slice[right] >= slice[mid] { + right = right - 1 + } else { + swap(slice, left, right) + left = left + 1 + right = right + 1 } } - // swap pivot back to its place and return - s[swapIdx], s[len(s)-1] = s[len(s)-1], s[swapIdx] - return -} -func pickPivot(s []int) (pivotIdx int, pivot int) { - pivotIdx = rand.Intn(len(s)) - pivot = s[pivotIdx] - return + if left > right { + swap(slice, left, mid) + return left + } + + if slice[left] >= slice[mid] { + swap(slice, left, mid) + return left + } else if slice[left] <= slice[mid] { + swap(slice, left+1, mid) + return left + 1 + } + + panic("partition falied.") } -func main() { +func choose_pivot(slice []int) int { + left := 0 + mid := len(slice) / 2 + right := len(slice) - 1 - file, err := os.Open("data/perm50e6.txt") - if err != nil { - fmt.Println(err) - os.Exit(1) + if slice[right] < slice[left] { + left, right = right, left } - var perline int - var nums1 []int - var nums2 []int - fmt.Println("Reading File:...") - for { - _, err := fmt.Fscanf(file, "%d\n", &perline) // give a patter to scan + if slice[mid] <= slice[left] { + return left + } else if slice[right] <= slice[mid] { + return right - if err != nil { + } else { + return mid + } - if err == io.EOF { - break // stop reading the file - } - fmt.Println(err) - os.Exit(1) - } - nums1 = append(nums1, perline) - nums2 = append(nums2, perline) +} + +func swap(slice []int, a int, b int) { + if a <= len(slice) && b <= len(slice) { + slice[a], slice[b] = slice[b], slice[a] } - fmt.Println("Sorting!") +} + +func main() { + + sortSize := 20000000 + // MAXGOROUTINES := 1 + unsorted := make([]int, 0, sortSize) + unsorted = rand.Perm(sortSize) start := time.Now() - Cqsort(nums1, 16) + quicksort(unsorted) duration := time.Since(start) + fmt.Println("single ", duration) - fmt.Println("goroutines", duration) - + unsorted = rand.Perm(sortSize) start = time.Now() - Cqsort(nums2, 1) + par_quicksort(unsorted) duration = time.Since(start) fmt.Println(duration) diff --git a/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/rust/src/main.rs b/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/rust/src/main.rs index a0817d6db..0cc394ef0 100644 --- a/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/rust/src/main.rs +++ b/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/rust/src/main.rs @@ -17,14 +17,14 @@ fn choose_pivot(slice: &[T]) -> usize { } fn partition(slice: &mut [T], pivot: usize) -> usize { - let mxix = slice.len() - 1; - slice.swap(pivot, mxix); - let (mut left, mut right) = (0, mxix - 1); + let mid = slice.len() - 1; + slice.swap(pivot, mid); + let (mut left, mut right) = (0, mid - 1); while left < right { - if slice[left] <= slice[mxix] { + if slice[left] <= slice[mid] { left += 1; - } else if slice[right] >= slice[mxix] { + } else if slice[right] >= slice[mid] { right -= 1; } else { slice.swap(left, right); @@ -35,16 +35,16 @@ fn partition(slice: &mut [T], pivot: usize) -> usize { if left > right { // We just swapped the final two. - slice.swap(left, mxix); + slice.swap(left, mid); return left; } // Left and right met. - if slice[left] >= slice[mxix] { - slice.swap(left, mxix); + if slice[left] >= slice[mid] { + slice.swap(left, mid); return left; - } else if slice[left] <= slice[mxix] { - slice.swap(left + 1, mxix); + } else if slice[left] <= slice[mid] { + slice.swap(left + 1, mid); return left + 1; } -- 2.51.2 From 305cd62d00ab1bb5ef57e6689c17dc19a5a7b703 Mon Sep 17 00:00:00 2001 From: Anson Biggs Date: Mon, 25 Apr 2022 21:02:23 -0700 Subject: [PATCH 14/15] final code --- .../Go-v-Rust-Quicksort/golang/main.go | 11 ++---- .../Go-v-Rust-Quicksort/rust/.rustfmt.toml | 1 + .../Go-v-Rust-Quicksort/rust/src/main.rs | 37 +++++++++++-------- 3 files changed, 27 insertions(+), 22 deletions(-) create mode 100644 Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/rust/.rustfmt.toml diff --git a/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/golang/main.go b/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/golang/main.go index 32c468c7e..e905223a3 100644 --- a/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/golang/main.go +++ b/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/golang/main.go @@ -21,7 +21,6 @@ func quicksort(slice []int) { } func par_quicksort(slice []int) { - if len(slice) <= 1 { return } @@ -89,7 +88,6 @@ func choose_pivot(slice []int) int { } else { return mid } - } func swap(slice []int, a int, b int) { @@ -103,18 +101,17 @@ func main() { sortSize := 20000000 // MAXGOROUTINES := 1 unsorted := make([]int, 0, sortSize) - unsorted = rand.Perm(sortSize) start := time.Now() + unsorted = rand.Perm(sortSize) quicksort(unsorted) duration := time.Since(start) - fmt.Println("single ", duration) + fmt.Println("Single Threaded: ", duration) - unsorted = rand.Perm(sortSize) start = time.Now() + unsorted = rand.Perm(sortSize) par_quicksort(unsorted) duration = time.Since(start) - - fmt.Println(duration) + fmt.Println("Concurrent: ", duration) } diff --git a/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/rust/.rustfmt.toml b/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/rust/.rustfmt.toml new file mode 100644 index 000000000..9afaf5073 --- /dev/null +++ b/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/rust/.rustfmt.toml @@ -0,0 +1 @@ +max_width = 60 \ No newline at end of file diff --git a/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/rust/src/main.rs b/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/rust/src/main.rs index 0cc394ef0..34990b193 100644 --- a/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/rust/src/main.rs +++ b/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/rust/src/main.rs @@ -3,7 +3,8 @@ use rayon::join; fn choose_pivot(slice: &[T]) -> usize { - let (mut left, mid, mut right) = (0, slice.len() / 2, slice.len() - 1); + let (mut left, mid, mut right) = + (0, slice.len() / 2, slice.len() - 1); if slice[right] < slice[left] { std::mem::swap(&mut right, &mut left); } @@ -16,7 +17,10 @@ fn choose_pivot(slice: &[T]) -> usize { } } -fn partition(slice: &mut [T], pivot: usize) -> usize { +fn partition( + slice: &mut [T], + pivot: usize, +) -> usize { let mid = slice.len() - 1; slice.swap(pivot, mid); let (mut left, mut right) = (0, mid - 1); @@ -62,7 +66,8 @@ fn quicksort(slice: &mut [T]) { } let pivot = partition(slice, choose_pivot(slice)); - let (left_slice, right_slice) = slice.split_at_mut(pivot); + let (left_slice, right_slice) = + slice.split_at_mut(pivot); let right_slice = &mut right_slice[1..]; // want to exclude pivot @@ -70,7 +75,9 @@ fn quicksort(slice: &mut [T]) { quicksort(right_slice); } -fn par_quicksort(slice: &mut [T]) { +fn par_quicksort( + slice: &mut [T], +) { if slice.len() <= 1 { return; } else if slice.len() == 2 { @@ -81,30 +88,30 @@ fn par_quicksort(slice: &mut [T]) { } let pivot = partition(slice, choose_pivot(slice)); - let (left_slice, right_slice) = slice.split_at_mut(pivot); + let (left_slice, right_slice) = + slice.split_at_mut(pivot); let right_slice = &mut right_slice[1..]; // want to exclude pivot - join(|| quicksort(left_slice), || quicksort(right_slice)); + join( + || quicksort(left_slice), + || quicksort(right_slice), + ); } -use rand::distributions::{Distribution, Uniform}; +use rand::prelude::SliceRandom; use rand::thread_rng; fn main() { - let mut s: Vec = Uniform::from(0..1_000_000_000) - .sample_iter(&mut thread_rng()) - .take(100_000) - .collect(); + let mut s = get_bench_vec(); quicksort(&mut s); + par_quicksort(&mut s); } extern crate test; use test::Bencher; fn get_bench_vec() -> Vec { - let s = Uniform::from(0..1_000_000_000) - .sample_iter(&mut thread_rng()) - .take(500_000) - .collect(); + let mut s = (0..20000000).collect::>(); + s.shuffle(&mut thread_rng()); return s; } -- 2.51.2 From d1d23e9670da424be60d4c268b7aa24c89f55844 Mon Sep 17 00:00:00 2001 From: Anson Biggs Date: Wed, 21 Sep 2022 09:38:15 -0600 Subject: [PATCH 15/15] Add report and presentation to readme --- Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/readme.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/readme.md diff --git a/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/readme.md b/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/readme.md new file mode 100644 index 000000000..6afeea147 --- /dev/null +++ b/Anson-Projects/anson-stuff/Go-v-Rust-Quicksort/readme.md @@ -0,0 +1,5 @@ +# Go vs Rust Quicksort + +Presentation: https://ss.ansonbiggs.com/s/858gL2pxjsAZzsR + +Report: https://ss.ansonbiggs.com/s/AwNbmRY3zbzjQFx