From 2e239681cea8a0cd4df9e963b97b16417c98440f Mon Sep 17 00:00:00 2001 From: Keenan Tims Date: Wed, 11 Dec 2024 00:55:47 -0800 Subject: [PATCH] day11: performance --- 11/Cargo.lock | 46 +++++++++++++++++++++++++++++++++++ 11/Cargo.toml | 1 + 11/src/main.rs | 65 +++++++++++++++++++++++++++++++++----------------- 3 files changed, 90 insertions(+), 22 deletions(-) diff --git a/11/Cargo.lock b/11/Cargo.lock index b5abc4f..2c7cdb0 100644 --- a/11/Cargo.lock +++ b/11/Cargo.lock @@ -2,11 +2,37 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "crossbeam-deque" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" + [[package]] name = "day11" version = "0.1.0" dependencies = [ "itertools", + "rayon", ] [[package]] @@ -23,3 +49,23 @@ checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" dependencies = [ "either", ] + +[[package]] +name = "rayon" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] diff --git a/11/Cargo.toml b/11/Cargo.toml index 9f1e0f2..285fbe6 100644 --- a/11/Cargo.toml +++ b/11/Cargo.toml @@ -5,3 +5,4 @@ edition = "2021" [dependencies] itertools = "0.13.0" +rayon = "1.10.0" diff --git a/11/src/main.rs b/11/src/main.rs index 7fdea69..10c0d3f 100644 --- a/11/src/main.rs +++ b/11/src/main.rs @@ -1,6 +1,7 @@ use std::collections::HashMap; use std::fs::File; use std::io::{BufRead, BufReader, Lines}; +use std::iter::repeat; use std::time::{Duration, Instant}; use itertools::Itertools; @@ -42,46 +43,67 @@ struct Stone { value: u64, } +enum BlinkResult { + One(Stone), + Two(Stone, Stone), +} + impl Stone { - fn blink_once(self) -> Vec { + fn blink_once(self) -> BlinkResult { let n_digits = if self.value == 0 { 1 } else { self.value.ilog10() + 1 }; if self.value == 0 { - vec![Stone { value: 1 }] + BlinkResult::One(Stone { value: 1 }) } else if n_digits % 2 == 0 { let parts = ( self.value / 10u64.pow(n_digits / 2), self.value % 10u64.pow(n_digits / 2), ); - vec![Stone { value: parts.0 }, Stone { value: parts.1 }] + BlinkResult::Two(Stone { value: parts.0 }, Stone { value: parts.1 }) } else { - vec![Stone { + BlinkResult::One(Stone { value: self.value * 2024, - }] + }) } } - fn blink(self, times: usize) -> Vec { - let mut stones = vec![self]; - for _ in 0..times { - stones = stones.iter().flat_map(|stone| stone.blink_once()).collect(); - } - stones - } + // #[allow(dead_code)] + // fn blink(self, times: usize) -> Vec { + // // Used in submitted part 1 solution + // let mut stones = vec![self]; + // for _ in 0..times { + // stones = stones.iter().flat_map(|stone| stone.blink_once()).collect(); + // } + // stones + // } } -fn count_blinks(stone: Stone, blinks: u64, cache: &mut HashMap<(u64, Stone), u64>) -> u64 { - if cache.contains_key(&(blinks, stone)) { - return cache[&(blinks, stone)]; +fn count_blinks(stone: Stone, blink: usize, cache: &mut Vec>) -> u64 { + if cache[blink].contains_key(&stone) { + return cache[blink][&stone]; } let stones = stone.blink_once(); - let result = if blinks == 1 { - stones.len() as u64 + let result = if blink == 0 { + match stones { + BlinkResult::One(_) => 1, + BlinkResult::Two(_, _) => 2, + } } else { - stones.iter().map(|s| count_blinks(*s, blinks - 1, cache)).sum() + match stones { + BlinkResult::One(s) => count_blinks(s, blink - 1, cache), + BlinkResult::Two(s1, s2) => count_blinks(s1, blink - 1, cache) + count_blinks(s2, blink - 1, cache), + } }; - cache.insert((blinks, stone), result); + cache[blink].insert(stone, result); result } +fn blink_stones(stones: &[Stone], blinks: usize) -> u64 { + let mut cache = Vec::from_iter(repeat(HashMap::new()).take(blinks)); + stones + .iter() + .map(|stone| count_blinks(*stone, blinks - 1, &mut cache)) + .sum() +} + // PROBLEM 1 solution fn problem1(mut input: Lines) -> u64 { @@ -94,7 +116,7 @@ fn problem1(mut input: Lines) -> u64 { value: v.parse().unwrap(), }) .collect_vec(); - stones.iter().flat_map(|stone| stone.blink(25)).count() as u64 + blink_stones(&stones, 25) } // PROBLEM 2 solution @@ -108,8 +130,7 @@ fn problem2(mut input: Lines) -> u64 { value: v.parse().unwrap(), }) .collect_vec(); - let mut cache = HashMap::new(); - stones.iter().map(|s| count_blinks(*s, 75, &mut cache)).sum() + blink_stones(&stones, 75) } #[cfg(test)]