From 61f187293433a712e68f3b3e05cb647042ac9c7e Mon Sep 17 00:00:00 2001 From: Alienscience Date: Wed, 8 Oct 2025 10:29:25 +0200 Subject: [PATCH 1/6] Updated README --- README.md | 2 ++ 1 file changed, 2 insertions(+) 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 From 55be2dedd2a5f4a014a9765d3a16418b263b3ff9 Mon Sep 17 00:00:00 2001 From: Alienscience Date: Wed, 8 Oct 2025 11:20:16 +0200 Subject: [PATCH 2/6] Use VecDeque --- src/bfs.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) 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); } } } From 18963cdd71f18bf4d8efb59aac2176032b40e71b Mon Sep 17 00:00:00 2001 From: Alienscience Date: Wed, 8 Oct 2025 12:09:23 +0200 Subject: [PATCH 3/6] Use lut for brightness/contrast --- src/lut_filters.rs | 45 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/src/lut_filters.rs b/src/lut_filters.rs index a73068c..4ec510b 100644 --- a/src/lut_filters.rs +++ b/src/lut_filters.rs @@ -18,7 +18,7 @@ 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 { @@ -35,6 +35,49 @@ pub fn apply_brightness_contrast_gamma( naive::apply_gamma(&temp_img, gamma) } +mod saul { + use super::*; + + fn create_lut(contrast: f32) -> [f32; 256] { + let mut ret = [0.0; 256]; + for r in 0..=u8::MAX { + let r_float = r as f32; + ret[r as usize] = ((r_float - 128.0) * (1.0 + contrast)) + 128.0; + } + 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_lut(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; + + // Apply contrast and brightness (5 FP ops per channel!) + let r = lut[r] + brightness as f32; + let g = lut[g] + brightness as f32; + let b = lut[b] + brightness as f32; + + output.put_pixel( + x, + y, + Rgb([ + r.clamp(0.0, 255.0) as u8, + g.clamp(0.0, 255.0) as u8, + b.clamp(0.0, 255.0) as u8, + ]), + ); + } + + output + } +} + mod naive { use super::*; From 4773a6ec8f9f04b2f27154e6260bfce424dadae4 Mon Sep 17 00:00:00 2001 From: Alienscience Date: Wed, 8 Oct 2025 12:24:18 +0200 Subject: [PATCH 4/6] Use lut for gamma --- src/lut_filters.rs | 48 +++++++++++++++++++++++++++++----------------- 1 file changed, 30 insertions(+), 18 deletions(-) diff --git a/src/lut_filters.rs b/src/lut_filters.rs index 4ec510b..02532fe 100644 --- a/src/lut_filters.rs +++ b/src/lut_filters.rs @@ -32,17 +32,18 @@ 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_lut(contrast: f32) -> [f32; 256] { - let mut ret = [0.0; 256]; + 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; - ret[r as usize] = ((r_float - 128.0) * (1.0 + contrast)) + 128.0; + 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 } @@ -51,27 +52,38 @@ mod saul { 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_lut(contrast); + 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]])); + } - // Apply contrast and brightness (5 FP ops per channel!) - let r = lut[r] + brightness as f32; - let g = lut[g] + brightness as f32; - let b = lut[b] + brightness as f32; + output + } - output.put_pixel( - x, - y, - Rgb([ - r.clamp(0.0, 255.0) as u8, - g.clamp(0.0, 255.0) as u8, - b.clamp(0.0, 255.0) as u8, - ]), - ); + 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 From 04b9a64b78ef1976c02ef5d849fbc33803699551 Mon Sep 17 00:00:00 2001 From: Alienscience Date: Wed, 8 Oct 2025 14:01:34 +0200 Subject: [PATCH 5/6] Actually call apply_gamma --- src/lut_filters.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lut_filters.rs b/src/lut_filters.rs index 02532fe..e6646cf 100644 --- a/src/lut_filters.rs +++ b/src/lut_filters.rs @@ -22,7 +22,7 @@ pub fn apply_brightness_contrast(img: &RgbImage, brightness: i16, contrast: f32) } 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( From 45c4233b9a9fabc6bd98055ffd957201dc0acea7 Mon Sep 17 00:00:00 2001 From: Alienscience Date: Wed, 8 Oct 2025 15:10:52 +0200 Subject: [PATCH 6/6] Use rayon --- Cargo.lock | 1 + Cargo.toml | 1 + src/dna_matcher.rs | 4 +++- 3 files changed, 5 insertions(+), 1 deletion(-) 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/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())