polynomint/math.rs
1use crate::Polynomial;
2
3impl Polynomial {
4 /// Gives a new polynomial equal to the old one times x.
5 ///
6 /// # Examples
7 /// ```
8 /// use polynomint::{Polynomial, poly};
9 ///
10 /// let first = poly![1, 2, 3];
11 /// let second = first.times_x();
12 ///
13 /// assert_eq!(second, poly![0, 1, 2, 3]);
14 /// ```
15 pub fn times_x(&self) -> Self {
16 let mut coeffs = vec![0];
17 coeffs.append(&mut self.coeffs.clone());
18 Self { coeffs }
19 }
20
21 /// Gives a new polynomial equal to the remainder of the old one when taken
22 /// modulo `n`.
23 ///
24 /// # Examples
25 /// ```
26 /// use polynomint::{Polynomial, poly};
27 ///
28 /// let poly = poly![6, -5, 3, -7, 4];
29 /// assert_eq!(poly.rem_euclid(2), poly![0, 1, 1, 1]);
30 /// assert_eq!(poly.rem_euclid(4), poly![2, 3, 3, 1]);
31 /// assert_eq!(poly.rem_euclid(5), poly![1, 0, 3, 3, 4]);
32 /// ```
33 pub fn rem_euclid(&self, n: isize) -> Self {
34 if self.is_zero() {
35 Polynomial::zero()
36 } else {
37 let mut coeffs = self.coeffs.clone();
38 for i in 0..=self.degree() {
39 coeffs[i as usize] = coeffs[i as usize].rem_euclid(n);
40 }
41 let mut output = Polynomial { coeffs };
42 output.reduce();
43 output
44 }
45 }
46
47 /// Creates a new polynomial which is the derivative of the old one.
48 ///
49 /// # Examples
50 /// ```
51 /// use polynomint::{Polynomial, poly};
52 ///
53 /// let poly1 = poly![1, -2, 5, 4]; // 4x^3 + 5x^2 - 2x + 1
54 /// assert_eq!(poly1.derivative(), poly![-2, 10, 12]); // deriv. is 12x^2 + 10x - 2
55 /// let poly2 = poly![192, 3, -4, -9, 0, 38]; // 38x^5 - 9x^3 - 4x^2 + 3x + 192
56 /// assert_eq!(poly2.derivative(), poly![3, -8, -27, 0, 190]); // deriv. is 190x^4 - 27x^2 - 8x + 3
57 /// ```
58 pub fn derivative(&self) -> Self {
59 if self.degree() <= 0 {
60 Self::zero()
61 } else {
62 let mut coeffs = Vec::new();
63 for i in 0..self.degree() {
64 coeffs.push((i + 1) * self.coeffs[i as usize + 1]);
65 }
66 let mut output = Self { coeffs };
67 output.reduce();
68 output
69 }
70 }
71
72 /// Plugs in a specific `isize` value `x` to the polynomial.
73 ///
74 /// # Examples
75 /// ```
76 /// use polynomint::{poly, Polynomial};
77 ///
78 /// let poly1 = poly![5,2,1];
79 /// let poly2 = poly![-5,4,-3,-1];
80 ///
81 /// assert_eq!(poly1.eval(1), 8);
82 /// assert_eq!(poly2.eval(1), -5);
83 ///
84 /// assert_eq!(poly1.eval(-2), 5);
85 /// assert_eq!(poly2.eval(-2), -17);
86 /// ```
87 pub fn eval(&self, x: isize) -> isize {
88 let mut acc = 0;
89 // take a polynomial like 5x^2 + 2x + 3: we can get this by: 0 *= x -> 0
90 // += 5 -> 5
91 // *= x -> 5x
92 // += 2 -> 5x + 2
93 // *= x -> 5x^2 + 2x
94 // += 3 -> 5x^2 + 2x + 3
95 // this motivates the loop
96 for &i in self.coeffs.iter().rev() {
97 acc *= x;
98 acc += i;
99 }
100 acc
101 }
102
103 /// Returns `true` if `x` is a root of the polynomial; otherwise returns `false`.
104 ///
105 /// # Examples
106 /// ```
107 /// use polynomint::{Polynomial, poly};
108 /// let poly = poly![-2, 1] * poly![-4, 1] * poly![3, 1];
109 ///
110 /// assert_eq!(poly, poly![24, -10, -3, 1]);
111 /// assert!(poly.has_root(2));
112 /// assert!(poly.has_root(4));
113 /// assert!(poly.has_root(-3));
114 /// assert!(!poly.has_root(1));
115 /// ```
116 pub fn has_root(&self, x: isize) -> bool {
117 self.eval(x) == 0
118 }
119
120 /// Returns `true` if `x` is a root of the polynomial taken modulo `div`; otherwise returns false.
121 ///
122 /// # Examples
123 /// ```
124 /// use polynomint::{Polynomial, poly};
125 ///
126 /// let poly = poly![-2, 1] * poly![-6, 1];
127 ///
128 /// assert_eq!(poly, poly![12, -8, 1]);
129 /// assert!(poly.has_root_mod(2, 5));
130 /// assert!(poly.has_root_mod(1, 5));
131 /// assert!(poly.has_root_mod(2, 3));
132 /// assert!(poly.has_root_mod(0, 3));
133 /// assert!(!poly.has_root_mod(4, 5));
134 /// ```
135 pub fn has_root_mod(&self, x: isize, div: isize) -> bool {
136 self.eval(x).rem_euclid(div) == 0
137 }
138
139 /// If `a` is a root of `self`, returns `Some(p)` where `self = p * (x - a)`.
140 /// (That is, if `a` is a root of `self`, this returns the result of factoring
141 /// `x - a` out of `self`.) Otherwise returns `None`.
142 ///
143 /// # Examples
144 /// ```
145 /// use polynomint::{Polynomial, poly};
146 ///
147 /// let poly = poly![12, -8, 1]; // x^2 - 8x + 12 = (x - 2)(x - 6)
148 /// assert_eq!(poly.factor_root(2), Some(poly![-6, 1]));
149 /// assert_eq!(poly.factor_root(6), Some(poly![-2, 1]));
150 /// assert_eq!(poly.factor_root(5), None);
151 /// ```
152 pub fn factor_root(&self, a: isize) -> Option<Self> {
153 // if not a root, we're done
154 if !self.has_root(a) {
155 None
156 // if polynomial is zero, everything's a root, and the factoring gives zero again
157 } else if self.is_zero() {
158 Some(Self::zero())
159 // if zero is a root, then we can just skip the constant and be done
160 } else if a == 0 {
161 Some(Self {
162 coeffs: self.iter().skip(1).copied().collect(),
163 })
164 // otherwise, we know that the last coefficient b[0] of the output
165 // will be -c[0]/a where c is self's coeff vec, and b[n] = (b[n-1] - c[n])/a
166 // in general; thus the loop below does what we want---
167 } else {
168 let mut coeffs = Vec::new();
169 // keep an accumulator,
170 let mut acc = 0;
171 for &coeff in self.iter().take(self.degree() as usize) {
172 // and at each step, subtract c[n] and divide by a
173 acc -= coeff;
174 acc /= a;
175 coeffs.push(acc);
176 }
177 Some(Self { coeffs })
178 }
179 }
180
181 /// If `a` is a root of `self` and if `p` is a prime, this returns the
182 /// result of factoring `x - a` out of `self`, if everything is considered
183 /// a polynomial with coefficients modulo `p`. Otherwise returns `None`.
184 ///
185 /// The API demands that `p` be prime because factoring gets more complicated
186 /// when the modulus is composite, like the integers mod 4---the example below,
187 /// `x^2 - 8x + 12`, just becomes `x^2`, but `x^2 = x^2 + 4x + 4 = (x + 2)^2`,
188 /// and unique factorization is lost.
189 ///
190 /// # Examples
191 /// ```
192 /// use polynomint::{Polynomial, poly};
193 ///
194 /// let poly = poly![12, -8, 1]; // x^2 - 8x + 12 = (x - 2)(x - 6)
195 /// // = x^2 + x (mod 3) = x(x - 2) or x(x + 1) mod 3
196 /// // = x^2 + 2x + 2 = (x - 2)(x + 4) or (x - 1)(x + 3) mod 5
197 /// assert_eq!(poly.factor_root_mod(2, 3), Some(poly![0, 1]));
198 /// assert_eq!(poly.factor_root_mod(0, 3), Some(poly![1, 1]));
199 /// assert_eq!(poly.factor_root_mod(1, 3), None);
200 /// assert_eq!(poly.factor_root_mod(2, 5), Some(poly![4, 1]));
201 /// assert_eq!(poly.factor_root_mod(1, 5), Some(poly![3, 1]));
202 /// assert_eq!(poly.factor_root_mod(0, 5), None);
203 ///
204 /// let poly2 = poly![1, 0, 1]; // x^2 + 1 = (x + 1)^2 mod 2
205 ///
206 /// assert_eq!(poly2.factor_root_mod(1, 2), Some(poly![1, 1]));
207 /// assert_eq!(poly2.factor_root_mod(0, 2), None);
208 /// ```
209 pub fn factor_root_mod(&self, a: isize, p: isize) -> Option<Self> {
210 // if not a root or p isn't prime, we're done
211 if !self.has_root_mod(a, p) || !Self::is_prime(p as usize) {
212 None
213 // if polynomial is zero, everything's a root, and the factoring gives zero again
214 } else if self.is_zero() {
215 Some(Self::zero())
216 // if zero is a root, then we can just skip the constant, reduce mod div, and be done
217 } else if a == 0 {
218 let mut output = Self {
219 coeffs: self.rem_euclid(p).iter().skip(1).copied().collect(),
220 };
221 output.reduce();
222 Some(output)
223 // otherwise, we know that the last coefficient b[0] of the output
224 // will be -c[0]/a where c is self's coeff vec, and b[n] = (b[n-1] - c[n])/a
225 // in general; thus the loop below does what we want---
226 } else {
227 let mut coeffs = Vec::new();
228 // keep an accumulator,
229 let mut acc = 0;
230 for &coeff in self.rem_euclid(p).iter().take(self.degree() as usize) {
231 // and at each step, subtract c[n] and divide by a
232 acc -= coeff;
233 acc *= Self::inv_mod_p(a.rem_euclid(p), p);
234 coeffs.push(acc.rem_euclid(p));
235 }
236 Some(Self { coeffs })
237 }
238 }
239
240 fn is_prime(p: usize) -> bool {
241 if p == 2 || p == 3 {
242 true
243 } else if p == 1 || p % 2 == 0 || p % 3 == 0 {
244 false
245 } else {
246 // we need only search for prime factors up to the sqrt of n;
247 // every prime past 3 is either 1 or 5 mod 6, so we can quickly
248 // reduce our search space to a size of approx sqrt(n)/3
249 for i in (5..((p as f64).sqrt().floor() as usize)).filter(|&x| x % 6 == 1 || x % 6 == 5)
250 {
251 if p % i == 0 {
252 return false;
253 }
254 }
255 true
256 }
257 }
258
259 fn inv_mod_p(a: isize, p: isize) -> isize {
260 let mut r_pair = (a, p);
261 let mut s_pair = (1, 0);
262 while r_pair.1 != 0 {
263 let quot = r_pair.0 / r_pair.1;
264 r_pair = (r_pair.1, r_pair.0 - quot * r_pair.1);
265 s_pair = (s_pair.1, s_pair.0 - quot * s_pair.1);
266 }
267 s_pair.0.rem_euclid(p)
268 }
269}