properly speedup part2

This commit is contained in:
nora 2023-12-04 20:35:59 +01:00
parent 672f2a3674
commit 93af372574
4 changed files with 94 additions and 32 deletions

View file

@ -20,7 +20,7 @@ helper::define_variants! {
basic => crate::part1; basic => crate::part1;
} }
part2 { part2 {
naive => crate::naive::part2; naive => crate::naive::part2, sample_count=1000;
zero_alloc => crate::zero_alloc::part2; zero_alloc => crate::zero_alloc::part2;
branchless => |i| unsafe { crate::branchless::part2(i) }; branchless => |i| unsafe { crate::branchless::part2(i) };
no_lines => |i| unsafe { crate::no_lines::part2(i) }; no_lines => |i| unsafe { crate::no_lines::part2(i) };

View file

@ -1,3 +1,5 @@
mod p2cache;
use helper::{Day, Variants}; use helper::{Day, Variants};
pub fn main() { pub fn main() {
@ -9,10 +11,11 @@ struct Day04;
helper::define_variants! { helper::define_variants! {
day => crate::Day04; day => crate::Day04;
part1 { part1 {
basic => crate::part1; basic => crate::part1, sample_count=1000;
} }
part2 { part2 {
basic => crate::part2; basic => crate::part2, sample_count=100;
cache => crate::p2cache::part2, sample_count=1000;
} }
} }
@ -26,21 +29,25 @@ impl Day for Day04 {
} }
} }
fn line_match_count(line: &str) -> usize {
let mut numbers = line.split(':').nth(1).unwrap().split("|");
let winning = numbers
.next()
.unwrap()
.split_whitespace()
.collect::<Vec<_>>();
let you_have = numbers.next().unwrap().split_whitespace();
you_have
.filter(|have| winning.iter().any(|w| w == have))
.count()
}
fn part1(input: &str) -> u64 { fn part1(input: &str) -> u64 {
input input
.lines() .lines()
.map(|line| { .map(|line| {
let mut numbers = line.split(':').nth(1).unwrap().split("|"); let win_amount = line_match_count(line);
let winning = numbers
.next()
.unwrap()
.split_whitespace()
.collect::<Vec<_>>();
let you_have = numbers.next().unwrap().split_whitespace();
let win_amount = you_have
.filter(|have| winning.iter().any(|w| w == have))
.count();
if win_amount > 0 { if win_amount > 0 {
1 << (win_amount - 1) 1 << (win_amount - 1)
@ -51,8 +58,19 @@ fn part1(input: &str) -> u64 {
.sum() .sum()
} }
fn part2(_input: &str) -> u64 { fn part2(input: &str) -> u64 {
0 let lines = input.lines().map(line_match_count).collect::<Vec<_>>();
let mut processed = 0;
let mut todo = (0..lines.len()).collect::<Vec<_>>();
while let Some(line) = todo.pop() {
let matches = lines[line];
todo.extend((line + 1)..(line + 1 + matches));
processed += 1;
}
processed
} }
helper::tests! { helper::tests! {
@ -62,8 +80,8 @@ helper::tests! {
default => 24733; default => 24733;
} }
part2 { part2 {
small => 0; small => 30;
default => 0; default => 5422730;
} }
} }
helper::benchmarks! {} helper::benchmarks! {}

31
2023/day04/src/p2cache.rs Normal file
View file

@ -0,0 +1,31 @@
pub fn part2(input: &str) -> u64 {
let lines = input
.lines()
.map(crate::line_match_count)
.collect::<Vec<_>>();
let mut cache = vec![0; lines.len()];
let mut processed = 0;
// By iterating backwards, we ensure the cache is always populated for every subsequent line.
for (i, result) in lines.iter().copied().enumerate().rev() {
let before = processed;
processed += 1; // Every card gives us one card.
// Now, let's see how many cards this card will expand to.
for expand in (i + 1)..((i + 1) + result) {
#[cfg(debug_assertions)]
eprintln!(
"{} expands to {} which is worth {}",
i + 1,
expand + 1,
cache[expand]
);
// Since the value is bigger than i, it must be cached!
processed += cache[expand];
}
cache[i] = processed - before;
}
processed
}

View file

@ -72,20 +72,20 @@ macro_rules! define_variants {
( (
day => $day:ty; day => $day:ty;
part1 { part1 {
$( $name1:ident => $func1:expr; )* $( $name1:ident => $func1:expr $(, sample_count=$sample_count1:expr)? ; )*
} }
part2 { part2 {
$( $name2:ident => $func2:expr; )* $( $name2:ident => $func2:expr $(, sample_count=$sample_count2:expr)? ; )*
} }
) => { ) => {
macro_rules! part1_variants { macro_rules! part1_variants {
($macro:ident) => { ($macro:ident) => {
$crate::$macro! { $day; $( ($name1, $func1) ),* } $crate::$macro! { $day; $( ($name1, $func1, [ $( sample_count=$sample_count1, )? ]) ),* }
}; };
} }
macro_rules! part2_variants { macro_rules! part2_variants {
($macro:ident) => { ($macro:ident) => {
$crate::$macro! { $day; $( ($name2, $func2) ),* } $crate::$macro! { $day; $( ($name2, $func2, [ $( sample_count=$sample_count2, )? ]) ),* }
}; };
} }
}; };
@ -93,7 +93,7 @@ macro_rules! define_variants {
#[macro_export] #[macro_export]
macro_rules! construct_variants { macro_rules! construct_variants {
( $day:ty; $( ($name:ident, $func:expr) ),*) => { ( $day:ty; $( ($name:ident, $func:expr, [ $($_:tt)* ]) ),*) => {
$crate::Variants { $crate::Variants {
variants: vec![$( variants: vec![$(
$crate::Variant::new(stringify!($name), $func) $crate::Variant::new(stringify!($name), $func)
@ -105,7 +105,6 @@ macro_rules! construct_variants {
#[macro_export] #[macro_export]
macro_rules! benchmarks { macro_rules! benchmarks {
() => { () => {
#[::divan::bench_group(sample_count = 10_000)]
mod bench { mod bench {
mod part1 { mod part1 {
part1_variants! { _define_benchmarks } part1_variants! { _define_benchmarks }
@ -122,15 +121,29 @@ macro_rules! benchmarks {
} }
#[macro_export] #[macro_export]
macro_rules! _define_benchmarks { macro_rules! _bench_sample_count {
($day:ty; $( ($name:ident, $func:expr) ),*) => { (;$($tt:tt)*) => {
$( #[::divan::bench(sample_count = 10_000)]
#[::divan::bench] $($tt)*
fn $name(bencher: ::divan::Bencher) { };
let input = include_str!("../input.txt"); ($sample_count:expr; $($tt:tt)*) => {
let input = <$day as $crate::Day>::pad_input(input); #[::divan::bench(sample_count = $sample_count)]
$($tt)*
};
}
bencher.with_inputs(|| input.as_ref()).bench_values($func); #[macro_export]
macro_rules! _define_benchmarks {
($day:ty; $( ($name:ident, $func:expr, [ $(sample_count=$sample_count:expr,)? ]) ),*) => {
$(
$crate::_bench_sample_count! {
$($sample_count)?;
fn $name(bencher: ::divan::Bencher) {
let input = include_str!("../input.txt");
let input = <$day as $crate::Day>::pad_input(input);
bencher.with_inputs(|| input.as_ref()).bench_values($func);
}
} }
)* )*
}; };