diff --git a/Cargo.lock b/Cargo.lock index fc7a1b5..945ff38 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -10,6 +10,7 @@ dependencies = [ "aoc-runner-derive", "faer", "itertools", + "microlp", ] [[package]] @@ -614,12 +615,32 @@ dependencies = [ "regex-automata", ] +[[package]] +name = "matrixmultiply" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06de3016e9fae57a36fd14dba131fccf49f74b40b7fbdb472f96e361ec71a08" +dependencies = [ + "autocfg", + "rawpointer", +] + [[package]] name = "memchr" version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" +[[package]] +name = "microlp" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d1790c73b93164ff65868f63164497cb32339458a9297e17e212d91df62258" +dependencies = [ + "log", + "sprs", +] + [[package]] name = "nano-gemm" version = "0.1.3" @@ -690,6 +711,21 @@ dependencies = [ "nano-gemm-core", ] +[[package]] +name = "ndarray" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c7c9125e8f6f10c9da3aad044cc918cf8784fa34de857b1aa68038eb05a50a9" +dependencies = [ + "matrixmultiply", + "num-complex", + "num-integer", + "num-traits", + "portable-atomic", + "portable-atomic-util", + "rawpointer", +] + [[package]] name = "npyz" version = "0.8.4" @@ -821,6 +857,21 @@ version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" +[[package]] +name = "portable-atomic" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" + +[[package]] +name = "portable-atomic-util" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507" +dependencies = [ + "portable-atomic", +] + [[package]] name = "ppv-lite86" version = "0.2.21" @@ -972,6 +1023,12 @@ dependencies = [ "bitflags", ] +[[package]] +name = "rawpointer" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" + [[package]] name = "rayon" version = "1.11.0" @@ -1135,6 +1192,18 @@ dependencies = [ "rayon", ] +[[package]] +name = "sprs" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dca58a33be2188d4edc71534f8bafa826e787cc28ca1c47f31be3423f0d6e55" +dependencies = [ + "ndarray", + "num-complex", + "num-traits", + "smallvec", +] + [[package]] name = "syn" version = "1.0.109" diff --git a/Cargo.toml b/Cargo.toml index 6f00b3c..edc1acf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,3 +9,4 @@ aoc-runner = "0.3.0" aoc-runner-derive = "0.3.0" itertools = "0.14.0" faer = "0.23" +microlp = "0.2.11" diff --git a/src/day10.rs b/src/day10.rs index 0def324..8193b19 100644 --- a/src/day10.rs +++ b/src/day10.rs @@ -1,18 +1,19 @@ -use std::collections::{HashMap, HashSet}; +use std::collections::HashMap; use itertools::Itertools; +use microlp::{ComparisonOp, OptimizationDirection, Problem, Variable}; #[aoc(day10, part1)] pub fn part1(input: &str) -> u32 { let machines = parse(input); - for machine in &machines { - println!( - "num buttons: {} num lights: {} diff: {}", - machine.buttons.len(), - machine.lights.len(), - machine.buttons.len() as i32 - machine.lights.len() as i32 - ); - } + // for machine in &machines { + // println!( + // "num buttons: {} num lights: {} diff: {}", + // machine.buttons.len(), + // machine.lights.len(), + // machine.buttons.len() as i32 - machine.lights.len() as i32 + // ); + // } machines.into_iter().map(|m| m.button_presses()).sum() } @@ -33,9 +34,31 @@ impl Machine { fn joltage_presses(self: Machine) -> u32 { // Method: Set up a linear set of equations A^Tx=b, where A contains // the coordinates of the buttons (one row per button) plus coordinates - // associated with optimisation parameters + // associated with optimisation parameters; or use a milp library :) + let mut problem = Problem::new(OptimizationDirection::Minimize); + let vars: Vec = (0..self.buttons.len()) + .map(|_| problem.add_integer_var(1.0, (0, *self.joltage.iter().max().unwrap() as i32))) + .collect(); - 0 + for (i, joltage) in self.joltage.iter().enumerate() { + problem.add_constraint( + vars.iter() + .zip(&self.buttons) + .map(|(var, button)| (*var, button.contains(&(i as u32)) as i32 as f64)) + .collect::>(), + ComparisonOp::Eq, + *joltage as f64, + ); + } + + println!("{:?}", problem); + + problem + .solve() + .unwrap() + .iter() + .map(|(_, value)| value.round() as u32) + .sum() } fn button_presses(self: Machine) -> u32 { diff --git a/src/lib.rs b/src/lib.rs index 5d78afe..8b290fd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,10 +4,10 @@ extern crate aoc_runner; extern crate aoc_runner_derive; pub mod day1; -pub mod day2; -// pub mod day10; +pub mod day10; pub mod day11; pub mod day12; +pub mod day2; pub mod day3; pub mod day4; pub mod day5;