From 86a4ca331f4d07551e96e7c7a50ebb6db5538e60 Mon Sep 17 00:00:00 2001 From: Olivia Appleton Date: Thu, 11 Jul 2024 20:25:29 -0500 Subject: [PATCH] add final prime infrastructure --- rust/Cargo.lock | 16 +++++++ rust/Cargo.toml | 1 + rust/src/main.rs | 50 ++++++++++++++-------- rust/src/primes.rs | 104 ++++++++++++++++++++++++++------------------- 4 files changed, 110 insertions(+), 61 deletions(-) diff --git a/rust/Cargo.lock b/rust/Cargo.lock index f4589d10..c186ca65 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -23,6 +23,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "either" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" + [[package]] name = "equivalent" version = "1.0.1" @@ -146,6 +152,15 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + [[package]] name = "memchr" version = "2.7.4" @@ -260,6 +275,7 @@ dependencies = [ name = "rust" version = "0.1.0" dependencies = [ + "itertools", "rstest", "seq-macro", ] diff --git a/rust/Cargo.toml b/rust/Cargo.toml index d7c37765..256c37b4 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -4,5 +4,6 @@ version = "0.1.0" edition = "2021" [dependencies] +itertools = "0.13.0" rstest = "0.21.0" seq-macro = "0.3.5" diff --git a/rust/src/main.rs b/rust/src/main.rs index 8953b578..28cf7782 100644 --- a/rust/src/main.rs +++ b/rust/src/main.rs @@ -1,11 +1,13 @@ #[cfg(test)] use std::time::Duration; -// #[cfg(test)] -// use std::iter::zip; +#[cfg(test)] +use std::iter::zip; use seq_macro::seq; #[cfg(test)] use rstest::rstest; +#[cfg(test)] +use itertools::Itertools; seq!(N in 0001..=0002 { mod p~N; @@ -16,14 +18,15 @@ type ProblemType = fn() -> u64; type ProblemRef<'a> = (&'a str, ProblemType, u64); const ANSWERS: [ProblemRef; 2] = [ ("p0001", p0001::p0001, 233168), - ("p0002", p0002::p0002, 4613732) + ("p0002", p0002::p0002, 4613732), +// ("p0003", p0003::p0003, 6857), ]; fn main() { - // let sieve = primes::ModifiedEratosthenes::new().take(10); - // for i in sieve { - // println!("{}", i); - // } + let sieve = primes::Eratosthenes::new().take(10); + for i in sieve { + println!("{}", i); + } for (name, func, answer) in ANSWERS { let result = func(); println!("Problem {} should return {}. Returned {}!", name, answer, result); @@ -46,13 +49,26 @@ fn test_problem(#[case] idx: usize) -> Result<(), String> { }); -// #[cfg(test)] -// #[test] -// fn test_primes() -> Result<(), String> { -// let primes = [2, 3, 5, 7, 11, 13, 17, 19]; -// let sieve = primes::ModifiedEratosthenes::new().take(primes.len()); -// for (p, s) in zip(primes, sieve) { -// assert_eq!(p, s); -// } -// Ok(()) -// } +#[cfg(test)] +#[test] +fn test_primes() -> Result<(), String> { + let primes = [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113]; + let sieve = primes::Eratosthenes::new().take(primes.len()); + for (p, s) in zip(primes, sieve) { + assert_eq!(p, s); + } + Ok(()) +} + +#[cfg(test)] +#[test] +fn test_prime_factors() -> Result<(), String> { + for v in primes::Eratosthenes::new().take(15).combinations(2) { + let p = v[0]; + let s = v[1]; + for f in primes::PrimeFactors::new(p * s) { + assert!(f == p || f == s); + } + } + Ok(()) +} diff --git a/rust/src/primes.rs b/rust/src/primes.rs index e406495a..9829ae3e 100644 --- a/rust/src/primes.rs +++ b/rust/src/primes.rs @@ -1,66 +1,82 @@ use std::collections::HashMap; -pub struct ModifiedEratosthenes { - sieve: HashMap, +pub struct Eratosthenes { + sieve: HashMap>, prime: u64, candidate: u64, - recurse: Option> } -impl ModifiedEratosthenes { - pub fn new() -> ModifiedEratosthenes { - return ModifiedEratosthenes{ +impl Default for Eratosthenes { + fn default() -> Self { + return Eratosthenes{ sieve: HashMap::new(), prime: 0, candidate: 2, - recurse: None }; } } -impl Iterator for ModifiedEratosthenes { +impl Eratosthenes { + pub fn new() -> Eratosthenes { + return Default::default(); + } +} + +impl Iterator for Eratosthenes { type Item = u64; fn next(&mut self) -> Option { - if self.candidate == 2 { - self.candidate = 3; - self.prime = 3; - println!("Returning 2"); - return Some(2); - } - let mut candidate = self.candidate; - self.candidate += 2; - loop { - let prime_squared = self.prime * self.prime; - println!("Candidate: {}", candidate); - let step: u64; - if self.sieve.contains_key(&candidate) { - step = self.sieve.remove(&candidate)?; - println!("Candidate in cache as {}", step); - } - else if candidate < prime_squared { - println!("Candidate not in cache, but less than {}", prime_squared); - return Some(candidate); - } - else { - if candidate != prime_squared { - panic!("Something has gone wrong in the sieve"); + fn next_prime(sieve: &mut HashMap>, candidate: u64) -> u64 { + match sieve.get(&candidate) { + Some(numbers) => { + for num in numbers.to_owned() { + sieve + .entry(candidate + num) + .and_modify(|v| v.push(num)) + .or_insert_with(|| vec![num]); + } + sieve.remove(&candidate); + return next_prime(sieve, candidate + 1); } - step = self.prime * 2; - if self.recurse.is_none() { - self.recurse = Some(Box::new(ModifiedEratosthenes::new())); - let mut recursed = self.recurse.take()?; - let _ = (*recursed).next(); + None => { + sieve.insert(candidate * candidate, vec![candidate]); + return candidate; } - let mut recursed = self.recurse.take()?; - self.prime = ((*recursed).next())?; } - println!("This is the good part"); - candidate += step; - while self.sieve.contains_key(&candidate) { - candidate += step; + } + + self.prime = next_prime(&mut self.sieve, self.candidate); + self.candidate = self.prime + 1; // This number will be the next to be tested + + return Some(self.prime) + } +} + +pub struct PrimeFactors { + number: u64 +} + +impl PrimeFactors { + pub fn new(x: u64) -> PrimeFactors { + return PrimeFactors{ + number: x + }; + } +} + +impl Iterator for PrimeFactors { + type Item = u64; + + fn next(&mut self) -> Option { + for p in Eratosthenes::new() { + if self.number % p == 0 { + self.number = self.number / p; + return Some(p); + } + else if self.number < p { + break; } - self.sieve.insert(candidate, step); } + return None; } -} \ No newline at end of file +}