diff --git a/.cargo/config.toml b/.cargo/config.toml new file mode 100644 index 0000000..5474bc4 --- /dev/null +++ b/.cargo/config.toml @@ -0,0 +1,2 @@ +[build] +rustflags = ["-Ctarget-cpu=native"] \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 356992e..e757392 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -25,15 +25,80 @@ checksum = "0942ffc6dcaadf03badf6e6a2d0228460359d5e34b57ccdc720b7382dfbd5ec5" name = "aoc-2023" version = "0.1.0" dependencies = [ + "astro_nalgebra", + "nalgebra", "rustworkx-core", ] +[[package]] +name = "approx" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cab112f0a86d568ea0e627cc1d6be74a1e9cd55214684db5561995f6dad897c6" +dependencies = [ + "num-traits", +] + +[[package]] +name = "astro-float" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3fb35913818db18bedc81d292953fa0ecc0da3370753bb39c93251f19481f87" +dependencies = [ + "astro-float-macro", + "astro-float-num", +] + +[[package]] +name = "astro-float-macro" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a94bc6994ab6dd5dd03e66a7aa8247a411670dbc56363309151a82cbf2163ee" +dependencies = [ + "astro-float-num", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "astro-float-num" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d79d1a2f9821df68fbac2d59bdf24a8b7563a5ca5c88164edd60bbb4d7f6a306" +dependencies = [ + "itertools", + "lazy_static", + "rand", + "serde", +] + +[[package]] +name = "astro_nalgebra" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92d7023b1596370903f4f988be0fd05386777c2a4e9f56409a0eac8f1da66aab" +dependencies = [ + "approx", + "astro-float", + "nalgebra", + "num-traits", + "serde", + "simba", +] + [[package]] name = "autocfg" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "bytemuck" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "374d28ec25809ee0e23827c2ab573d729e293f281dfe393500e7ad618baa61c6" + [[package]] name = "cfg-if" version = "1.0.0" @@ -147,12 +212,85 @@ dependencies = [ "either", ] +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + [[package]] name = "libc" version = "0.2.151" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "302d7ab3130588088d277783b1e2d2e10c9e9e4a16dd9050e6ec93fb3e7048f4" +[[package]] +name = "matrixmultiply" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7574c1cf36da4798ab73da5b215bbf444f50718207754cb522201d78d1cd0ff2" +dependencies = [ + "autocfg", + "rawpointer", +] + +[[package]] +name = "nalgebra" +version = "0.32.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "307ed9b18cc2423f29e83f84fd23a8e73628727990181f18641a8b5dc2ab1caa" +dependencies = [ + "approx", + "matrixmultiply", + "nalgebra-macros", + "num-complex", + "num-rational", + "num-traits", + "simba", + "typenum", +] + +[[package]] +name = "nalgebra-macros" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91761aed67d03ad966ef783ae962ef9bbaca728d2dd7ceb7939ec110fffad998" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "num-complex" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ba157ca0885411de85d6ca030ba7e2a83a28636056c7c699b07c8b6f7383214" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0638a1c9d0a3c0914158145bc76cff373a75a627e6ecbfb71cbe6f453a5a19b0" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.17" @@ -168,6 +306,12 @@ version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +[[package]] +name = "paste" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" + [[package]] name = "petgraph" version = "0.6.4" @@ -196,18 +340,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.73" +version = "1.0.74" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dd5e8a1f1029c43224ad5898e50140c2aebb1705f19e67c918ebf5b9e797fe1" +checksum = "2de98502f212cfcea8d0bb305bd0f49d7ebdd75b64ba0a68f937d888f4e0d6db" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.34" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22a37c9326af5ed140c86a46655b5278de879853be5573c01df185b6f49a580a" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ "proc-macro2", ] @@ -251,6 +395,12 @@ dependencies = [ "rand_core", ] +[[package]] +name = "rawpointer" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" + [[package]] name = "rayon" version = "1.8.0" @@ -301,17 +451,76 @@ dependencies = [ "rayon-cond", ] +[[package]] +name = "safe_arch" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f398075ce1e6a179b46f51bd88d0598b92b00d3551f1a2d4ac49e771b56ac354" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "serde" +version = "1.0.194" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b114498256798c94a0689e1a15fec6005dee8ac1f41de56404b67afc2a4b773" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.194" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3385e45322e8f9931410f01b3031ec534c3947d0e94c18049af4d9f9907d4e0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.46", +] + +[[package]] +name = "simba" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "061507c94fc6ab4ba1c9a0305018408e312e17c041eb63bef8aa726fa33aceae" +dependencies = [ + "approx", + "num-complex", + "num-traits", + "paste", + "wide", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "syn" -version = "2.0.45" +version = "2.0.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eae3c679c56dc214320b67a1bc04ef3dfbd6411f6443974b5e4893231298e66" +checksum = "89456b690ff72fddcecf231caedbe615c59480c93358a93dfae7fc29e3ebbf0e" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + [[package]] name = "unicode-ident" version = "1.0.12" @@ -330,6 +539,16 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wide" +version = "0.7.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c68938b57b33da363195412cfc5fc37c9ed49aa9cfe2156fde64b8d2c9498242" +dependencies = [ + "bytemuck", + "safe_arch", +] + [[package]] name = "zerocopy" version = "0.7.32" @@ -347,5 +566,5 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.46", ] diff --git a/Cargo.toml b/Cargo.toml index a10a4b8..9c47654 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,4 +14,6 @@ overflow-checks = true lto = "fat" [dependencies] -rustworkx-core = "0.13" \ No newline at end of file +rustworkx-core = "0.13" +nalgebra = "0.32" +astro_nalgebra = "0.1" \ No newline at end of file diff --git a/aoc-py/solutions/day24.py b/aoc-py/solutions/day24.py index 12aea94..f4dfedd 100644 --- a/aoc-py/solutions/day24.py +++ b/aoc-py/solutions/day24.py @@ -174,7 +174,9 @@ def part_two_linalg(self, inp: str) -> int: hs1.z_pos * hs1.y_vel - hs3.z_pos * hs3.y_vel - (hs1.y_pos * hs1.z_vel - hs3.y_pos * hs3.z_vel), ]) - return round(sum(np.linalg.solve(a, b)[:3])) # type: ignore (`solve` function is not known) + return round( + sum(np.linalg.solve(a, b)[:3]) # type: ignore (`solve` function is not known) + ) def part_two(self, inp: str) -> int: """Part 2 solved using z3-solver""" diff --git a/src/bin/day24.rs b/src/bin/day24.rs index d70ff54..19e4d61 100644 --- a/src/bin/day24.rs +++ b/src/bin/day24.rs @@ -1,4 +1,4 @@ -//! Day 24: Step Counter +//! Day 24: Never Tell Me The Odds //! //! use std::{ @@ -7,6 +7,13 @@ use std::{ }; use aoc_2023::Solution; +use astro_nalgebra::{ + num_traits::Zero, + BigFloat, + ConstCtx, +}; +use nalgebra::{Matrix6, Matrix6x1}; + #[derive(Debug, Clone, PartialEq, Eq)] struct ParseHailstoneError; @@ -20,65 +27,88 @@ struct Hailstone { z_vel: f64, } +type BF1024 = BigFloat>; + +#[derive(Debug, Clone, PartialEq)] +struct BFHailstone { + x_pos: BF1024, + y_pos: BF1024, + z_pos: BF1024, + x_vel: BF1024, + y_vel: BF1024, + z_vel: BF1024, +} + macro_rules! parse_part { - ($parts:expr) => { + ($parts:expr, $target_ty:ty) => { $parts .next() .and_then(|raw| raw .trim() - .parse::() + .parse::<$target_ty>() .ok() ) .ok_or(ParseHailstoneError)? } } -#[inline] -fn float_cmp(a: f64, b: f64) -> bool { - (a - b).abs() < f64::EPSILON -} - -impl FromStr for Hailstone { - type Err = ParseHailstoneError; +macro_rules! impl_from_str { + ($struct_ty:ty, $field_ty:ty) => { + impl FromStr for $struct_ty { + type Err = ParseHailstoneError; - fn from_str(raw: &str) -> Result { - let (pos, vel) = raw - .split_once('@') - .ok_or(ParseHailstoneError)?; - let mut pos = pos.split(','); - let mut vel = vel.split(','); + fn from_str(raw: &str) -> Result { + let (pos, vel) = raw + .split_once('@') + .ok_or(ParseHailstoneError)?; + let mut pos = pos.split(','); + let mut vel = vel.split(','); - Ok(Self { - x_pos: parse_part!(pos), - y_pos: parse_part!(pos), - z_pos: parse_part!(pos), + Ok(Self { + x_pos: parse_part!(pos, $field_ty), + y_pos: parse_part!(pos, $field_ty), + z_pos: parse_part!(pos, $field_ty), - x_vel: parse_part!(vel), - y_vel: parse_part!(vel), - z_vel: parse_part!(vel), - }) + x_vel: parse_part!(vel, $field_ty), + y_vel: parse_part!(vel, $field_ty), + z_vel: parse_part!(vel, $field_ty), + }) + } + } } } +impl_from_str!(Hailstone, f64); +impl_from_str!(BFHailstone, BF1024); + +#[inline] +fn float_cmp(a: f64, b: f64) -> bool { + (a - b).abs() < f64::EPSILON +} + impl Hailstone { #[inline] + #[must_use] fn m(&self) -> f64 { self.y_vel / self.x_vel } #[inline] + #[must_use] fn b(&self) -> f64 { self.m() .mul_add(-self.x_pos, self.y_pos) } #[inline] + #[must_use] fn evaluate(&self, x: f64) -> f64 { self.m() .mul_add(x, self.b()) } #[inline] + #[must_use] fn in_domain(&self, x: f64, y: f64) -> bool { (if self.x_vel > 0.0 { x >= self.x_pos @@ -97,6 +127,7 @@ impl Hailstone { } #[inline] + #[must_use] fn intersection(&self, other: &Self) -> Option<(f64, f64)> { let m_diff = self.m() - other.m(); (m_diff != 0.0) @@ -128,8 +159,10 @@ impl Day24 { .map(|(x, y)| hs1.in_domain(x, y) && hs2.in_domain(x, y) - && (200_000_000_000_000.0..=400_000_000_000_000.0).contains(&x) - && (200_000_000_000_000.0..=400_000_000_000_000.0).contains(&y) + && (200_000_000_000_000.0..=400_000_000_000_000.0) + .contains(&x) + && (200_000_000_000_000.0..=400_000_000_000_000.0) + .contains(&y) ) .unwrap_or_default() ) @@ -137,13 +170,89 @@ impl Day24 { .count() } - pub fn part_two(&self, _inp: T) -> usize { - 0 + pub fn part_two(&self, inp: T) -> usize { + let inp = inp.to_string(); + let mut hailstones = inp + .lines() + .take(3) + .filter_map(|line| line.parse::().ok()); + + let hs1 = hailstones + .next() + .unwrap(); + let hs2 = hailstones + .next() + .unwrap(); + let hs3 = hailstones + .next() + .unwrap(); + + let a = Matrix6::new( + hs2.y_vel.clone() - hs1.y_vel.clone(), + hs1.x_vel.clone() - hs2.x_vel.clone(), BF1024::zero(), + hs1.y_pos.clone() - hs2.y_pos.clone(), + hs2.x_pos.clone() - hs1.x_pos.clone(), BF1024::zero(), + hs3.y_vel.clone() - hs1.y_vel.clone(), + hs1.x_vel.clone() - hs3.x_vel.clone(), BF1024::zero(), + hs1.y_pos.clone() - hs3.y_pos.clone(), + hs3.x_pos.clone() - hs1.x_pos.clone(), BF1024::zero(), + hs2.z_vel.clone() - hs1.z_vel.clone(), BF1024::zero(), + hs1.x_vel.clone() - hs2.x_vel.clone(), + hs1.z_pos.clone() - hs2.z_pos.clone(), BF1024::zero(), + hs2.x_pos.clone() - hs1.x_pos.clone(), + hs3.z_vel.clone() - hs1.z_vel.clone(), BF1024::zero(), + hs1.x_vel.clone() - hs3.x_vel.clone(), + hs1.z_pos.clone() - hs3.z_pos.clone(), BF1024::zero(), + hs3.x_pos.clone() - hs1.x_pos.clone(), + BF1024::zero(), hs2.z_vel.clone() - hs1.z_vel.clone(), + hs1.y_vel.clone() - hs2.y_vel.clone(), BF1024::zero(), + hs1.z_pos.clone() - hs2.z_pos.clone(), + hs2.y_pos.clone() - hs1.y_pos.clone(), + BF1024::zero(), hs3.z_vel.clone() - hs1.z_vel.clone(), + hs1.y_vel.clone() - hs3.y_vel.clone(), BF1024::zero(), + hs1.z_pos.clone() - hs3.z_pos.clone(), + hs3.y_pos.clone() - hs1.y_pos.clone(), + ); + + let b = Matrix6x1::new( + hs1.y_pos.clone() * hs1.x_vel.clone() - hs2.y_pos.clone() * hs2.x_vel.clone() + - (hs1.x_pos.clone() * hs1.y_vel.clone() - hs2.x_pos.clone() * hs2.y_vel.clone()), + + hs1.y_pos.clone() * hs1.x_vel.clone() - hs3.y_pos.clone() * hs3.x_vel.clone() + - (hs1.x_pos.clone() * hs1.y_vel.clone() - hs3.x_pos.clone() * hs3.y_vel.clone()), + + hs1.z_pos.clone() * hs1.x_vel.clone() - hs2.z_pos.clone() * hs2.x_vel + - (hs1.x_pos.clone() * hs1.z_vel.clone() - hs2.x_pos * hs2.z_vel.clone()), + + hs1.z_pos.clone() * hs1.x_vel - hs3.z_pos.clone() * hs3.x_vel + - (hs1.x_pos * hs1.z_vel.clone() - hs3.x_pos * hs3.z_vel.clone()), + + hs1.z_pos.clone() * hs1.y_vel.clone() - hs2.z_pos * hs2.y_vel + - (hs1.y_pos.clone() * hs1.z_vel.clone() - hs2.y_pos * hs2.z_vel), + + hs1.z_pos * hs1.y_vel - hs3.z_pos * hs3.y_vel + - (hs1.y_pos * hs1.z_vel - hs3.y_pos * hs3.z_vel), + ); + + a + .try_inverse() + .map(|a_inverse| { + let result = a_inverse * b; + + (result[0] + .as_f64() + + result[1] + .as_f64() + + result[2] + .as_f64() + ) as usize + }) + .unwrap() } } impl Solution for Day24 { - const NAME: &'static str = "Step Counter"; + const NAME: &'static str = "Never Tell Me The Odds"; fn run(&self, inp: String) { let p1 = self.part_one(&inp); diff --git a/src/bin/day25.rs b/src/bin/day25.rs index 6b353c8..d8be72a 100644 --- a/src/bin/day25.rs +++ b/src/bin/day25.rs @@ -13,7 +13,7 @@ pub struct Day25; impl Day25 { /// # Panics /// - /// If failed to parse line + /// If failed to parse input lines pub fn part_one(&self, inp: T) -> usize { let mut graph = GraphMap::new(); let inp = inp @@ -38,7 +38,7 @@ impl Day25 { size_1 * size_2 } else { - panic!("Could not perform a minimum cut on the graph"); + panic!("Could not perform a minimum cut on the graph") } } diff --git a/src/bin/day5.rs b/src/bin/day5.rs index 3772cd4..408ff6d 100644 --- a/src/bin/day5.rs +++ b/src/bin/day5.rs @@ -38,7 +38,7 @@ impl Day5 { .unwrap(); (src_start..src_start + range, dest_start - src_start) }) - .collect::>() + .collect::, i64)>>() } /// # Panics