Skip to content

Commit

Permalink
Use bnum in favour of num-bigint (#12)
Browse files Browse the repository at this point in the history
  • Loading branch information
hesampakdaman authored Apr 8, 2024
1 parent 05e52e6 commit b4ec5e9
Show file tree
Hide file tree
Showing 13 changed files with 131 additions and 129 deletions.
25 changes: 12 additions & 13 deletions Cargo.lock

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

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ version = "0.1.0"
edition = "2021"

[dependencies]
num-bigint = { version = "0.4.4", features = ["rand"] }
bnum = { version = "0.11.0", features = ["numtraits", "rand"] }
num-integer = "0.1.46"
num-traits = "0.2.18"
rand = "0.8.5"
16 changes: 8 additions & 8 deletions src/algorithms/pollards_rho.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,23 @@ use crate::orchestration;
use crate::primality_test::MillerRabin;
use crate::traits::Factorize;
use crate::PrimeFactorization;
use num_bigint::BigInt;
use bnum::types::U512;
use num_integer::Integer;

pub struct PollardsRho;

impl Factorize for PollardsRho {
fn factorize(n: &BigInt) -> BigInt {
let init = BigInt::from(2);
let psudorandom_fn = utils::generate_pseudorandom_fn(n);
let finished = move |x: &BigInt, y: &BigInt| (x - y).gcd(n) != BigInt::from(1);
let (tortoise, hare) = utils::floyds_cycle_detection(init, &psudorandom_fn, &finished);
(hare - tortoise).gcd(n)
fn factorize(n: &U512) -> U512 {
let init = U512::from(2u8);
let pseudorandom_fn = utils::generate_pseudorandom_fn(&n);
let finished = move |x: &U512, y: &U512| x.abs_diff(*y).gcd(&n) != U512::from(1u8);
let (tortoise, hare) = utils::floyds_cycle_detection(init, &pseudorandom_fn, &finished);
hare.abs_diff(tortoise).gcd(&n)
}
}

impl PrimeFactorization for PollardsRho {
fn prime_factorization(n: &BigInt) -> Vec<BigInt> {
fn prime_factorization(n: &U512) -> Vec<U512> {
orchestration::FactorizeRecursiveWith::<Self, MillerRabin>::prime_factorization(n)
}
}
Expand Down
20 changes: 10 additions & 10 deletions src/algorithms/pollards_rho/utils.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use num_bigint::{BigInt, RandBigInt};
use num_traits::One;
use bnum::types::U512;
use rand::Rng;

pub fn floyds_cycle_detection<F, P>(init: BigInt, next: &F, finished: &P) -> (BigInt, BigInt)
pub fn floyds_cycle_detection<F, P>(init: U512, next: &F, finished: &P) -> (U512, U512)
where
F: Fn(&BigInt) -> BigInt + ?Sized,
P: Fn(&BigInt, &BigInt) -> bool + ?Sized,
F: Fn(&U512) -> U512 + ?Sized,
P: Fn(&U512, &U512) -> bool + ?Sized,
{
let mut tortoise = init;
let mut hare = next(&tortoise);
Expand All @@ -15,11 +15,11 @@ where
(tortoise, hare)
}

pub fn generate_pseudorandom_fn(n: &'_ BigInt) -> impl Fn(&BigInt) -> BigInt + '_ {
let c = random_integer(&n);
move |x| (x.pow(2) + &c) % n
pub fn generate_pseudorandom_fn(n: &'_ U512) -> impl Fn(&U512) -> U512 + '_ {
let c = random_integer(n);
move |x| (x.pow(2) + c) % n
}

fn random_integer(bound: &BigInt) -> BigInt {
rand::thread_rng().gen_bigint_range(&BigInt::one(), bound)
fn random_integer(bound: &U512) -> U512 {
rand::thread_rng().gen_range(U512::from(2u8)..*bound)
}
22 changes: 11 additions & 11 deletions src/algorithms/trial_division.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
use crate::PrimeFactorization;
use num_bigint::BigInt;
use bnum::types::U512;
use num_integer::Integer;
use num_traits::One;

pub struct TrialDivision;

impl PrimeFactorization for TrialDivision {
fn prime_factorization(n: &BigInt) -> Vec<BigInt> {
if n <= &BigInt::one() {
fn prime_factorization(n: &U512) -> Vec<U512> {
if n <= &U512::one() {
return vec![n.clone()];
}
trial_div(n.clone())
}
}

fn trial_div(mut n: BigInt) -> Vec<BigInt> {
fn trial_div(mut n: U512) -> Vec<U512> {
let mut factors = vec![];
let mut divisors = DivisorCandidates::new();
while let Some(d) = divisors.next() {
Expand All @@ -32,31 +32,31 @@ fn trial_div(mut n: BigInt) -> Vec<BigInt> {
factors
}

fn is_still_undivided(n: &BigInt) -> bool {
fn is_still_undivided(n: &U512) -> bool {
!n.is_one()
}

struct DivisorCandidates {
current: BigInt,
current: U512,
}

impl DivisorCandidates {
fn new() -> Self {
DivisorCandidates {
current: BigInt::from(2u8),
current: U512::from(2u8),
}
}
}

impl Iterator for DivisorCandidates {
type Item = BigInt;
type Item = U512;

fn next(&mut self) -> Option<Self::Item> {
let output = self.current.clone();
self.current = if self.current == BigInt::from(2u8) {
&self.current + 1u8
self.current = if self.current == U512::from(2u8) {
&self.current + U512::from(1u8)
} else {
&self.current + 2u8
&self.current + U512::from(2u8)
};
Some(output)
}
Expand Down
22 changes: 11 additions & 11 deletions src/factorization.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use num_bigint::BigInt;
use bnum::types::U512;
use std::collections::BTreeMap;
use std::fmt;

Expand All @@ -7,12 +7,12 @@ use crate::PrimeFactorization;
static SUPERSCRIPTS: [&str; 10] = ["⁰", "¹", "²", "³", "⁴", "⁵", "⁶", "⁷", "⁸", "⁹"];

pub struct Factorization<'a> {
number: &'a BigInt,
factors: Vec<BigInt>,
number: &'a U512,
factors: Vec<U512>,
}

impl<'a> Factorization<'a> {
pub fn new<F: PrimeFactorization>(n: &'a BigInt) -> Self {
pub fn new<F: PrimeFactorization>(n: &'a U512) -> Self {
Factorization {
number: n,
factors: F::prime_factorization(n),
Expand All @@ -29,7 +29,7 @@ impl<'a> Factorization<'a> {
format!("{} = {}", self.number, display)
}

fn frequencies(&self) -> BTreeMap<&BigInt, u128> {
fn frequencies(&self) -> BTreeMap<&U512, u128> {
self.factors.iter().fold(BTreeMap::new(), |mut bmap, n| {
*bmap.entry(n).or_insert(0) += 1;
bmap
Expand All @@ -43,7 +43,7 @@ impl fmt::Display for Factorization<'_> {
}
}

fn format_factor(base: &BigInt, exp: u128) -> String {
fn format_factor(base: &U512, exp: u128) -> String {
fn format_exp(exp: u128) -> String {
if exp <= 1 {
return "".to_string();
Expand All @@ -63,17 +63,17 @@ mod tests {
struct FakePrimeFactorizer;

impl PrimeFactorization for FakePrimeFactorizer {
fn prime_factorization(n: &BigInt) -> Vec<BigInt> {
if n == &BigInt::from(36) {
return vec![2, 2, 3, 3].into_iter().map(BigInt::from).collect();
fn prime_factorization(n: &U512) -> Vec<U512> {
if n == &U512::from(36u8) {
return vec![2u8, 2, 3, 3].into_iter().map(U512::from).collect();
} else {
return vec![2; 12].into_iter().map(BigInt::from).collect();
return vec![2u8; 12].into_iter().map(U512::from).collect();
}
}
}

fn check(n: u32, expected: &str) {
let n = BigInt::from(n);
let n = U512::from(n);
let actual = Factorization::new::<FakePrimeFactorizer>(&n);
assert_eq!(format!("{actual}"), expected);
}
Expand Down
7 changes: 2 additions & 5 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
use num_bigint::BigInt;
use bnum::types::U512;
use rustic_factors::algorithms;
use rustic_factors::Factorization;
use rustic_factors::primality_test::MillerRabin;
use rustic_factors::traits::PrimalityTest;
use std::env;

fn main() {
Expand All @@ -17,11 +15,10 @@ fn run(args: Vec<String>) -> Result<(), String> {
return Err(format!("Usage: {} <algorithm> <number>", args[0]));
}
let method = &args[1];
let n: BigInt = args[2]
let n: U512 = args[2]
.parse()
.map_err(|_| String::from("Please provide a valid positive integer"))?;
match method.as_str() {
"miller_rabin" => println!("{}", MillerRabin::is_prime(&n)),
"pollards_rho" => println!("{}", Factorization::new::<algorithms::PollardsRho>(&n)),
"trial_division" => println!("{}", Factorization::new::<algorithms::TrialDivision>(&n)),
_ => {
Expand Down
36 changes: 18 additions & 18 deletions src/orchestration/recursive.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::traits::{Factorize, PrimalityTest, PrimeFactorization};
use num_bigint::BigInt;
use bnum::types::U512;
use num_integer::Integer;
use num_traits::One;
use std::marker::PhantomData;
Expand All @@ -19,7 +19,7 @@ where
Factorizer: Factorize,
PrimeTester: PrimalityTest,
{
fn prime_factorization(n: &BigInt) -> Vec<BigInt> {
fn prime_factorization(n: &U512) -> Vec<U512> {
let max_successive_failures = 5;
Self::new(max_successive_failures).recursive_factorization(n.clone())
}
Expand All @@ -38,9 +38,9 @@ where
}
}

fn recursive_factorization(&self, mut n: BigInt) -> Vec<BigInt> {
fn recursive_factorization(&self, mut n: U512) -> Vec<U512> {
let mut factors = vec![];
let two = BigInt::from(2);
let two = U512::from(2u8);
while n.is_even() {
factors.push(two.clone());
n /= &two;
Expand All @@ -49,14 +49,14 @@ where
factors
}

fn recursion_step(&self, n: BigInt, factors: &mut Vec<BigInt>, retried: usize) {
fn recursion_step(&self, n: U512, factors: &mut Vec<U512>, retried: usize) {
if retried == self.max_successive_fails {
panic![
"Failed to find factor after {0} succesive attempts",
self.max_successive_fails
]
}
if n <= BigInt::one() {
if n <= U512::one() {
return;
}
match self.classify_factor(Factorizer::factorize(&n), &n) {
Expand All @@ -72,7 +72,7 @@ where
}
}

fn classify_factor(&self, factor: BigInt, n: &BigInt) -> DivisorOfN {
fn classify_factor(&self, factor: U512, n: &U512) -> DivisorOfN {
if PrimeTester::is_prime(&factor) {
return DivisorOfN::Prime(factor);
}
Expand All @@ -84,9 +84,9 @@ where
}

enum DivisorOfN {
Prime(BigInt),
Composite(BigInt),
Trivial(BigInt),
Prime(U512),
Composite(U512),
Trivial(U512),
}

#[cfg(test)]
Expand All @@ -98,23 +98,23 @@ mod tests {
struct FakePrimeTester;

impl PrimalityTest for FakePrimeTester {
fn is_prime(n: &BigInt) -> bool {
[2, 3, 5].contains(&n.try_into().unwrap())
fn is_prime(n: &U512) -> bool {
[2, 3, 5].contains(&n.to_str_radix(10).parse().unwrap())
}
}

struct FakeFactorizer;

impl Factorize for FakeFactorizer {
fn factorize(n: &BigInt) -> BigInt {
fn factorize(n: &U512) -> U512 {
if n.is_even() {
return 2.into();
return U512::from(2u8);
}
if n % 3 == BigInt::zero() {
return 3.into();
if n % U512::from(3u8) == U512::zero() {
return U512::from(3u8);
}
if n % 5 == BigInt::zero() {
return 5.into();
if n % U512::from(5u8) == U512::zero() {
return U512::from(5u8);
}
n.to_owned()
}
Expand Down
Loading

0 comments on commit b4ec5e9

Please sign in to comment.