Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix clippy warnings #17

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions examples/divisor_sigma.rs
Original file line number Diff line number Diff line change
@@ -3,21 +3,21 @@ use num_prime::nt_funcs::factorize64;
/// Return all divisors of the target
fn divisors(target: u64) -> Vec<u64> {
let factors = factorize64(target);
let mut result = Vec::with_capacity(factors.iter().map(|(_, e)| e + 1).product());
let mut result = Vec::with_capacity(factors.values().map(|e| e + 1).product());
result.push(1);

for (p, e) in factors {
// the new results contain all previous divisors multiplied by p, p^2, .., p^e
let mut new_result = Vec::with_capacity(result.len() * e);
for i in 1..(e as u32 + 1) {
for i in 1..=(e as u32) {
new_result.extend(result.iter().map(|f| f * p.pow(i)));
}
result.append(&mut new_result);
}
result
}

/// Calculate the divisor sigma function σ_z(n) on the target
/// Calculate the divisor sigma function `σ_z(n`) on the target
/// Reference: <https://en.wikipedia.org/wiki/Divisor_function>
fn divisor_sigma(target: u64, z: u32) -> u64 {
divisors(target).into_iter().map(|d| d.pow(z)).sum()
2 changes: 1 addition & 1 deletion examples/find_mersenne_primes.rs
Original file line number Diff line number Diff line change
@@ -11,6 +11,6 @@ fn list_mersenne() -> Vec<u64> {
fn main() {
println!("Mersenne primes under 2^128:");
for p in list_mersenne() {
println!("2^{} - 1", p);
println!("2^{p} - 1");
}
}
2 changes: 1 addition & 1 deletion examples/prime_omega.rs
Original file line number Diff line number Diff line change
@@ -10,7 +10,7 @@ fn prime_omega(target: u64) -> usize {
/// Reference: <https://en.wikipedia.org/wiki/Prime_omega_function>
#[allow(non_snake_case)]
fn prime_Omega(target: u64) -> usize {
factorize64(target).into_iter().map(|(_, e)| e).sum()
factorize64(target).into_values().sum()
}

fn main() {
18 changes: 9 additions & 9 deletions examples/profile_factorization.rs
Original file line number Diff line number Diff line change
@@ -8,7 +8,7 @@ use rand::random;

/// Collect the the iteration number of each factorization algorithm with different settings
fn profile_n(n: u128) -> Vec<(String, usize)> {
let k_squfof: Vec<u16> = SQUFOF_MULTIPLIERS.iter().take(10).cloned().collect();
let k_squfof: Vec<u16> = SQUFOF_MULTIPLIERS.iter().take(10).copied().collect();
let k_oneline: Vec<u16> = vec![1, 360, 480];
const MAXITER: usize = 1 << 20;
const POLLARD_REPEATS: usize = 2;
@@ -25,8 +25,8 @@ fn profile_n(n: u128) -> Vec<(String, usize)> {

// squfof
for &k in &k_squfof {
let key = format!("squfof_k{}", k);
if let Some(kn) = n.checked_mul(k as u128) {
let key = format!("squfof_k{k}");
if let Some(kn) = n.checked_mul(u128::from(k)) {
let n = squfof(&n, kn, MAXITER).1;
n_stats.push((key, n));
} else {
@@ -36,8 +36,8 @@ fn profile_n(n: u128) -> Vec<(String, usize)> {

// one line
for &k in &k_oneline {
let key = format!("one_line_k{}", k);
if let Some(kn) = n.checked_mul(k as u128) {
let key = format!("one_line_k{k}");
if let Some(kn) = n.checked_mul(u128::from(k)) {
let n = one_line(&n, kn, MAXITER).1;
n_stats.push((key, n));
} else {
@@ -50,7 +50,7 @@ fn profile_n(n: u128) -> Vec<(String, usize)> {

/// Collect the best case of each factorization algorithm
fn profile_n_min(n: u128) -> Vec<(String, usize)> {
let k_squfof: Vec<u16> = SQUFOF_MULTIPLIERS.iter().cloned().collect();
let k_squfof: Vec<u16> = SQUFOF_MULTIPLIERS.to_vec();
let k_oneline: Vec<u16> = vec![1, 360, 480];
const MAXITER: usize = 1 << 24;
const POLLARD_REPEATS: usize = 4;
@@ -72,7 +72,7 @@ fn profile_n_min(n: u128) -> Vec<(String, usize)> {
// squfof
let mut squfof_best = (MAXITER, u128::MAX);
for &k in &k_squfof {
if let Some(kn) = n.checked_mul(k as u128) {
if let Some(kn) = n.checked_mul(u128::from(k)) {
let tstart = Instant::now();
let (result, iters) = squfof(&n, kn, squfof_best.0);
if result.is_some() {
@@ -86,7 +86,7 @@ fn profile_n_min(n: u128) -> Vec<(String, usize)> {
// one line
let mut oneline_best = (MAXITER, u128::MAX);
for &k in &k_oneline {
if let Some(kn) = n.checked_mul(k as u128) {
if let Some(kn) = n.checked_mul(u128::from(k)) {
let tstart = Instant::now();
let (result, iters) = one_line(&n, kn, oneline_best.0);
if result.is_some() {
@@ -119,7 +119,7 @@ fn main() -> Result<(), Error> {

let n = p1 * p2;
n_list.push((n, (n as f64).log2() as f32));
println!("Semiprime ({}bits): {} = {} * {}", total_bits, n, p1, p2);
println!("Semiprime ({total_bits}bits): {n} = {p1} * {p2}");
// stats.push(profile_n(n));
stats.push(profile_n_min(n));
}
85 changes: 46 additions & 39 deletions src/buffer.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
//! Implementations and extensions for [PrimeBuffer], which represents a container of primes
//! Implementations and extensions for [`PrimeBuffer`], which represents a container of primes
//!
//! In `num-prime`, there is no global instance to store primes, the user has to generate
//! and store the primes themselves. The trait [PrimeBuffer] defines a unified interface
//! and store the primes themselves. The trait [`PrimeBuffer`] defines a unified interface
//! for a prime number container. Some methods that can take advantage of pre-generated
//! primes will be implemented in the [PrimeBufferExt] trait.
//! primes will be implemented in the [`PrimeBufferExt`] trait.
//!
//! We also provide [NaiveBuffer] as a simple implementation of [PrimeBuffer] without any
//! external dependencies. The performance of the [NaiveBuffer] will not be extremely optimized,
//! We also provide [`NaiveBuffer`] as a simple implementation of [`PrimeBuffer`] without any
//! external dependencies. The performance of the [`NaiveBuffer`] will not be extremely optimized,
//! but it will be efficient enough for most applications.
//!
@@ -30,7 +30,7 @@ use std::num::NonZeroUsize;
pub trait PrimeBufferExt: for<'a> PrimeBuffer<'a> {
/// Test if an integer is a prime.
///
/// For targets smaller than 2^64, the deterministic [is_prime64] will be used, otherwise
/// For targets smaller than 2^64, the deterministic [`is_prime64`] will be used, otherwise
/// the primality test algorithms can be specified by the `config` argument.
///
/// The primality test can be either deterministic or probabilistic for large integers depending on the `config`.
@@ -61,7 +61,7 @@ pub trait PrimeBufferExt: for<'a> PrimeBuffer<'a> {
};
}

let config = config.unwrap_or(PrimalityTestConfig::default());
let config = config.unwrap_or_default();
let mut probability = 1.;

// miller-rabin test
@@ -74,7 +74,7 @@ pub trait PrimeBufferExt: for<'a> PrimeBuffer<'a> {
for _ in 0..config.sprp_random_trials {
// we have ensured target is larger than 2^64
let mut w: u64 = rand::random();
while witness_list.iter().find(|&x| x == &w).is_some() {
while witness_list.iter().any(|x| x == &w) {
w = rand::random();
}
witness_list.push(w);
@@ -130,10 +130,10 @@ pub trait PrimeBufferExt: for<'a> PrimeBuffer<'a> {
.collect();
return (factors, None);
}
let config = config.unwrap_or(FactorizationConfig::default());
let config = config.unwrap_or_default();

// test the existing primes
let (result, factored) = trial_division(self.iter().cloned(), target, config.td_limit);
let (result, factored) = trial_division(self.iter().copied(), target, config.td_limit);
let mut result: BTreeMap<T, usize> = result
.into_iter()
.map(|(k, v)| (T::from_u64(k).unwrap(), v))
@@ -159,13 +159,11 @@ pub trait PrimeBufferExt: for<'a> PrimeBuffer<'a> {
.probably()
{
*result.entry(target).or_insert(0) += 1;
} else if let Some(divisor) = self.divisor(&target, &mut config) {
todo.push(divisor.clone());
todo.push(target / divisor);
} else {
if let Some(divisor) = self.divisor(&target, &mut config) {
todo.push(divisor.clone());
todo.push(target / divisor);
} else {
failed.push(target);
}
failed.push(target);
}
}
}
@@ -242,7 +240,7 @@ pub trait PrimeBufferExt: for<'a> PrimeBuffer<'a> {
config.rho_trials -= 1;
// TODO: change to a reasonable pollard rho limit
// TODO: add other factorization methods
if let (Some(p), _) = pollard_rho(target, start, offset, 1048576) {
if let (Some(p), _) = pollard_rho(target, start, offset, 1_048_576) {
return Some(p);
}
}
@@ -253,16 +251,23 @@ pub trait PrimeBufferExt: for<'a> PrimeBuffer<'a> {

impl<T> PrimeBufferExt for T where for<'a> T: PrimeBuffer<'a> {}

/// NaiveBuffer implements a very simple Sieve of Eratosthenes
/// `NaiveBuffer` implements a very simple Sieve of Eratosthenes
pub struct NaiveBuffer {
list: Vec<u64>, // list of found prime numbers
next: u64, // all primes smaller than this value has to be in the prime list, should be an odd number
}

impl Default for NaiveBuffer {
fn default() -> Self {
Self::new()
}
}

impl NaiveBuffer {
#[inline]
#[must_use]
pub fn new() -> Self {
let list = SMALL_PRIMES.iter().map(|&p| p as u64).collect();
let list = SMALL_PRIMES.iter().map(|&p| u64::from(p)).collect();
NaiveBuffer {
list,
next: SMALL_PRIMES_NEXT,
@@ -355,14 +360,15 @@ impl NaiveBuffer {
}

/// Returns all primes ≤ `limit` and takes ownership. The primes are sorted.
#[must_use]
pub fn into_primes(mut self, limit: u64) -> std::vec::IntoIter<u64> {
self.reserve(limit);
let position = match self.list.binary_search(&limit) {
Ok(p) => p + 1,
Err(p) => p,
}; // into_ok_or_err()
self.list.truncate(position);
return self.list.into_iter();
self.list.into_iter()
}

/// Returns primes of certain amount counting from 2. The primes are sorted.
@@ -375,13 +381,14 @@ impl NaiveBuffer {
}

/// Returns primes of certain amount counting from 2 and takes ownership. The primes are sorted.
#[must_use]
pub fn into_nprimes(mut self, count: usize) -> std::vec::IntoIter<u64> {
let (_, bound) = nth_prime_bounds(&(count as u64))
.expect("Estimated size of the largest prime will be larger than u64 limit");
self.reserve(bound);
debug_assert!(self.list.len() >= count);
self.list.truncate(count);
return self.list.into_iter();
self.list.into_iter()
}

/// Get the n-th prime (n counts from 1).
@@ -414,7 +421,7 @@ impl NaiveBuffer {
x
}

/// Legendre's phi function, used as a helper function for [Self::prime_pi]
/// Legendre's phi function, used as a helper function for [`Self::prime_pi`]
pub fn prime_phi(&mut self, x: u64, a: usize, cache: &mut LruCache<(u64, usize), u64>) -> u64 {
if a == 1 {
return (x + 1) / 2;
@@ -459,19 +466,19 @@ impl NaiveBuffer {
let mut phi_cache = LruCache::new(cache_cap);
let mut sum =
self.prime_phi(limit, a as usize, &mut phi_cache) + (b + a - 2) * (b - a + 1) / 2;
for i in a + 1..b + 1 {
for i in (a + 1)..=b {
let w = limit / self.nth_prime(i);
sum -= self.prime_pi(w);
if i <= c {
let l = self.prime_pi(w.sqrt());
sum += (l * (l - 1) - i * (i - 3)) / 2 - 1;
for j in i..(l + 1) {
for j in i..=l {
let pj = self.nth_prime(j);
sum -= self.prime_pi(w / pj);
}
}
}
return sum;
sum
}
}

@@ -496,12 +503,12 @@ mod tests {
];

let mut pb = NaiveBuffer::new();
assert_eq!(pb.primes(50).cloned().collect::<Vec<_>>(), PRIME50);
assert_eq!(pb.primes(300).cloned().collect::<Vec<_>>(), PRIME300);
assert_eq!(pb.primes(50).copied().collect::<Vec<_>>(), PRIME50);
assert_eq!(pb.primes(300).copied().collect::<Vec<_>>(), PRIME300);

// test when limit itself is a prime
pb.clear();
assert_eq!(pb.primes(293).cloned().collect::<Vec<_>>(), PRIME300);
assert_eq!(pb.primes(293).copied().collect::<Vec<_>>(), PRIME300);
pb = NaiveBuffer::new();
assert_eq!(*pb.primes(257).last().unwrap(), 257); // boundary of small table
pb = NaiveBuffer::new();
@@ -511,15 +518,15 @@ mod tests {
#[test]
fn nth_prime_test() {
let mut pb = NaiveBuffer::new();
assert_eq!(pb.nth_prime(10000), 104729);
assert_eq!(pb.nth_prime(20000), 224737);
assert_eq!(pb.nth_prime(10000), 104729); // use existing primes
assert_eq!(pb.nth_prime(10000), 104_729);
assert_eq!(pb.nth_prime(20000), 224_737);
assert_eq!(pb.nth_prime(10000), 104_729); // use existing primes

// Riemann zeta based, test on OEIS:A006988
assert_eq!(pb.nth_prime(10u64.pow(4)), 104729);
assert_eq!(pb.nth_prime(10u64.pow(5)), 1299709);
assert_eq!(pb.nth_prime(10u64.pow(6)), 15485863);
assert_eq!(pb.nth_prime(10u64.pow(7)), 179424673);
assert_eq!(pb.nth_prime(10u64.pow(4)), 104_729);
assert_eq!(pb.nth_prime(10u64.pow(5)), 1_299_709);
assert_eq!(pb.nth_prime(10u64.pow(6)), 15_485_863);
assert_eq!(pb.nth_prime(10u64.pow(7)), 179_424_673);
}

#[test]
@@ -539,8 +546,8 @@ mod tests {
// Meissel–Lehmer algorithm, test on OEIS:A006880
assert_eq!(pb.prime_pi(10u64.pow(5)), 9592);
assert_eq!(pb.prime_pi(10u64.pow(6)), 78498);
assert_eq!(pb.prime_pi(10u64.pow(7)), 664579);
assert_eq!(pb.prime_pi(10u64.pow(8)), 5761455);
assert_eq!(pb.prime_pi(10u64.pow(7)), 664_579);
assert_eq!(pb.prime_pi(10u64.pow(8)), 5_761_455);
}

#[test]
@@ -573,7 +580,7 @@ mod tests {
}

// test large numbers
const P: u128 = 18699199384836356663; // https://golang.org/issue/638
const P: u128 = 18_699_199_384_836_356_663; // https://golang.org/issue/638
assert!(matches!(pb.is_prime(&P, None), Primality::Probable(_)));
assert!(matches!(
pb.is_prime(&P, Some(PrimalityTestConfig::bpsw())),
@@ -588,7 +595,7 @@ mod tests {
Primality::Probable(_)
));

const P2: u128 = 2019922777445599503530083;
const P2: u128 = 2_019_922_777_445_599_503_530_083;
assert!(matches!(pb.is_prime(&P2, None), Primality::Probable(_)));
assert!(matches!(
pb.is_prime(&P2, Some(PrimalityTestConfig::bpsw())),
78 changes: 39 additions & 39 deletions src/factor.rs
Original file line number Diff line number Diff line change
@@ -19,7 +19,7 @@ use std::collections::BTreeMap;
/// The parameter limit additionally sets the maximum of primes to be tried.
/// The residual will be Ok(1) or Ok(p) if fully factored.
///
/// TODO: implement fast check for small primes with BigInts in the precomputed table, and skip them in this function
/// TODO: implement fast check for small primes with `BigInts` in the precomputed table, and skip them in this function
pub fn trial_division<
I: Iterator<Item = u64>,
T: Integer + Clone + Roots + NumRef + FromPrimitive,
@@ -98,14 +98,14 @@ where

while i < max_iter {
i += 1;
a = a.sqm(&target).addm(&offset, &target);
a = a.sqm(target).addm(&offset, target);
if a == b {
return (None, i);
}

// FIXME: optimize abs_diff for montgomery form if we are going to use the abs_diff in the std lib
let diff = if b > a { &b - &a } else { &a - &b }; // abs_diff
z = z.mulm(&diff, &target);
z = z.mulm(&diff, target);
if z.is_zero() {
// the factor is missed by a combined GCD, do backtracing
if backtrace {
@@ -145,7 +145,7 @@ where
/// This function implements Shanks's square forms factorization (SQUFOF).
///
/// The input is usually multiplied by a multiplier, and the multiplied integer should be put in
/// the `mul_target` argument. The multiplier can be choosen from SQUFOF_MULTIPLIERS, or other square-free odd numbers.
/// the `mul_target` argument. The multiplier can be choosen from `SQUFOF_MULTIPLIERS`, or other square-free odd numbers.
/// The returned values are the factor and the count of passed iterations.
///
/// The max iteration can be choosed as 2*n^(1/4), based on Theorem 4.22 from [1].
@@ -163,7 +163,7 @@ where
for<'r> &'r T: RefNum<T>,
{
assert!(
&mul_target.is_multiple_of(&target),
&mul_target.is_multiple_of(target),
"mul_target should be multiples of target"
);
let rd = Roots::sqrt(&mul_target); // root of k*N
@@ -210,7 +210,7 @@ where
if new_u == u {
break;
} else {
u = new_u
u = new_u;
}
}

@@ -277,7 +277,7 @@ pub const SQUFOF_MULTIPLIERS: [u16; 38] = [
///
///
/// The one line factorization algorithm is especially good at factoring semiprimes with form pq,
/// where p = next_prime(c^a+d1), p = next_prime(c^b+d2), a and b are close, and c, d1, d2 are small integers.
/// where p = `next_prime(c^a+d1`), p = `next_prime(c^b+d2`), a and b are close, and c, d1, d2 are small integers.
///
/// Reference: Hart, W. B. (2012). A one line factoring algorithm. Journal of the Australian Mathematical Society, 92(1), 61-69. doi:10.1017/S1446788712000146
// TODO: add multipliers preset for one_line method?
@@ -290,7 +290,7 @@ where
for<'r> &'r T: RefNum<T>,
{
assert!(
&mul_target.is_multiple_of(&target),
&mul_target.is_multiple_of(target),
"mul_target should be multiples of target"
);

@@ -306,13 +306,13 @@ where
}

// prevent overflow
ikn = if let Some(n) = (&ikn).checked_add(&mul_target) {
ikn = if let Some(n) = ikn.checked_add(&mul_target) {
n
} else {
return (None, i);
}
}
return (None, max_iter);
(None, max_iter)
}

// TODO: ECM, (self initialize) Quadratic sieve, Lehman's Fermat(https://en.wikipedia.org/wiki/Fermat%27s_factorization_method, n_factor_lehman)
@@ -335,7 +335,7 @@ mod tests {
fn pollard_rho_test() {
assert_eq!(pollard_rho(&8051u16, 2, 1, 100).0, Some(97));
assert!(matches!(pollard_rho(&8051u16, random(), 1, 100).0, Some(i) if i == 97 || i == 83));
assert_eq!(pollard_rho(&455459u32, 2, 1, 100).0, Some(743));
assert_eq!(pollard_rho(&455_459_u32, 2, 1, 100).0, Some(743));

// Mint test
for _ in 0..10 {
@@ -365,34 +365,34 @@ mod tests {
12851,
13289,
75301,
120787,
967009,
997417,
7091569,
5214317,
20834839,
23515517,
33409583,
44524219,
13290059,
223553581,
2027651281,
11111111111,
100895598169,
60012462237239,
287129523414791,
9007199254740931,
11111111111111111,
314159265358979323,
384307168202281507,
419244183493398773,
658812288346769681,
922337203685477563,
1000000000000000127,
1152921505680588799,
1537228672809128917,
120_787,
967_009,
997_417,
7_091_569,
5_214_317,
20_834_839,
23_515_517,
33_409_583,
44_524_219,
13_290_059,
223_553_581,
2_027_651_281,
11_111_111_111,
100_895_598_169,
60_012_462_237_239,
287_129_523_414_791,
9_007_199_254_740_931,
11_111_111_111_111_111,
314_159_265_358_979_323,
384_307_168_202_281_507,
419_244_183_493_398_773,
658_812_288_346_769_681,
922_337_203_685_477_563,
1_000_000_000_000_000_127,
1_152_921_505_680_588_799,
1_537_228_672_809_128_917,
// this case should success at step 276, from https://rosettacode.org/wiki/Talk:Square_form_factorization
4558849,
4_558_849,
];
for n in cases {
let d = squfof(&n, n, 40000)
@@ -401,7 +401,7 @@ mod tests {
.or(squfof(&n, 5 * n, 40000).0)
.or(squfof(&n, 7 * n, 40000).0)
.or(squfof(&n, 11 * n, 40000).0);
assert!(matches!(d, Some(_)), "{}", n);
assert!(d.is_some(), "{}", n);
}
}

23 changes: 12 additions & 11 deletions src/integer.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
//! Backend implementations for integers
use crate::tables::{CUBIC_MODULI, CUBIC_RESIDUAL, QUAD_MODULI, QUAD_RESIDUAL};
use crate::traits::{BitTest, ExactRoots};
use crate::{
tables::{CUBIC_MODULI, CUBIC_RESIDUAL, QUAD_MODULI, QUAD_RESIDUAL},
traits::{BitTest, ExactRoots},
};

#[cfg(feature = "num-bigint")]
use num_bigint::{BigInt, BigUint, ToBigInt};
@@ -155,19 +157,18 @@ impl ExactRoots for BigInt {
#[cfg(test)]
mod tests {
use super::*;
use rand;

#[test]
fn exact_root_test() {
// some simple tests
assert!(matches!(ExactRoots::sqrt_exact(&3u8), None));
assert!(ExactRoots::sqrt_exact(&3u8).is_none());
assert!(matches!(ExactRoots::sqrt_exact(&4u8), Some(2)));
assert!(matches!(ExactRoots::sqrt_exact(&9u8), Some(3)));
assert!(matches!(ExactRoots::sqrt_exact(&18u8), None));
assert!(matches!(ExactRoots::sqrt_exact(&3i8), None));
assert!(ExactRoots::sqrt_exact(&18u8).is_none());
assert!(ExactRoots::sqrt_exact(&3i8).is_none());
assert!(matches!(ExactRoots::sqrt_exact(&4i8), Some(2)));
assert!(matches!(ExactRoots::sqrt_exact(&9i8), Some(3)));
assert!(matches!(ExactRoots::sqrt_exact(&18i8), None));
assert!(ExactRoots::sqrt_exact(&18i8).is_none());

// test fast implementations of sqrt against nth_root
for _ in 0..100 {
@@ -188,15 +189,15 @@ mod tests {
}
// test perfect powers
for _ in 0..100 {
let x = rand::random::<u32>() as u64;
let x = u64::from(rand::random::<u32>());
assert!(matches!(ExactRoots::sqrt_exact(&(x * x)), Some(v) if v == x));
let x = rand::random::<i16>() as i64;
let x = i64::from(rand::random::<i16>());
assert!(matches!(ExactRoots::cbrt_exact(&(x * x * x)), Some(v) if v == x));
}
// test non-perfect powers
for _ in 0..100 {
let x = rand::random::<u32>() as u64;
let y = rand::random::<u32>() as u64;
let x = u64::from(rand::random::<u32>());
let y = u64::from(rand::random::<u32>());
if x == y {
continue;
}
8 changes: 4 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -26,8 +26,8 @@
//! - [Moebius function][nt_funcs::moebius]
//!
//! # Usage
//! Most number theoretic functions can be found in [nt_funcs] module, while some
//! of them are implemented as member function of [num_modular::ModularOps] or [PrimalityUtils].
//! Most number theoretic functions can be found in [`nt_funcs`] module, while some
//! of them are implemented as member function of [`num_modular::ModularOps`] or [`PrimalityUtils`].
//!
//! Example code for primality testing and integer factorization:
//! ```rust
@@ -52,9 +52,9 @@
//! This crate is built with modular integer type and prime generation backends.
//! Most functions support generic input types, and support for `num-bigint` is
//! also available (it's an optional feature). To make a new integer type supported
//! by this crate, the type has to implement [detail::PrimalityBase] and [detail::PrimalityRefBase].
//! by this crate, the type has to implement [`detail::PrimalityBase`] and [`detail::PrimalityRefBase`].
//! For prime generation, there's a builtin implementation (see [buffer] module),
//! but you can also use other backends (such as `primal`) as long as it implements [PrimeBuffer].
//! but you can also use other backends (such as `primal`) as long as it implements [`PrimeBuffer`].
//!
//! # Optional Features
//! - `big-int` (default): Enable this feature to support `num-bigint::BigUint` as integer inputs.
6 changes: 3 additions & 3 deletions src/mint.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
//! Wrapper of integer to makes it efficient in modular arithmetics but still have the same
//! API of normal integers.
use core::ops::*;
use either::*;
use core::ops::{Add, Div, Mul, Neg, Rem, Shr, Sub};
use either::{Either, Left, Right};
use num_integer::{Integer, Roots};
use num_modular::{
ModularCoreOps, ModularInteger, ModularPow, ModularSymbols, ModularUnaryOps, Montgomery,
@@ -12,7 +12,7 @@ use num_traits::{FromPrimitive, Num, One, Pow, ToPrimitive, Zero};

use crate::{BitTest, ExactRoots};

/// Integer with fast modular arithmetics support, based on [MontgomeryInt] under the hood
/// Integer with fast modular arithmetics support, based on [`MontgomeryInt`] under the hood
///
/// This struct only designed to be working with this crate. Most binary operators assume that
/// the modulus of two operands (when in montgomery form) are the same, and most implicit conversions
2,743 changes: 1,376 additions & 1,367 deletions src/nt_funcs.rs

Large diffs are not rendered by default.

56 changes: 26 additions & 30 deletions src/primality.rs
Original file line number Diff line number Diff line change
@@ -341,7 +341,7 @@ where
}
}

/// A dummy trait for integer type. All types that implements this and [PrimalityRefBase]
/// A dummy trait for integer type. All types that implements this and [`PrimalityRefBase`]
/// will be supported by most functions in `num-primes`
pub trait PrimalityBase:
Integer
@@ -369,7 +369,7 @@ impl<
{
}

/// A dummy trait for integer reference type. All types that implements this and [PrimalityBase]
/// A dummy trait for integer reference type. All types that implements this and [`PrimalityBase`]
/// will be supported by most functions in `num-primes`
pub trait PrimalityRefBase<Base>:
RefNum<Base>
@@ -441,26 +441,26 @@ mod tests {
3927,
12970,
42837,
141481,
467280,
1543321,
5097243,
16835050,
55602393,
183642229,
606529080,
2003229469,
6616217487,
21851881930,
72171863277,
238367471761,
787274278560,
2600190307441,
141_481,
467_280,
1_543_321,
5_097_243,
16_835_050,
55_602_393,
183_642_229,
606_529_080,
2_003_229_469,
6_616_217_487,
21_851_881_930,
72_171_863_277,
238_367_471_761,
787_274_278_560,
2_600_190_307_441,
];
let m = random::<u16>();
for n in 2..p3qm1.len() {
let (uk, _) = LucasUtils::lucasm(3, -1, m as u64, n as u64);
assert_eq!(uk, p3qm1[n] % (m as u64));
let (uk, _) = LucasUtils::lucasm(3, -1, u64::from(m), n as u64);
assert_eq!(uk, p3qm1[n] % u64::from(m));

#[cfg(feature = "num-bigint")]
{
@@ -491,18 +491,14 @@ mod tests {
(u as u16, v as u16)
}
for _ in 0..10 {
let n = random::<u8>() as u16;
let n = u16::from(random::<u8>());
let m = random::<u16>();
let p = random::<u16>() as usize;
let q = random::<i16>() as isize;
assert_eq!(
LucasUtils::lucasm(p, q, m, n),
lucasm_naive(p, q, m, n),
"failed with Lucas settings: p={}, q={}, m={}, n={}",
p,
q,
m,
n
"failed with Lucas settings: p={p}, q={q}, m={m}, n={n}"
);
}
}
@@ -519,7 +515,7 @@ mod tests {

// least lucas pseudo primes for Q=-1 and Jacobi(D/n) = -1 (from Wikipedia)
let plimit: [u16; 5] = [323, 35, 119, 9, 9];
for (i, l) in plimit.iter().cloned().enumerate() {
for (i, l) in plimit.iter().copied().enumerate() {
let p = i + 1;
assert!(l.is_lprp(Some(p), Some(-1)));

@@ -544,7 +540,7 @@ mod tests {

// least strong lucas pseudoprimes for Q=-1 and Jacobi(D/n) = -1 (from Wikipedia)
let plimit: [u16; 3] = [4181, 169, 119];
for (i, l) in plimit.iter().cloned().enumerate() {
for (i, l) in plimit.iter().copied().enumerate() {
let p = i + 1;
assert!(l.is_slprp(Some(p), Some(-1)));

@@ -581,7 +577,7 @@ mod tests {
if n <= 3 || (n.is_sprp(2) && n.is_sprp(3)) {
continue;
} // skip real primes
if lpsp.iter().find(|&x| x == &n).is_some() {
if lpsp.iter().any(|x| x == &n) {
continue;
} // skip pseudoprimes
assert!(!n.is_lprp(None, None), "lucas prp test on {}", n);
@@ -601,7 +597,7 @@ mod tests {
if n <= 3 || (n.is_sprp(2) && n.is_sprp(3)) {
continue;
} // skip real primes
if slpsp.iter().find(|&x| x == &n).is_some() {
if slpsp.iter().any(|x| x == &n) {
continue;
} // skip pseudoprimes
assert!(!n.is_slprp(None, None), "strong lucas prp test on {}", n);
@@ -621,7 +617,7 @@ mod tests {
if n <= 3 || (n.is_sprp(2) && n.is_sprp(3)) {
continue;
} // skip real primes
if eslpsp.iter().find(|&x| x == &n).is_some() {
if eslpsp.iter().any(|x| x == &n) {
continue;
} // skip pseudoprimes
assert!(!n.is_eslprp(None), "extra strong lucas prp test on {}", n);
26 changes: 14 additions & 12 deletions src/rand.rs
Original file line number Diff line number Diff line change
@@ -83,9 +83,10 @@ impl_randprime_prim!(u8 u16 u32 u64);
impl<R: Rng> RandPrime<u128> for R {
#[inline]
fn gen_prime(&mut self, bit_size: usize, config: Option<PrimalityTestConfig>) -> u128 {
if bit_size > (u128::BITS as usize) {
panic!("The given bit size limit exceeded the capacity of the integer type!")
}
assert!(
bit_size <= (u128::BITS as usize),
"The given bit size limit exceeded the capacity of the integer type!"
);

loop {
let t: u128 = self.gen();
@@ -101,9 +102,10 @@ impl<R: Rng> RandPrime<u128> for R {

#[inline]
fn gen_prime_exact(&mut self, bit_size: usize, config: Option<PrimalityTestConfig>) -> u128 {
if bit_size > (u128::BITS as usize) {
panic!("The given bit size limit exceeded the capacity of the integer type!")
}
assert!(
bit_size <= (u128::BITS as usize),
"The given bit size limit exceeded the capacity of the integer type!"
);

loop {
let t: u128 = self.gen();
@@ -212,11 +214,11 @@ mod tests {

// test random prime generation for each size
let p: u8 = rng.gen_prime(8, None);
assert!(is_prime64(p as u64));
assert!(is_prime64(u64::from(p)));
let p: u16 = rng.gen_prime(16, None);
assert!(is_prime64(p as u64));
assert!(is_prime64(u64::from(p)));
let p: u32 = rng.gen_prime(32, None);
assert!(is_prime64(p as u64));
assert!(is_prime64(u64::from(p)));
let p: u64 = rng.gen_prime(64, None);
assert!(is_prime64(p));
let p: u128 = rng.gen_prime(128, None);
@@ -251,15 +253,15 @@ mod tests {

// test exact size prime generation
let p: u8 = rng.gen_prime_exact(8, None);
assert!(is_prime64(p as u64));
assert!(is_prime64(u64::from(p)));
assert_eq!(p.leading_zeros(), 0);
let p: u32 = rng.gen_prime_exact(32, None);
assert!(is_prime64(p as u64));
assert!(is_prime64(u64::from(p)));
assert_eq!(p.leading_zeros(), 0);
let p: u128 = rng.gen_prime_exact(128, None);
assert!(is_prime(&p, None).probably());
assert_eq!(p.leading_zeros(), 0);

// test random safe prime generation
let p: u8 = rng.gen_safe_prime_exact(8);
assert!(is_safe_prime(&p).probably());
20,423 changes: 17,493 additions & 2,930 deletions src/tables.rs

Large diffs are not rendered by default.

22 changes: 13 additions & 9 deletions src/traits.rs
Original file line number Diff line number Diff line change
@@ -32,8 +32,9 @@ pub enum Primality {

impl Primality {
/// Check whether the resule indicates that the number is
/// (very) probably a prime. Return false only on [Primality::No]
/// (very) probably a prime. Return false only on [`Primality::No`]
#[inline(always)]
#[must_use]
pub fn probably(self) -> bool {
match self {
Primality::No => false,
@@ -112,13 +113,15 @@ impl PrimalityTestConfig {
/// Create a configuration with a very strong primality check. It's based on
/// the **strongest deterministic primality testing** and some SPRP tests with
/// random bases.
#[must_use]
pub fn strict() -> Self {
let mut config = Self::bpsw();
config.sprp_random_trials = 1;
config
}

/// Create a configuration for Baillie-PSW test (base 2 SPRP test + SLPRP test)
#[must_use]
pub fn bpsw() -> Self {
Self {
sprp_trials: 1,
@@ -172,6 +175,7 @@ impl Default for FactorizationConfig {

impl FactorizationConfig {
/// Same as the default configuration but with strict primality check
#[must_use]
pub fn strict() -> Self {
let mut config = Self::default();
config.primality_config = PrimalityTestConfig::strict();
@@ -180,7 +184,7 @@ impl FactorizationConfig {
}

// FIXME: backport to num_integer (see https://github.com/rust-num/num-traits/issues/233)
/// Extension on [num_integer::Roots] to support perfect power check on integers
/// Extension on [`num_integer::Roots`] to support perfect power check on integers
pub trait ExactRoots: Roots + Pow<u32, Output = Self> + Clone {
fn nth_root_exact(&self, n: u32) -> Option<Self> {
let r = self.nth_root(n);
@@ -230,7 +234,7 @@ pub trait PrimeBuffer<'a> {
fn bound(&self) -> u64;

/// Test if the number is in the buffer. If a number is not in the buffer,
/// then it's either a composite or large than [PrimeBuffer::bound()]
/// then it's either a composite or large than [`PrimeBuffer::bound()`]
fn contains(&self, num: u64) -> bool;

/// clear the prime buffer to save memory
@@ -276,26 +280,26 @@ pub trait RandPrime<T> {
/// Generate a random prime within the given bit size limit
///
/// # Panics
/// if the bit_size is 0 or it's larger than the bit width of the integer
/// if the `bit_size` is 0 or it's larger than the bit width of the integer
fn gen_prime(&mut self, bit_size: usize, config: Option<PrimalityTestConfig>) -> T;

/// Generate a random prime with **exact** the given bit size
///
/// # Panics
/// if the bit_size is 0 or it's larger than the bit width of the integer
/// if the `bit_size` is 0 or it's larger than the bit width of the integer
fn gen_prime_exact(&mut self, bit_size: usize, config: Option<PrimalityTestConfig>) -> T;

/// Generate a random (Sophie German) safe prime within the given bit size limit. The generated prime
/// is guaranteed to pass the [is_safe_prime][crate::nt_funcs::is_safe_prime] test
/// is guaranteed to pass the [`is_safe_prime`][crate::nt_funcs::is_safe_prime] test
///
/// # Panics
/// if the bit_size is 0 or it's larger than the bit width of the integer
/// if the `bit_size` is 0 or it's larger than the bit width of the integer
fn gen_safe_prime(&mut self, bit_size: usize) -> T;

/// Generate a random (Sophie German) safe prime with the **exact** given bit size. The generated prime
/// is guaranteed to pass the [is_safe_prime][crate::nt_funcs::is_safe_prime] test
/// is guaranteed to pass the [`is_safe_prime`][crate::nt_funcs::is_safe_prime] test
///
/// # Panics
/// if the bit_size is 0 or it's larger than the bit width of the integer
/// if the `bit_size` is 0 or it's larger than the bit width of the integer
fn gen_safe_prime_exact(&mut self, bit_size: usize) -> T;
}