diff --git a/Cargo.lock b/Cargo.lock index c337c95..50664d6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -425,6 +425,7 @@ dependencies = [ "image", "image-compare", "rand", + "rayon", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index f4172be..f4ccf6a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,7 @@ path = "src/lib.rs" rand = "0.8" image = "0.25" image-compare = "0.5.0" +rayon = "1.11.0" [dev-dependencies] divan = { version = "4.0.2", package = "codspeed-divan-compat" } diff --git a/README.md b/README.md index 8e9c5be..c5d095f 100644 --- a/README.md +++ b/README.md @@ -34,3 +34,5 @@ cargo codspeed run -m walltime ``` Note: You can also set the `CODSPEED_RUNNER_MODE` environment variable to `walltime` to avoid passing `-m walltime` every time. + +# Sauls Version diff --git a/src/bfs.rs b/src/bfs.rs index 487fddc..95f61ac 100644 --- a/src/bfs.rs +++ b/src/bfs.rs @@ -1,4 +1,4 @@ -use std::collections::HashSet; +use std::collections::{HashSet, VecDeque}; /// A simple graph represented as an adjacency list #[derive(Debug, Clone)] @@ -27,21 +27,22 @@ impl Graph { /// Returns the order in which nodes were visited pub fn bfs_naive(graph: &Graph, start: usize) -> Vec { let mut visited = HashSet::new(); - let mut queue = Vec::new(); // Using Vec instead of VecDeque - intentionally inefficient! + // let mut queue = Vec::new(); // Using Vec instead of VecDeque - intentionally inefficient! + let mut queue = VecDeque::new(); let mut result = Vec::new(); - queue.push(start); + queue.push_back(start); visited.insert(start); while !queue.is_empty() { // remove(0) is O(n) - this makes BFS slow! - let node = queue.remove(0); + let node = queue.remove(0).expect("node is available"); result.push(node); if let Some(neighbors) = graph.adjacency.get(node) { for &neighbor in neighbors { if visited.insert(neighbor) { - queue.push(neighbor); + queue.push_back(neighbor); } } } diff --git a/src/dna_matcher.rs b/src/dna_matcher.rs index d99c90e..19cbb18 100644 --- a/src/dna_matcher.rs +++ b/src/dna_matcher.rs @@ -1,7 +1,9 @@ +use rayon::prelude::*; + /// Naive approach: Read the entire file as a string and filter lines pub fn naive_dna_matcher(genome: &str, pattern: &str) -> Vec { genome - .lines() + .par_lines() .filter(|line| !line.starts_with('>')) // Skip headers .filter(|line| line.contains(pattern)) .map(|s| s.to_string()) diff --git a/src/lut_filters.rs b/src/lut_filters.rs index a73068c..e6646cf 100644 --- a/src/lut_filters.rs +++ b/src/lut_filters.rs @@ -18,11 +18,11 @@ use image::{ImageBuffer, Rgb, RgbImage}; pub fn apply_brightness_contrast(img: &RgbImage, brightness: i16, contrast: f32) -> RgbImage { - naive::apply_brightness_contrast(img, brightness, contrast) + saul::apply_brightness_contrast(img, brightness, contrast) } pub fn apply_gamma(img: &RgbImage, gamma: f32) -> RgbImage { - naive::apply_gamma(img, gamma) + saul::apply_gamma(img, gamma) } pub fn apply_brightness_contrast_gamma( @@ -32,7 +32,62 @@ pub fn apply_brightness_contrast_gamma( gamma: f32, ) -> RgbImage { let temp_img = apply_brightness_contrast(img, brightness, contrast); - naive::apply_gamma(&temp_img, gamma) + saul::apply_gamma(&temp_img, gamma) +} + +mod saul { + use super::*; + + fn create_brightness_contrast_lut(brightness: i16, contrast: f32) -> [u8; 256] { + let mut ret = [0; 256]; + for r in 0..=u8::MAX { + let r_float = r as f32; + let value = ((r_float - 128.0) * (1.0 + contrast)) + 128.0 + brightness as f32; + ret[r as usize] = value.clamp(0.0, 255.0) as u8; + } + ret + } + + /// Apply brightness and contrast with floating-point math per pixel + pub fn apply_brightness_contrast(img: &RgbImage, brightness: i16, contrast: f32) -> RgbImage { + let (width, height) = img.dimensions(); + let mut output = ImageBuffer::new(width, height); + let lut = create_brightness_contrast_lut(brightness, contrast); + + for (x, y, pixel) in img.enumerate_pixels() { + let r = pixel[0] as usize; + let g = pixel[1] as usize; + let b = pixel[2] as usize; + output.put_pixel(x, y, Rgb([lut[r], lut[g], lut[b]])); + } + + output + } + + fn create_gamma_lut(gamma: f32) -> [u8; 256] { + let mut ret = [0; 256]; + for r in 0..=u8::MAX { + let value = (r as f32 / 255.0).powf(1.0 / gamma) * 255.0; + ret[r as usize] = value as u8; + } + ret + } + + pub fn apply_gamma(img: &RgbImage, gamma: f32) -> RgbImage { + let (width, height) = img.dimensions(); + let mut output = ImageBuffer::new(width, height); + let lut = create_gamma_lut(gamma); + + for (x, y, pixel) in img.enumerate_pixels() { + let r = lut[pixel[0] as usize]; + let g = lut[pixel[1] as usize]; + let b = lut[pixel[2] as usize]; + + output.put_pixel(x, y, Rgb([r, g, b])); + } + + output + } } mod naive {