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}