oxiz_math/polynomial/
constructors.rs1use super::types::*;
4#[allow(unused_imports)]
5use crate::prelude::*;
6use num_bigint::BigInt;
7use num_rational::BigRational;
8use num_traits::{One, Zero};
9
10impl super::Polynomial {
11 #[inline]
13 pub fn zero() -> Self {
14 Self {
15 terms: Vec::new(),
16 order: MonomialOrder::default(),
17 }
18 }
19
20 #[inline]
22 pub fn one() -> Self {
23 Self::constant(BigRational::one())
24 }
25
26 pub fn constant(c: BigRational) -> Self {
28 if c.is_zero() {
29 Self::zero()
30 } else {
31 Self {
32 terms: vec![Term::constant(c)],
33 order: MonomialOrder::default(),
34 }
35 }
36 }
37
38 pub fn from_var(var: Var) -> Self {
40 Self {
41 terms: vec![Term::from_var(var)],
42 order: MonomialOrder::default(),
43 }
44 }
45
46 pub fn from_var_power(var: Var, power: u32) -> Self {
48 if power == 0 {
49 Self::one()
50 } else {
51 Self {
52 terms: vec![Term::new(
53 BigRational::one(),
54 Monomial::from_var_power(var, power),
55 )],
56 order: MonomialOrder::default(),
57 }
58 }
59 }
60
61 pub fn from_terms(terms: impl IntoIterator<Item = Term>, order: MonomialOrder) -> Self {
63 let mut poly = Self {
64 terms: terms.into_iter().filter(|t| !t.is_zero()).collect(),
65 order,
66 };
67 poly.normalize();
68 poly
69 }
70
71 pub fn from_coeffs_int(coeffs: &[(i64, &[(Var, u32)])]) -> Self {
73 let terms: Vec<Term> = coeffs
74 .iter()
75 .map(|(c, powers)| {
76 Term::new(
77 BigRational::from_integer(BigInt::from(*c)),
78 Monomial::from_powers(powers.iter().copied()),
79 )
80 })
81 .collect();
82 Self::from_terms(terms, MonomialOrder::default())
83 }
84
85 pub fn linear(coeffs: &[(BigRational, Var)], constant: BigRational) -> Self {
87 let mut terms: Vec<Term> = coeffs
88 .iter()
89 .filter(|(c, _)| !c.is_zero())
90 .map(|(c, v)| Term::new(c.clone(), Monomial::from_var(*v)))
91 .collect();
92
93 if !constant.is_zero() {
94 terms.push(Term::constant(constant));
95 }
96
97 Self::from_terms(terms, MonomialOrder::default())
98 }
99
100 pub fn univariate(var: Var, coeffs: &[BigRational]) -> Self {
103 let terms: Vec<Term> = coeffs
104 .iter()
105 .enumerate()
106 .filter(|(_, c)| !c.is_zero())
107 .map(|(i, c)| Term::new(c.clone(), Monomial::from_var_power(var, i as u32)))
108 .collect();
109 Self::from_terms(terms, MonomialOrder::default())
110 }
111
112 #[inline]
114 pub fn is_zero(&self) -> bool {
115 self.terms.is_empty()
116 }
117
118 #[inline]
120 pub fn is_constant(&self) -> bool {
121 self.terms.len() == 1 && self.terms[0].monomial.is_unit()
122 }
123
124 pub fn constant_value(&self) -> BigRational {
129 if self.is_zero() {
130 BigRational::zero()
131 } else if self.is_constant() {
132 self.terms[0].coeff.clone()
133 } else {
134 BigRational::zero()
135 }
136 }
137
138 pub fn is_one(&self) -> bool {
140 self.terms.len() == 1 && self.terms[0].monomial.is_unit() && self.terms[0].coeff.is_one()
141 }
142
143 pub fn is_univariate(&self) -> bool {
145 if self.terms.is_empty() {
146 return true;
147 }
148
149 let mut var: Option<Var> = None;
150 for term in &self.terms {
151 for vp in term.monomial.vars() {
152 match var {
153 None => var = Some(vp.var),
154 Some(v) if v != vp.var => return false,
155 _ => {}
156 }
157 }
158 }
159 true
160 }
161
162 pub fn is_linear(&self) -> bool {
164 self.terms.iter().all(|t| t.monomial.is_linear())
165 }
166
167 #[inline]
169 pub fn num_terms(&self) -> usize {
170 self.terms.len()
171 }
172
173 #[inline]
175 pub fn terms(&self) -> &[Term] {
176 &self.terms
177 }
178
179 pub fn total_degree(&self) -> u32 {
181 self.terms
182 .iter()
183 .map(|t| t.monomial.total_degree())
184 .max()
185 .unwrap_or(0)
186 }
187
188 pub fn degree(&self, var: Var) -> u32 {
190 self.terms
191 .iter()
192 .map(|t| t.monomial.degree(var))
193 .max()
194 .unwrap_or(0)
195 }
196
197 pub fn max_var(&self) -> Var {
199 self.terms
200 .iter()
201 .map(|t| t.monomial.max_var())
202 .filter(|&v| v != NULL_VAR)
203 .max()
204 .unwrap_or(NULL_VAR)
205 }
206
207 pub fn vars(&self) -> Vec<Var> {
209 let mut vars: Vec<Var> = self
210 .terms
211 .iter()
212 .flat_map(|t| t.monomial.vars().iter().map(|vp| vp.var))
213 .collect();
214 vars.sort_unstable();
215 vars.dedup();
216 vars
217 }
218
219 #[inline]
221 pub fn leading_term(&self) -> Option<&Term> {
222 self.terms.first()
223 }
224
225 pub fn leading_coeff(&self) -> BigRational {
227 self.terms
228 .first()
229 .map(|t| t.coeff.clone())
230 .unwrap_or_else(BigRational::zero)
231 }
232
233 pub fn leading_monomial(&self) -> Option<&Monomial> {
235 self.terms.first().map(|t| &t.monomial)
236 }
237
238 pub fn constant_term(&self) -> BigRational {
240 self.terms
241 .iter()
242 .find(|t| t.monomial.is_unit())
243 .map(|t| t.coeff.clone())
244 .unwrap_or_else(BigRational::zero)
245 }
246
247 pub fn univ_coeff(&self, var: Var, k: u32) -> BigRational {
249 for term in &self.terms {
250 if term.monomial.degree(var) == k && term.monomial.num_vars() <= 1 {
251 return term.coeff.clone();
252 }
253 }
254 BigRational::zero()
255 }
256
257 pub fn coeff(&self, var: Var, k: u32) -> super::Polynomial {
260 let terms: Vec<Term> = self
261 .terms
262 .iter()
263 .filter(|t| t.monomial.degree(var) == k)
264 .map(|t| {
265 let new_mon = if let Some(m) = t.monomial.div(&Monomial::from_var_power(var, k)) {
266 m
267 } else {
268 Monomial::unit()
269 };
270 Term::new(t.coeff.clone(), new_mon)
271 })
272 .collect();
273 super::Polynomial::from_terms(terms, self.order)
274 }
275
276 pub fn leading_coeff_wrt(&self, var: Var) -> super::Polynomial {
278 let d = self.degree(var);
279 self.coeff(var, d)
280 }
281
282 pub(crate) fn normalize(&mut self) {
284 if self.terms.is_empty() {
285 return;
286 }
287
288 let order = self.order;
290 self.terms
291 .sort_by(|a, b| order.compare(&b.monomial, &a.monomial));
292
293 let mut i = 0;
295 while i < self.terms.len() {
296 let mut j = i + 1;
297 while j < self.terms.len() && self.terms[j].monomial == self.terms[i].monomial {
298 let coeff = self.terms[j].coeff.clone();
299 self.terms[i].coeff += coeff;
300 j += 1;
301 }
302 if j > i + 1 {
304 self.terms.drain((i + 1)..j);
305 }
306 i += 1;
307 }
308
309 self.terms.retain(|t| !t.coeff.is_zero());
311 }
312}