Skip to content

Commit

Permalink
Move recursive solver to an orchestration layer (#4)
Browse files Browse the repository at this point in the history
  • Loading branch information
hesampakdaman authored Apr 4, 2024
1 parent 6644f9f commit 43846df
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 74 deletions.
87 changes: 13 additions & 74 deletions src/algorithms/pollards_rho.rs
Original file line number Diff line number Diff line change
@@ -1,89 +1,28 @@
mod utils;

use std::marker::PhantomData;

use crate::primality_test;
use crate::traits::PrimalityTest;
use crate::orchestration;
use crate::primality_test::MillerRabin;
use crate::traits::Factorize;
use crate::PrimeFactorization;

pub struct PollardsRho;

impl PrimeFactorization for PollardsRho {
fn prime_factorization(n: u128) -> Vec<u128> {
RecursivePollardsRho::<primality_test::MillerRabin>::new(n)
.solve()
.factors
impl Factorize for PollardsRho {
fn factorize(n: u128) -> u128 {
let init = 2;
let psudorandom_fn = utils::generate_psudeorandom_fn(n);
let finished = |x: u128, y: u128| utils::gcd(x.abs_diff(y), n) != 1;
let (tortoise, hare) = utils::floyds_cycle_detection(init, &psudorandom_fn, &finished);
utils::gcd(tortoise.abs_diff(hare), n)
}
}

struct RecursivePollardsRho<P: PrimalityTest> {
n: u128,
factors: Vec<u128>,
prime_tester: PhantomData<P>,
}

impl<P: PrimalityTest> RecursivePollardsRho<P> {
fn new(mut n: u128) -> Self {
let mut factors = vec![];
while n % 2 == 0 {
factors.push(2);
n /= 2;
}
Self {
n,
factors,
prime_tester: PhantomData,
}
}

fn solve(mut self) -> Self {
self.recursively_factorize_n(self.n);
self
}

fn recursively_factorize_n(&mut self, n: u128) {
if n <= 1 {
return;
}
match self.get_divisor_with_pollards_rho(n) {
DivisorOfN::Trivial(_) => self.recursively_factorize_n(n),
DivisorOfN::Prime(p) => {
self.factors.push(p);
self.recursively_factorize_n(n / p)
}
DivisorOfN::Composite(d) => {
self.recursively_factorize_n(n / d);
self.recursively_factorize_n(d);
}
}
}

fn get_divisor_with_pollards_rho(&self, n: u128) -> DivisorOfN {
let d = pollards_rho(n);
if P::is_prime(d) {
return DivisorOfN::Prime(d);
}
if d == 1 || d == n {
return DivisorOfN::Trivial(d);
}
DivisorOfN::Composite(d)
impl PrimeFactorization for PollardsRho {
fn prime_factorization(n: u128) -> Vec<u128> {
orchestration::FactorizeRecursiveWith::<Self, MillerRabin>::prime_factorization(n)
}
}

fn pollards_rho(n: u128) -> u128 {
let init = 2;
let psudorandom_fn = utils::generate_psudeorandom_fn(n);
let finished = |x: u128, y: u128| utils::gcd(x.abs_diff(y), n) != 1;
let (tortoise, hare) = utils::floyds_cycle_detection(init, &psudorandom_fn, &finished);
utils::gcd(tortoise.abs_diff(hare), n)
}

enum DivisorOfN {
Prime(u128),
Composite(u128),
Trivial(u128),
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ pub mod algorithms;
pub mod factorization;
pub mod traits;
pub mod primality_test;
pub mod orchestration;

pub use factorization::Factorization;
pub use traits::PrimeFactorization;
3 changes: 3 additions & 0 deletions src/orchestration.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
pub mod recursive;

pub use recursive::FactorizeRecursiveWith;
78 changes: 78 additions & 0 deletions src/orchestration/recursive.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
use crate::traits::{Factorize, PrimalityTest, PrimeFactorization};
use std::marker::PhantomData;

pub struct FactorizeRecursiveWith<F, P>
where
F: Factorize,
P: PrimalityTest,
{
_factorizer: PhantomData<F>,
_prime_tester: PhantomData<P>,
}

impl<Factorizer, PrimeTester> PrimeFactorization
for FactorizeRecursiveWith<Factorizer, PrimeTester>
where
Factorizer: Factorize,
PrimeTester: PrimalityTest,
{
fn prime_factorization(n: u128) -> Vec<u128> {
Self::new().recursive_factorization(n)
}
}

impl<Factorizer, PrimeTester> FactorizeRecursiveWith<Factorizer, PrimeTester>
where
Factorizer: Factorize,
PrimeTester: PrimalityTest,
{
fn new() -> Self {
Self {
_factorizer: PhantomData,
_prime_tester: PhantomData,
}
}

fn recursive_factorization(&self, mut n: u128) -> Vec<u128> {
let mut factors = vec![];
while n % 2 == 0 {
factors.push(2);
n /= 2;
}
self.recursion_step(n, &mut factors);
factors
}

fn recursion_step(&self, n: u128, factors: &mut Vec<u128>) {
if n <= 1 {
return;
}
match self.classify_factor(Factorizer::factorize(n), n) {
DivisorOfN::Trivial(_) => self.recursion_step(n, factors),
DivisorOfN::Prime(p) => {
factors.push(p);
self.recursion_step(n / p, factors)
}
DivisorOfN::Composite(d) => {
self.recursion_step(n / d, factors);
self.recursion_step(d, factors);
}
}
}

fn classify_factor(&self, factor: u128, n: u128) -> DivisorOfN {
if PrimeTester::is_prime(factor) {
return DivisorOfN::Prime(factor);
}
if factor == 1 || factor == n {
return DivisorOfN::Trivial(factor);
}
DivisorOfN::Composite(factor)
}
}

enum DivisorOfN {
Prime(u128),
Composite(u128),
Trivial(u128),
}
4 changes: 4 additions & 0 deletions src/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ pub trait PrimeFactorization {
fn prime_factorization(n: u128) -> Vec<u128>;
}

pub trait Factorize {
fn factorize(n: u128) -> u128;
}

pub trait PrimalityTest {
fn is_prime(p: u128) -> bool;
}

0 comments on commit 43846df

Please sign in to comment.