Skip to content

Commit

Permalink
Make prime infrastructure generic
Browse files Browse the repository at this point in the history
  • Loading branch information
LivInTheLookingGlass committed Jul 14, 2024
1 parent 2330d42 commit 26ed5d7
Show file tree
Hide file tree
Showing 5 changed files with 71 additions and 54 deletions.
26 changes: 13 additions & 13 deletions docs/rust/primes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ primes.rs

View source code `here on GitHub! <https://github.com/LivInTheLookingGlass/Euler/blob/master/rust/src/primes.rs>`_

.. rust:fn:: primes::primes() -> Eratosthenes
.. rust:fn:: primes::primes<I>() -> Eratosthenes<I>
A convenience method that returns an iterator over the prime numbers.

.. rust:fn:: primes::primes_until(x: u64) -> Eratosthenes
.. rust:fn:: primes::primes_until<I>(x: I) -> Eratosthenes<I>
A convenience method that returns an iterator over the prime numbers until a given limit.

.. rust:struct:: primes::Eratosthenes
.. rust:struct:: primes::Eratosthenes<I>
This class implements the `Sieve of Eratosthenes <https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes>`_. In general,
it will iterate over all of the prime numbers. You can also provide an optional ``limit`` argument, which will force
Expand All @@ -21,34 +21,34 @@ View source code `here on GitHub! <https://github.com/LivInTheLookingGlass/Euler
.. image:: https://upload.wikimedia.org/wikipedia/commons/9/94/Animation_Sieve_of_Eratosth.gif
:alt: Any animated example of the Sieve of Eratosthenes

.. rust:fn:: primes::Eratosthenes::new() -> Eratosthenes
.. rust:fn:: primes::Eratosthenes::new() -> Eratosthenes<I>
.. rust:fn:: primes::Eratosthenes::with_limit(limit: u64) -> Eratosthenes
.. rust:fn:: primes::Eratosthenes::with_limit(limit: I) -> Eratosthenes<I>
.. rust:fn:: primes::Eratosthenes::next() -> Option<u64>
.. rust:fn:: primes::Eratosthenes::next() -> Option<I>
.. rust:fn:: primes::prime_factors(x: u64) -> PrimeFactors
.. rust:fn:: primes::prime_factors<I>(x: I) -> PrimeFactors<I>
A convenience method that returns an iterator over the prime factors of a given number.

.. rust:struct:: primes::PrimeFactors
.. rust:struct:: primes::PrimeFactors<I>
This class will iterate over all the prime factors of a number. It *only* supports positive integers. To find the
factors of a negative number, iterate over the prime factors of its absolute value and add ``-1`` as a factor manually.

.. rust:fn:: primes::PrimeFactors::new(x: u64) -> PrimeFactors
.. rust:fn:: primes::PrimeFactors::new(x: I) -> PrimeFactors<I>
.. rust:fn:: primes::PrimeFactors::next() -> Option<u64>
.. rust:fn:: primes::PrimeFactors::next() -> Option<I>
.. rust:fn:: primes::proper_divisors(x: u64) -> Vec<u64>
.. rust:fn:: primes::proper_divisors<I>(x: I) -> Vec<I>
This function returns a vector of the proper divisors of a number.

.. rust:fn:: fn is_composite(x: u64) -> u64
.. rust:fn:: fn is_composite<I>(x: I) -> I
Returns ``0`` if the number is prime, and the smallest prime factor otherwise.

.. rust:fn:: fn is_prime(x: u64) -> bool
.. rust:fn:: fn is_prime<I>(x: I) -> bool
Returns ``true`` if the number is prime, and ``false`` otherwise.

Expand Down
10 changes: 10 additions & 0 deletions rust/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions rust/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ edition = "2021"

[dependencies]
itertools = "0.13.0"
num-traits = "0.2.19"
rstest = "0.21.0"
seq-macro = "0.3.5"
6 changes: 3 additions & 3 deletions rust/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const ANSWERS: [ProblemRef; 4] = [
];

fn main() {
let sieve = primes::primes().take(10);
let sieve = primes::primes::<u64>().take(10);
for i in sieve {
println!("{}", i);
}
Expand Down Expand Up @@ -55,7 +55,7 @@ fn test_problem(#[case] idx: usize) -> Result<(), String> {
#[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::primes().take(primes.len());
let sieve = primes::primes::<u32>().take(primes.len());
for (p, s) in zip(primes, sieve) {
assert_eq!(p, s);
}
Expand All @@ -65,7 +65,7 @@ fn test_primes() -> Result<(), String> {
#[cfg(test)]
#[test]
fn test_prime_factors() -> Result<(), String> {
for v in primes::primes_until(256).combinations(2) {
for v in primes::primes_until::<u32>(256).combinations(2) {
let p = v[0];
let s = v[1];
assert!(primes::is_prime(p));
Expand Down
82 changes: 44 additions & 38 deletions rust/src/primes.rs
Original file line number Diff line number Diff line change
@@ -1,43 +1,49 @@
use std::collections::HashMap;
use std::cmp::PartialOrd;
use std::hash::Hash;

use num_traits::NumAssign;
use num_traits::Bounded;
use num_traits::zero;
use num_traits::one;
use itertools::Itertools;

pub struct Eratosthenes {
sieve: HashMap<u64, Vec<u64>>,
prime: u64,
candidate: u64,
limit: u64,
pub struct Eratosthenes<I: NumAssign + Bounded + PartialOrd + Eq + Hash + Copy> {
sieve: HashMap<I, Vec<I>>,
prime: I,
candidate: I,
limit: I,
}

impl Default for Eratosthenes {
impl<I: NumAssign + Bounded + PartialOrd + Eq + Hash + Copy> Default for Eratosthenes<I> {
fn default() -> Self {
return Eratosthenes{
return Eratosthenes::<I>{
sieve: HashMap::new(),
prime: 0,
candidate: 2,
limit: u64::MAX,
prime: zero::<I>(),
candidate: one::<I>() + one(),
limit: I::max_value(),
};
}
}

impl Eratosthenes {
pub fn new() -> Eratosthenes {
impl<I: NumAssign + Bounded + PartialOrd + Eq + Hash + Copy> Eratosthenes<I> {

Check warning

Code scanning / clippy

associated function with_limit is never used Warning

associated function with\_limit is never used
pub fn new() -> Eratosthenes<I> {
return Default::default();
}

pub fn with_limit(limit: u64) -> Eratosthenes {
pub fn with_limit(limit: I) -> Eratosthenes<I> {

Check warning

Code scanning / clippy

associated function with_limit is never used Warning

associated function with\_limit is never used
return Eratosthenes{
limit,
..Default::default()
};
}
}

impl Iterator for Eratosthenes {
type Item = u64;
impl<I: NumAssign + Bounded + PartialOrd + Eq + Hash + Copy> Iterator for Eratosthenes<I> {
type Item = I;

fn next(&mut self) -> Option<Self::Item> {
fn next_prime(sieve: &mut HashMap<u64, Vec<u64>>, candidate: u64) -> u64 {
fn next_prime<I: NumAssign + Bounded + PartialOrd + Eq + Hash + Copy>(sieve: &mut HashMap<I, Vec<I>>, candidate: I) -> I {
match sieve.get(&candidate) {
Some(numbers) => {
for num in numbers.to_owned() {
Expand All @@ -47,7 +53,7 @@ impl Iterator for Eratosthenes {
.or_insert_with(|| vec![num]);
}
sieve.remove(&candidate);
return next_prime(sieve, candidate + 1);
return next_prime(sieve, candidate + one::<I>());
}
None => {
sieve.insert(candidate * candidate, vec![candidate]);
Expand All @@ -56,8 +62,8 @@ impl Iterator for Eratosthenes {
}
}

self.prime = next_prime(&mut self.sieve, self.candidate);
self.candidate = self.prime + 1; // This number will be the next to be tested
self.prime = next_prime::<I>(&mut self.sieve, self.candidate);
self.candidate = self.prime + one();

if self.prime > self.limit {
return None;
Expand All @@ -66,32 +72,32 @@ impl Iterator for Eratosthenes {
}
}

pub fn primes() -> Eratosthenes {
pub fn primes<I: NumAssign + Bounded + PartialOrd + Eq + Hash + Copy>() -> Eratosthenes<I> {
return Eratosthenes::new();
}

pub fn primes_until(x: u64) -> Eratosthenes {
pub fn primes_until<I: NumAssign + Bounded + PartialOrd + Eq + Hash + Copy>(x: I) -> Eratosthenes<I> {

Check warning

Code scanning / clippy

function primes_until is never used Warning

function primes\_until is never used
return Eratosthenes::with_limit(x);
}

pub struct PrimeFactors {
number: u64
pub struct PrimeFactors<I: NumAssign + Bounded + PartialOrd + Eq + Hash + Copy> {
number: I
}

impl PrimeFactors {
pub fn new(x: u64) -> PrimeFactors {
impl<I: NumAssign + Bounded + PartialOrd + Eq + Hash + Copy> PrimeFactors<I> {
pub fn new(x: I) -> PrimeFactors<I> {
return PrimeFactors{
number: x
};
}
}

impl Iterator for PrimeFactors {
type Item = u64;
impl<I: NumAssign + Bounded + PartialOrd + Eq + Hash + Copy> Iterator for PrimeFactors<I> {
type Item = I;

fn next(&mut self) -> Option<Self::Item> {
for p in Eratosthenes::new() {
if self.number % p == 0 {
if self.number % p == zero() {
self.number /= p;
return Some(p);
}
Expand All @@ -103,38 +109,38 @@ impl Iterator for PrimeFactors {
}
}

pub fn prime_factors(x: u64) -> PrimeFactors {
pub fn prime_factors<I: NumAssign + Bounded + PartialOrd + Eq + Hash + Copy>(x: I) -> PrimeFactors<I> {
return PrimeFactors::new(x);
}

pub fn proper_divisors(x: u64) -> Vec<u64> {
let mut ret: Vec<u64> = vec![];
let factors: Vec<u64> = PrimeFactors::new(x).collect();
pub fn proper_divisors<I: NumAssign + Bounded + Ord + Eq + Hash + Copy>(x: I) -> Vec<I> {

Check warning

Code scanning / clippy

function proper_divisors is never used Warning

function proper\_divisors is never used
let mut ret: Vec<I> = vec![];
let factors: Vec<I> = PrimeFactors::new(x).collect();
ret.extend(factors.clone());
for i in 2..(factors.len()) {
for v in factors.iter().combinations(i) {
ret.push(v.into_iter().product());
ret.push(v.into_iter().fold(one(), |x, y| x * (*y)));
}
}
ret.sort();
ret.dedup();
return ret;
}

pub fn is_composite(x: u64) -> u64 {
pub fn is_composite<I: NumAssign + Bounded + PartialOrd + Eq + Hash + Copy>(x: I) -> I {

Check warning

Code scanning / clippy

function is_composite is never used Warning

function is\_composite is never used
match prime_factors(x).next() {
None => {
return 0;
return zero();
}
Some(number) => {
if number == x {
return 0;
return zero();
}
return number;
}
}
}

pub fn is_prime(x: u64) -> bool {
return is_composite(x) == 0;
pub fn is_prime<I: NumAssign + Bounded + PartialOrd + Eq + Hash + Copy>(x: I) -> bool {

Check warning

Code scanning / clippy

function is_prime is never used Warning

function is\_prime is never used
return is_composite(x) == zero();
}

0 comments on commit 26ed5d7

Please sign in to comment.