oxiz_math/polynomial/
arithmetic.rs1use super::types::*;
4#[allow(unused_imports)]
5use crate::prelude::*;
6use num_rational::BigRational;
7use num_traits::{One, Zero};
8
9impl super::Polynomial {
10 pub fn neg(&self) -> super::Polynomial {
12 super::Polynomial {
13 terms: self
14 .terms
15 .iter()
16 .map(|t| Term::new(-t.coeff.clone(), t.monomial.clone()))
17 .collect(),
18 order: self.order,
19 }
20 }
21
22 pub fn add(&self, other: &super::Polynomial) -> super::Polynomial {
24 let mut terms: Vec<Term> = self.terms.clone();
25 terms.extend(other.terms.iter().cloned());
26 super::Polynomial::from_terms(terms, self.order)
27 }
28
29 pub fn sub(&self, other: &super::Polynomial) -> super::Polynomial {
31 self.add(&other.neg())
32 }
33
34 pub fn scale(&self, c: &BigRational) -> super::Polynomial {
36 if c.is_zero() {
37 return super::Polynomial::zero();
38 }
39 if c.is_one() {
40 return self.clone();
41 }
42 super::Polynomial {
43 terms: self
44 .terms
45 .iter()
46 .map(|t| Term::new(&t.coeff * c, t.monomial.clone()))
47 .collect(),
48 order: self.order,
49 }
50 }
51
52 pub fn mul(&self, other: &super::Polynomial) -> super::Polynomial {
55 if self.is_zero() || other.is_zero() {
56 return super::Polynomial::zero();
57 }
58
59 if self.is_univariate()
61 && other.is_univariate()
62 && self.max_var() == other.max_var()
63 && self.terms.len() >= 16
64 && other.terms.len() >= 16
65 {
66 return self.mul_karatsuba(other);
67 }
68
69 let mut terms: Vec<Term> = Vec::with_capacity(self.terms.len() * other.terms.len());
70
71 for t1 in &self.terms {
72 for t2 in &other.terms {
73 terms.push(Term::new(
74 &t1.coeff * &t2.coeff,
75 t1.monomial.mul(&t2.monomial),
76 ));
77 }
78 }
79
80 super::Polynomial::from_terms(terms, self.order)
81 }
82
83 fn mul_karatsuba(&self, other: &super::Polynomial) -> super::Polynomial {
88 debug_assert!(self.is_univariate() && other.is_univariate());
89 debug_assert!(self.max_var() == other.max_var());
90
91 let var = self.max_var();
92 let deg1 = self.degree(var);
93 let deg2 = other.degree(var);
94
95 if deg1 <= 8 || deg2 <= 8 {
97 let mut terms: Vec<Term> = Vec::with_capacity(self.terms.len() * other.terms.len());
98 for t1 in &self.terms {
99 for t2 in &other.terms {
100 terms.push(Term::new(
101 &t1.coeff * &t2.coeff,
102 t1.monomial.mul(&t2.monomial),
103 ));
104 }
105 }
106 return super::Polynomial::from_terms(terms, self.order);
107 }
108
109 let split = deg1.max(deg2).div_ceil(2);
111
112 let (low0, high0) = self.split_at_degree(var, split);
114
115 let (low1, high1) = other.split_at_degree(var, split);
117
118 let z0 = low0.mul_karatsuba(&low1); let z2 = high0.mul_karatsuba(&high1); let sum0 = super::Polynomial::add(&low0, &high0);
125 let sum1 = super::Polynomial::add(&low1, &high1);
126 let z1_temp = sum0.mul_karatsuba(&sum1);
127
128 let z1 = super::Polynomial::sub(&super::Polynomial::sub(&z1_temp, &z0), &z2);
130
131 let x_split = Monomial::from_var_power(var, split);
133 let x_2split = Monomial::from_var_power(var, 2 * split);
134
135 let term1 = z1.mul_monomial(&x_split);
136 let term2 = z2.mul_monomial(&x_2split);
137
138 super::Polynomial::add(&super::Polynomial::add(&z0, &term1), &term2)
139 }
140
141 fn split_at_degree(&self, var: Var, deg: u32) -> (super::Polynomial, super::Polynomial) {
144 let mut low_terms = Vec::new();
145 let mut high_terms = Vec::new();
146
147 for term in &self.terms {
148 let term_deg = term.monomial.degree(var);
149 if term_deg < deg {
150 low_terms.push(term.clone());
151 } else {
152 if let Some(new_mon) = term.monomial.div(&Monomial::from_var_power(var, deg)) {
154 high_terms.push(Term::new(term.coeff.clone(), new_mon));
155 }
156 }
157 }
158
159 let low = if low_terms.is_empty() {
160 super::Polynomial::zero()
161 } else {
162 super::Polynomial::from_terms(low_terms, self.order)
163 };
164
165 let high = if high_terms.is_empty() {
166 super::Polynomial::zero()
167 } else {
168 super::Polynomial::from_terms(high_terms, self.order)
169 };
170
171 (low, high)
172 }
173
174 pub fn mul_monomial(&self, m: &Monomial) -> super::Polynomial {
176 if m.is_unit() {
177 return self.clone();
178 }
179 super::Polynomial {
180 terms: self
181 .terms
182 .iter()
183 .map(|t| Term::new(t.coeff.clone(), t.monomial.mul(m)))
184 .collect(),
185 order: self.order,
186 }
187 }
188
189 pub fn pow(&self, k: u32) -> super::Polynomial {
191 if k == 0 {
192 return super::Polynomial::one();
193 }
194 if k == 1 {
195 return self.clone();
196 }
197 if self.is_zero() {
198 return super::Polynomial::zero();
199 }
200
201 let mut result = super::Polynomial::one();
203 let mut base = self.clone();
204 let mut exp = k;
205
206 while exp > 0 {
207 if exp & 1 == 1 {
208 result = super::Polynomial::mul(&result, &base);
209 }
210 base = super::Polynomial::mul(&base, &base);
211 exp >>= 1;
212 }
213
214 result
215 }
216}