prime_data/data/factors/mod.rs
1//! Module dedicated to factorizing numbers
2use super::{PrimeData, utils::IntSqrt};
3use std::collections::HashMap;
4
5/// Retrieves every factor of x
6///
7/// *This function is only available with the `factors` feature enabled.*
8///
9/// A factor is any number that divides x. Therefore, it includes 1 and x itself.
10///
11/// This function is simply an abstraction over creating the [`Factorization`] struct
12/// and calling [`Factorization::all_factors`].
13///
14/// **Note**: The returned vector will have length 1, if and only if x is 1. It will have
15/// length 2 if and only if x is prime. However, it's much faster to verify if a number
16/// is prime using [PrimeData](`crate::PrimeData`).
17///
18/// # Examples
19///
20/// ```
21/// use prime_data::all_factors_of;
22///
23/// assert_eq!(all_factors_of(1), vec![1]);
24/// assert_eq!(all_factors_of(3), vec![1, 3]);
25/// assert_eq!(all_factors_of(6), vec![1, 2, 3, 6]);
26/// ```
27pub fn all_factors_of(x: u64) -> Vec<u64> {
28 Factorization::from(x).all_factors()
29}
30
31/// Represents some number into its prime-factorized form
32///
33/// *This struct is only available with the `factors` feature enabled.*
34pub struct Factorization {
35 data: HashMap<u64, u32>
36}
37
38impl Factorization {
39 /// Converts some factorization into the original number without consuming itself
40 ///
41 /// # Examples
42 ///
43 /// ```
44 /// use prime_data::Factorization;
45 ///
46 /// assert_eq!(1, Factorization::from(1).as_u64());
47 /// assert_eq!(12, Factorization::from(12).as_u64());
48 /// assert_eq!(29375346, Factorization::from(29375346).as_u64());
49 /// ```
50 pub fn as_u64(&self) -> u64 {
51 self.data.iter()
52 .fold(1u64, |acc, (&prime, &amount)| acc * prime.pow(amount))
53 }
54
55 /// Retrieves the factorization as a tuple (prime, amount)
56 ///
57 /// Note that if the vector is empty, it means the original number is 1.
58 ///
59 /// # Examples
60 ///
61 /// ```
62 /// use prime_data::Factorization;
63 ///
64 /// // 43560 = 2^3 * 3^2 * 5 * 11^2
65 /// let factorization = Factorization::from(43560);
66 /// assert_eq!(
67 /// factorization.as_tuples(),
68 /// vec![(2, 3), (3, 2), (5, 1), (11, 2)]
69 /// );
70 /// ```
71 pub fn as_tuples(&self) -> Vec<(u64, u32)> {
72 let mut vec: Vec<(u64, u32)> = self.data.iter().map(|(&p, &c)| (p, c)).collect();
73 vec.sort_by(|a, b| a.0.cmp(&(b.0)));
74
75 vec
76 }
77
78 /// Retrieves all possible factors of the factorized number
79 ///
80 /// It does so by multiplying every possible combination of its prime factors.
81 ///
82 /// **Note**: Includes 1 and itself. Therefore, the minimal length for this vector
83 /// is 1, happening when the original numbers is 1, then length 2, if and only if
84 /// the original number is prime.
85 ///
86 /// # Examples
87 ///
88 /// ```
89 /// use prime_data::Factorization;
90 ///
91 /// let thirty = Factorization::from(30);
92 /// assert_eq!(
93 /// thirty.all_factors(),
94 /// vec![1, 2, 3, 5, 6, 10, 15, 30]
95 /// );
96 /// ```
97 pub fn all_factors(&self) -> Vec<u64> {
98 let tuples = self.as_tuples();
99 let mut vector = Self::factor_combos(&tuples);
100 vector.sort();
101
102 vector
103 }
104}
105
106// private methods
107impl Factorization {
108 pub(crate) fn new() -> Self {
109 Self { data: HashMap::new() }
110 }
111
112 pub(crate) fn add_factor(&mut self, factor: u64) {
113 if let Some(amount) = self.data.get_mut(&factor) {
114 *amount += 1;
115 } else {
116 self.data.insert(factor, 1);
117 }
118 }
119
120 pub(crate) fn is_empty(&self) -> bool {
121 self.data.is_empty()
122 }
123
124 fn factor_combos(slice: &[(u64, u32)]) -> Vec<u64> {
125 if slice.len() == 0 {
126 vec![1]
127 } else {
128 let inner_combos = Self::factor_combos(&slice[1..]);
129 let (this_prime, amount) = slice[0];
130
131 let mut combinations = Vec::new();
132 for pow in 0..=amount {
133 let new_factor = this_prime.pow(pow);
134 combinations.append(&mut (inner_combos.iter().map(|&x| new_factor * x).collect()));
135 }
136
137 combinations
138 }
139 }
140}
141
142impl From<u64> for Factorization {
143 fn from(number: u64) -> Factorization {
144 let prime_data = PrimeData::generate(0..=(number.sqrt_floor()));
145
146 prime_data.factorize(number)
147 }
148}
149