From efaaef4e6a2d9116f499e7b441084d94f540f48a Mon Sep 17 00:00:00 2001 From: Joscha Date: Fri, 16 Dec 2022 14:39:13 +0100 Subject: [PATCH] [rs] Parallelize 2022_16 part 2 --- rs/Cargo.lock | 120 +++++++++++++++++++++++++++++++++++++++++- rs/Cargo.toml | 1 + rs/src/y2022/d16.rs | 125 ++++++++++++++++++++++++++------------------ 3 files changed, 193 insertions(+), 53 deletions(-) diff --git a/rs/Cargo.lock b/rs/Cargo.lock index 554d55b..12dce09 100644 --- a/rs/Cargo.lock +++ b/rs/Cargo.lock @@ -7,8 +7,15 @@ name = "aoc-rs" version = "0.0.0" dependencies = [ "clap", + "rayon", ] +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + [[package]] name = "bitflags" version = "1.3.2" @@ -21,6 +28,12 @@ version = "1.0.77" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e9f73505338f7d905b19d18738976aae232eb46b8efc15554ffc56deb5d9ebe4" +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + [[package]] name = "clap" version = "4.0.29" @@ -58,6 +71,55 @@ dependencies = [ "os_str_bytes", ] +[[package]] +name = "crossbeam-channel" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2dd04ddaf88237dc3b8d8f9a3c1004b506b54b3313403944054d23c0870c521" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "715e8152b692bba2d374b53d4875445368fdf21a94751410af607a5ac677d1fc" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01a9af1f4c2ef74bb8aa1f7e19706bc72d03598c8a570bb5de72243c7a9d9d5a" +dependencies = [ + "autocfg", + "cfg-if", + "crossbeam-utils", + "memoffset", + "scopeguard", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb766fa798726286dbbb842f174001dab8abc7b627a1dd86e0b7222a95d929f" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "either" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90e5c1c8368803113bf0c9584fc495a58b86dc8a29edbf8fe877d21d9507e797" + [[package]] name = "errno" version = "0.2.8" @@ -85,6 +147,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9" +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + [[package]] name = "hermit-abi" version = "0.2.6" @@ -110,7 +181,7 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "927609f78c2913a6f6ac3c27a4fe87f43e2a35367c0c4b0f8265e8f49a104330" dependencies = [ - "hermit-abi", + "hermit-abi 0.2.6", "io-lifetimes", "rustix", "windows-sys", @@ -128,6 +199,25 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f9f08d8963a6c613f4b1a78f4f4a4dbfadf8e6545b2d72861731e4858b8b47f" +[[package]] +name = "memoffset" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6058e64324c71e02bc2b150e4f3bc8286db6c83092132ffa3f6b1eab0f9def5" +dependencies = [ + "hermit-abi 0.1.19", + "libc", +] + [[package]] name = "once_cell" version = "1.16.0" @@ -182,6 +272,28 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rayon" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6db3a213adf02b3bcfd2d3846bb41cb22857d131789e01df434fb7e7bc0759b7" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cac410af5d00ab6884528b4ab69d1e8e146e8d471201800fa1b4524126de6ad3" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-utils", + "num_cpus", +] + [[package]] name = "rustix" version = "0.36.4" @@ -196,6 +308,12 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + [[package]] name = "strsim" version = "0.10.0" diff --git a/rs/Cargo.toml b/rs/Cargo.toml index 696a912..04d3f0c 100644 --- a/rs/Cargo.toml +++ b/rs/Cargo.toml @@ -5,3 +5,4 @@ edition = "2021" [dependencies] clap = { version = "4.0.29", features = ["derive", "deprecated"] } +rayon = "1.6.1" diff --git a/rs/src/y2022/d16.rs b/rs/src/y2022/d16.rs index f821180..f2b58da 100644 --- a/rs/src/y2022/d16.rs +++ b/rs/src/y2022/d16.rs @@ -1,6 +1,10 @@ use std::collections::HashMap; use std::mem; +use rayon::prelude::{ + IndexedParallelIterator, IntoParallelRefIterator, IntoParallelRefMutIterator, ParallelIterator, +}; + fn parse_valve(line: &str) -> (&str, u32, Vec<&str>) { let (name, rest) = line .strip_prefix("Valve ") @@ -168,15 +172,57 @@ impl Dp2 { let id = self.powers * (self.valves * own_id + el_id) + open.0 as usize; self.elems[id] } +} - fn set(&mut self, own_id: usize, el_id: usize, open: OpenSet, score: u32) { - let id = self.powers * (self.valves * own_id + el_id) + open.0 as usize; - self.elems[id] = score; +fn part_2_score( + minute: u32, + prev: &Dp2, + own_id: usize, + own_valve: &Valve, + el_id: usize, + el_valve: &Valve, + open: OpenSet, +) -> u32 { + let mut score = 0; + + // Both move + for own_next in &own_valve.next { + for el_next in &el_valve.next { + score = score.max(prev.get(*own_next, *el_next, open)); + } } - fn clear(&mut self) { - self.elems.fill(0); + // I open valve + let i_can_open = own_valve.rate > 0 && !open.is_open(own_id); + if i_can_open { + let open = open.open(own_id); + for el_next in &el_valve.next { + let room_but_valve_open = prev.get(own_id, *el_next, open); + let pressure_until_end = (minute - 1) * own_valve.rate; + score = score.max(room_but_valve_open + pressure_until_end); + } } + + // Elephant opens valve + let el_can_open = el_valve.rate > 0 && !open.is_open(el_id); + if el_can_open { + let open = open.open(el_id); + for own_next in &own_valve.next { + let room_but_valve_open = prev.get(*own_next, el_id, open); + let pressure_until_end = (minute - 1) * el_valve.rate; + score = score.max(room_but_valve_open + pressure_until_end); + } + } + + // Both open valve + if own_id != el_id && i_can_open && el_can_open { + let open = open.open(own_id).open(el_id); + let room_but_valves_open = prev.get(own_id, el_id, open); + let pressure_until_end = (minute - 1) * (own_valve.rate + el_valve.rate); + score = score.max(room_but_valves_open + pressure_until_end); + } + + score } fn solve_part_2(names: &HashMap<&str, usize>, valves: &[Valve], powerset: &[OpenSet]) -> u32 { @@ -194,58 +240,33 @@ fn solve_part_2(names: &HashMap<&str, usize>, valves: &[Valve], powerset: &[Open // - I open valve, elephant moves // - I open valve, elephant opens valve (if not in same room) + let mut variations = vec![]; + for (own_id, own_valve) in valves.iter().enumerate() { + for (el_id, el_valve) in valves.iter().enumerate() { + for open in powerset { + variations.push((own_id, own_valve, el_id, el_valve, open)); + } + } + } + + // Just to check whether the variations are in the correct order because I'm + // zipping them to curr.elems later. + for (i, (own_id, _, el_id, _, open)) in variations.iter().enumerate() { + let id = curr.powers * (curr.valves * own_id + el_id) + open.0 as usize; + assert_eq!(i, id); + } + for minute in 1..=26 { eprintln!("Minute {minute}"); mem::swap(&mut curr, &mut prev); - curr.clear(); - for (own_id, own_valve) in valves.iter().enumerate() { - for (el_id, el_valve) in valves.iter().enumerate() { - for open in powerset { - let mut score = 0; - - // Both move - for own_next in &own_valve.next { - for el_next in &el_valve.next { - score = score.max(prev.get(*own_next, *el_next, *open)); - } - } - - // I open valve - let i_can_open = own_valve.rate > 0 && !open.is_open(own_id); - if i_can_open { - let open = open.open(own_id); - for el_next in &el_valve.next { - let room_but_valve_open = prev.get(own_id, *el_next, open); - let pressure_until_end = (minute - 1) * own_valve.rate; - score = score.max(room_but_valve_open + pressure_until_end); - } - } - - // Elephant opens valve - let el_can_open = el_valve.rate > 0 && !open.is_open(el_id); - if el_can_open { - let open = open.open(el_id); - for own_next in &own_valve.next { - let room_but_valve_open = prev.get(*own_next, el_id, open); - let pressure_until_end = (minute - 1) * el_valve.rate; - score = score.max(room_but_valve_open + pressure_until_end); - } - } - - // Both open valve - if own_id != el_id && i_can_open && el_can_open { - let open = open.open(own_id).open(el_id); - let room_but_valves_open = prev.get(own_id, el_id, open); - let pressure_until_end = (minute - 1) * (own_valve.rate + el_valve.rate); - score = score.max(room_but_valves_open + pressure_until_end); - } - - curr.set(own_id, el_id, *open, score); - } - } - } + curr.elems + .par_iter_mut() + .zip(variations.par_iter()) + .for_each(|(score, (own_id, own_valve, el_id, el_valve, open))| { + *score = part_2_score(minute, &prev, *own_id, own_valve, *el_id, el_valve, **open); + }); } curr.get(names["AA"], names["AA"], OpenSet::ALL_CLOSED)