sciforge_lib/maths/polynomial/
poly.rs1use std::fmt;
2use std::ops::{Add, Div, Mul, Neg, Sub};
3
4#[derive(Clone, Debug)]
5pub struct Polynomial {
6 pub coeffs: Vec<f64>,
7}
8
9impl Polynomial {
10 pub fn new(coeffs: Vec<f64>) -> Self {
11 let mut p = Self { coeffs };
12 p.trim();
13 p
14 }
15
16 pub fn zero() -> Self {
17 Self { coeffs: vec![0.0] }
18 }
19 pub fn one() -> Self {
20 Self { coeffs: vec![1.0] }
21 }
22 pub fn monomial(degree: usize, coeff: f64) -> Self {
23 let mut c = vec![0.0; degree + 1];
24 c[degree] = coeff;
25 Self { coeffs: c }
26 }
27
28 fn trim(&mut self) {
29 while self.coeffs.len() > 1 && self.coeffs.last().is_some_and(|&c| c.abs() < 1e-30) {
30 self.coeffs.pop();
31 }
32 }
33
34 pub fn degree(&self) -> usize {
35 self.coeffs.len().saturating_sub(1)
36 }
37
38 pub fn eval(&self, x: f64) -> f64 {
39 let mut result = 0.0;
40 for c in self.coeffs.iter().rev() {
41 result = result * x + c;
42 }
43 result
44 }
45
46 pub fn derivative(&self) -> Self {
47 if self.coeffs.len() <= 1 {
48 return Self::zero();
49 }
50 Self::new(
51 self.coeffs
52 .iter()
53 .enumerate()
54 .skip(1)
55 .map(|(i, &c)| c * i as f64)
56 .collect(),
57 )
58 }
59
60 pub fn integral(&self, constant: f64) -> Self {
61 let mut coeffs = vec![constant];
62 for (i, &c) in self.coeffs.iter().enumerate() {
63 coeffs.push(c / (i + 1) as f64);
64 }
65 Self::new(coeffs)
66 }
67
68 pub fn definite_integral(&self, a: f64, b: f64) -> f64 {
69 let anti = self.integral(0.0);
70 anti.eval(b) - anti.eval(a)
71 }
72
73 pub fn scale(&self, s: f64) -> Self {
74 Self::new(self.coeffs.iter().map(|c| c * s).collect())
75 }
76
77 pub fn compose(&self, other: &Self) -> Self {
78 let mut result = Self::zero();
79 let mut power = Self::one();
80 for &c in &self.coeffs {
81 result = result + power.scale(c);
82 power = power.clone() * other.clone();
83 }
84 result
85 }
86
87 pub fn div_rem(&self, divisor: &Self) -> (Self, Self) {
88 if divisor.coeffs.iter().all(|c| c.abs() < 1e-30) {
89 panic!("division by zero polynomial");
90 }
91 let mut remainder = self.coeffs.clone();
92 let d_deg = divisor.degree();
93 let lead = *divisor.coeffs.last().unwrap();
94 let mut quotient = vec![];
95
96 while remainder.len() > d_deg && !remainder.is_empty() {
97 let coeff = *remainder.last().unwrap() / lead;
98 quotient.push(coeff);
99 for (i, &dc) in divisor.coeffs.iter().enumerate() {
100 let idx = remainder.len() - d_deg - 1 + i;
101 remainder[idx] -= coeff * dc;
102 }
103 remainder.pop();
104 }
105 quotient.reverse();
106 if quotient.is_empty() {
107 quotient.push(0.0);
108 }
109 (Self::new(quotient), Self::new(remainder))
110 }
111
112 pub fn gcd(&self, other: &Self) -> Self {
113 let mut a = self.clone();
114 let mut b = other.clone();
115 while b.coeffs.iter().any(|c| c.abs() > 1e-30) {
116 let (_, r) = a.div_rem(&b);
117 a = b;
118 b = r;
119 }
120 let lead = *a.coeffs.last().unwrap_or(&1.0);
121 if lead.abs() > 1e-30 {
122 a.scale(1.0 / lead)
123 } else {
124 a
125 }
126 }
127
128 pub fn from_roots(roots: &[f64]) -> Self {
129 let mut result = Self::one();
130 for &r in roots {
131 result = result * Self::new(vec![-r, 1.0]);
132 }
133 result
134 }
135}
136
137impl Add for Polynomial {
138 type Output = Self;
139 fn add(self, rhs: Self) -> Self {
140 let n = self.coeffs.len().max(rhs.coeffs.len());
141 let mut coeffs = vec![0.0; n];
142 for (i, &c) in self.coeffs.iter().enumerate() {
143 coeffs[i] += c;
144 }
145 for (i, &c) in rhs.coeffs.iter().enumerate() {
146 coeffs[i] += c;
147 }
148 Self::new(coeffs)
149 }
150}
151
152impl Sub for Polynomial {
153 type Output = Self;
154 fn sub(self, rhs: Self) -> Self {
155 let n = self.coeffs.len().max(rhs.coeffs.len());
156 let mut coeffs = vec![0.0; n];
157 for (i, &c) in self.coeffs.iter().enumerate() {
158 coeffs[i] += c;
159 }
160 for (i, &c) in rhs.coeffs.iter().enumerate() {
161 coeffs[i] -= c;
162 }
163 Self::new(coeffs)
164 }
165}
166
167impl Mul for Polynomial {
168 type Output = Self;
169 fn mul(self, rhs: Self) -> Self {
170 let mut coeffs = vec![0.0; self.coeffs.len() + rhs.coeffs.len() - 1];
171 for (i, &a) in self.coeffs.iter().enumerate() {
172 for (j, &b) in rhs.coeffs.iter().enumerate() {
173 coeffs[i + j] += a * b;
174 }
175 }
176 Self::new(coeffs)
177 }
178}
179
180impl Div for Polynomial {
181 type Output = Self;
182 fn div(self, rhs: Self) -> Self {
183 let (q, _) = self.div_rem(&rhs);
184 q
185 }
186}
187
188impl Neg for Polynomial {
189 type Output = Self;
190 fn neg(self) -> Self {
191 self.scale(-1.0)
192 }
193}
194
195impl fmt::Display for Polynomial {
196 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
197 let mut terms = vec![];
198 for (i, &c) in self.coeffs.iter().enumerate().rev() {
199 if c.abs() < 1e-30 {
200 continue;
201 }
202 match i {
203 0 => terms.push(format!("{c}")),
204 1 => terms.push(format!("{c}x")),
205 _ => terms.push(format!("{c}x^{i}")),
206 }
207 }
208 if terms.is_empty() {
209 write!(f, "0")
210 } else {
211 write!(f, "{}", terms.join(" + "))
212 }
213 }
214}