math_comb/lib.rs
1mod modexp;
2mod pollard;
3
4/// A struct that provides methods for prime factorization using pollard rho algorithm and testing primality of numbers.
5pub struct Prime {}
6
7impl Prime {
8 /// Pollard's rho algorithm for integer factorization.
9 ///
10 /// # Arguments
11 ///
12 /// * `n` - The number to factorize.
13 ///
14 /// # Returns
15 ///
16 /// A non-trivial factor of `n`.
17 ///
18 /// # Time Complexity
19 /// The algorithm offers a trade-off between its running time and the probability that it finds a factor.
20 /// A prime divisor can be achieved with a probability around 0.5, in O(?d) <= O(`n`^(1/4)) iterations.
21 /// This is a heuristic claim, and rigorous analysis of the algorithm remains open.
22 pub fn pollard(n: u64) -> u64 {
23 return pollard::pollard(n);
24 }
25
26 /// Factorizes `n` into its prime factors.
27 ///
28 /// # Arguments
29 ///
30 /// * `n` - The number to factorize.
31 ///
32 /// # Returns
33 ///
34 /// A vector containing the prime factors of `n` in sorted order.
35 pub fn factor(n: u64) -> Vec<u64> {
36 return pollard::factor(n);
37 }
38
39 /// Checks if `n` is a prime number.
40 ///
41 /// # Arguments
42 ///
43 /// * `n` - The number to check.
44 ///
45 /// # Returns
46 ///
47 /// `true` if `n` is prime, `false` otherwise.
48 pub fn is_prime(n: u64) -> bool {
49 return pollard::is_prime(n);
50 }
51}
52
53pub struct Spf {
54 spf_max_limit: usize,
55 spf: Vec<u64>
56}
57
58/// A struct representing the smallest prime factor (SPF) computation.
59impl Spf {
60 /// Creates a new `Spf` instance with a given maximum limit.
61 ///
62 /// # Arguments
63 ///
64 /// * `max_limit` - The maximum limit up to which the smallest prime factors are computed.
65 ///
66 /// # Returns
67 ///
68 /// A new `Spf` instance with precomputed smallest prime factors up to `max_limit`.
69 pub fn new(max_limit: usize) -> Spf {
70 let mut spf = vec![0; max_limit + 1];
71 for i in 2..=max_limit {
72 if spf[i] == 0 {
73 for j in (i..=max_limit).step_by(i) {
74 if spf[j] == 0 {
75 spf[j] = i as u64;
76 }
77 }
78 }
79 }
80 Spf {
81 spf_max_limit: max_limit,
82 spf: spf,
83 }
84 }
85
86 /// Retrieves the smallest prime factor of a given number.
87 ///
88 /// # Arguments
89 ///
90 /// * `x` - The number for which the smallest prime factor is to be retrieved.
91 ///
92 /// # Returns
93 ///
94 /// The smallest prime factor of `x`.
95 ///
96 /// # Panics
97 ///
98 /// Panics if `x` is greater than the `max_limit` specified during the creation of the `Spf` instance.
99 pub fn get_spf(&self, x: u64) -> u64 {
100 if x as usize > self.spf_max_limit {
101 panic!("x cannot be greater than max_limit!");
102 }
103 self.spf[x as usize]
104 }
105
106 /// Factorizes a given number into its prime factors.
107 ///
108 /// # Arguments
109 ///
110 /// * `x` - The number to be factorized.
111 ///
112 /// # Returns
113 ///
114 /// A vector containing the prime factors of `x`.
115 ///
116 /// # Panics
117 ///
118 /// Panics if `x` is greater than the `max_limit` specified during the creation of the `Spf` instance.
119 ///
120 /// # Complexity
121 ///
122 /// The factorization process takes O(log n) time after the SPF computation.
123 pub fn factorize(&self, x: u64) -> Vec<u64> {
124 if x as usize > self.spf_max_limit {
125 panic!("x cannot be greater than max_limit!");
126 }
127 let mut factors: Vec<u64> = Vec::new();
128 let mut y: usize = x as usize;
129 while y != 1 {
130 factors.push(self.spf[y]);
131 y /= self.spf[y] as usize;
132 }
133 factors.sort();
134 factors
135 }
136}
137
138/// A struct that provides methods for modular exponentiation and modular inverse calculations.
139pub struct Modexp {}
140
141impl Modexp {
142 /// Calculates (base^exponent) % modulus using modular exponentiation.
143 ///
144 /// # Arguments
145 ///
146 /// * `base` - The base.
147 /// * `exponent` - The exponent.
148 /// * `modulus` - The modulus.
149 pub fn mod_exp(base: u64, exponent: u64, modulus: u64) -> u64 {
150 return modexp::mod_exp(base, exponent, modulus);
151 }
152
153 /// Calculates the modular multiplicative inverse of `x` modulo `modulus`.
154 ///
155 /// The modular inverse of `x` modulo `modulus` is an integer `y` such that
156 /// (x * y) % modulus == 1. It exists if and only if `x` and `modulus` are coprime
157 /// (i.e., their greatest common divisor is 1).
158 ///
159 /// This function uses Fermat's Little Theorem, which states that if `modulus` is a prime number,
160 /// then for any integer `x` not divisible by `modulus`, `x` ^ (`modulus` - 1) ≡ 1 (mod `modulus`).
161 /// Therefore, the modular inverse of `x` is `x` ^ (`modulus` - 2) (mod `modulus`).
162 ///
163 /// # Arguments
164 ///
165 /// * `x` - The number for which to calculate the inverse.
166 /// * `modulus` - The modulus.
167 ///
168 /// # Returns
169 ///
170 /// The modular inverse of `x` modulo `modulus`.
171 ///
172 /// # Panics
173 ///
174 /// This function will panic if:
175 /// * `modulus` is 0.
176 /// * `x` and `modulus` are not coprime (their greatest common divisor is not 1).
177 pub fn mod_inv(x: u64, modulus: u64) -> u64 {
178 return modexp::mod_inv(x, modulus);
179 }
180}
181
182/// A struct for pre-calculating factorials and their modular inverses,
183/// useful for efficient combination and permutation calculations under mod.
184pub struct Comb {
185 mod_value: u64,
186 max_fact: usize,
187 fact: Vec<u64>,
188 inv_fact: Vec<u64>
189}
190
191impl Comb {
192 /// Creates a new `Comb` instance, pre-calculating factorials and their
193 /// modular inverses up to `max_fact`.
194 ///
195 /// This pre-computation allows for fast calculation of combinations and permutations
196 /// modulo `mod_value`.
197 ///
198 /// # Arguments
199 ///
200 /// * `mod_value` - The modulus to use for calculations.
201 /// * `max_fact` - The maximum number for which factorials and inverse
202 /// factorials will be pre-calculated. This determines the
203 /// range of `n` that can be used in `nCr` and `nPr` without
204 /// requiring further calculations.
205 /// # Panics
206 ///
207 /// Panics if modulus is not prime.
208 pub fn new(mod_value: u64, max_fact: usize) -> Comb {
209 if !Self::check_prime(mod_value) {
210 panic!("modulus is not prime!");
211 }
212
213 let mut fact: Vec<u64> = vec![0; max_fact + 1];
214 let mut inv_fact: Vec<u64> = vec![0; max_fact + 1];
215
216 fact[0] = 1;
217
218 for i in 1..=max_fact {
219 fact[i] = (fact[i - 1] * (i as u64)) % mod_value;
220 }
221 inv_fact[max_fact] = Modexp::mod_inv(fact[max_fact] as u64, mod_value);
222 for i in (0..max_fact).rev() {
223 inv_fact[i] = (inv_fact[i + 1] * ((i + 1) as u64)) % mod_value;
224 }
225
226 Comb {
227 mod_value: mod_value,
228 max_fact: max_fact,
229 fact: fact,
230 inv_fact: inv_fact
231 }
232 }
233
234 /// Calculates nPr (n permutations of r) under mod.
235 ///
236 /// # Arguments
237 ///
238 /// * `n` - The total number of items.
239 /// * `r` - The number of items to choose.
240 ///
241 /// # Panics
242 ///
243 /// Panics if `n` is less than `r` or `n` > `max_fact`.
244 pub fn nPr(&self, n: u64, r: u64) -> u64 {
245 if n < r {
246 panic!("n cannot be less than r!")
247 } else if n > (self.max_fact as u64) {
248 panic!("n cannot be greater than {}!", self.max_fact);
249 } else {
250 return (self.fact[n as usize] * self.inv_fact[r as usize]) % self.mod_value;
251 }
252 }
253
254 /// Calculates nCr (n combinations of r) under mod.
255 ///
256 /// # Arguments
257 ///
258 /// * `n` - The total number of items.
259 /// * `r` - The number of items to choose.
260 ///
261 /// # Panics
262 ///
263 /// Panics if `n` is less than `r` or `n` > `max_fact`.
264 pub fn nCr(&self, n: u64, r: u64) -> u64 {
265 if n < r {
266 panic!("n cannot be less than r!");
267 } else if n > (self.max_fact as u64) {
268 panic!("n cannot be greater than {}!", self.max_fact);
269 } else {
270 return (self.nPr(n, r) * self.inv_fact[(n - r) as usize]) % self.mod_value;
271 }
272 }
273
274 fn check_prime(n: u64) -> bool {
275 let mut _x: u64 = 2;
276 while _x * _x <= n {
277 if n % _x == 0 {
278 return false
279 }
280 _x = _x + 1;
281 }
282 return true;
283 }
284
285}
286
287#[cfg(test)]
288mod tests {
289 use super::*;
290
291 #[test]
292 fn test_ncr() {
293 let comb: Comb = Comb::new(1000000007, 5);
294 assert_eq!(comb.nCr(5, 2), 10);
295 assert_eq!(comb.nCr(4, 0), 1);
296 assert_eq!(comb.nCr(4, 4), 1);
297 }
298
299 #[test]
300 fn test_npr() {
301 let comb: Comb = Comb::new(1000000007, 5);
302 assert_eq!(comb.nPr(5, 2), 60);
303 assert_eq!(comb.nPr(5, 0), 120);
304 assert_eq!(comb.nPr(5, 5), 1);
305 }
306
307 #[test]
308 fn test_ncr_small_mod() {
309 let comb: Comb = Comb::new(7, 5);
310 assert_eq!(comb.nCr(5, 2), 3);
311 assert_eq!(comb.nCr(4, 0), 1);
312 assert_eq!(comb.nCr(4, 3), 4);
313 assert_eq!(comb.nCr(5, 0), 1);
314
315 let comb: Comb = Comb::new(2, 1);
316 assert_eq!(comb.nCr(1, 1), 1);
317 assert_eq!(comb.nCr(1, 0), 1);
318 assert_eq!(comb.nCr(0, 0), 1);
319 }
320
321 #[test]
322 fn test_npr_small_mod() {
323 let comb: Comb = Comb::new(7, 5);
324 assert_eq!(comb.nPr(5, 2), 4);
325 assert_eq!(comb.nPr(4, 0), 3);
326 assert_eq!(comb.nPr(4, 3), 4);
327 let comb: Comb = Comb::new(2, 1);
328 assert_eq!(comb.nPr(1, 1), 1);
329 assert_eq!(comb.nPr(1, 0), 1);
330 assert_eq!(comb.nPr(0, 0), 1);
331 }
332
333 #[test]
334 #[should_panic(expected = "n cannot be less than r!")]
335 fn test_ncr_panic() {
336 let comb = Comb::new(1000000007, 5);
337 comb.nCr(2, 5);
338 }
339
340 #[test]
341 #[should_panic(expected = "n cannot be less than r!")]
342 fn test_npr_panic() {
343 let comb = Comb::new(1000000007, 5);
344 comb.nPr(2, 5);
345 }
346
347 #[test]
348 #[should_panic(expected = "n cannot be greater than 5!")]
349 fn test_n_greater_than_max_fact_panic() {
350 let comb: Comb = Comb::new(13, 5);
351 comb.nCr(10, 3);
352 }
353
354 #[test]
355 #[should_panic(expected = "modulus is not prime!")]
356 fn test_composite_mod() {
357 let comb: Comb = Comb::new(4, 14);
358 }
359
360 #[test]
361 pub fn test_spf() {
362 let spf: Spf = Spf::new(10000000);
363 assert_eq!(spf.get_spf(7), 7);
364 assert_eq!(spf.get_spf(25), 5);
365 assert_eq!(spf.get_spf(2491), 47);
366 assert_eq!(spf.get_spf(10000000), 2);
367 assert_eq!(spf.get_spf(81), 3);
368 }
369
370 #[test]
371 fn test_get_factors_via_spf() {
372 let spf: Spf = Spf::new(10000000);
373 assert_eq!(spf.factorize(1000429), vec![1000429]);
374 assert_eq!(spf.factorize(24), vec![2, 2, 2, 3]);
375 assert_eq!(spf.factorize(45), vec![3, 3, 5]);
376 assert_eq!(spf.factorize(346789), vec![239, 1451]);
377 }
378
379 #[test]
380 #[should_panic(expected = "x cannot be greater than max_limit!")]
381 fn test_spf_factorize_above_limit() {
382 let spf: Spf = Spf::new(15);
383 spf.factorize(16);
384 }
385
386 #[test]
387 #[should_panic(expected = "x cannot be greater than max_limit!")]
388 fn test_spf_above_limit() {
389 let spf: Spf = Spf::new(15);
390 spf.get_spf(16);
391 }
392}