1use std::fmt::{Display, Debug};
18use std::ops::{Add, AddAssign, Sub, SubAssign, Mul, MulAssign, Neg, DivAssign, RemAssign, Div, Rem};
19use std::str::FromStr;
20use delegate::delegate;
21use num_traits::{Zero, One, Pow};
22use auto_impl_ops::auto_ops;
23
24use crate::abst::{MathType, AddMon, AddMonOps, AddGrp, AddGrpOps, Mon, MonOps, Ring, RingOps, EucRing, EucRingOps, Field, FieldOps};
25use crate::lc::Lc;
26use crate::util::parse_err::ParseErr;
27use super::{MultiDeg, Var, Var2, Var3,MultiVar, Mono, MonoOrd};
28
29pub type Poly <const X: char, R> = PolyBase<Var<X, usize>, R>;
31pub type LPoly <const X: char, R> = PolyBase<Var<X, isize>, R>;
33
34pub type Poly2 <const X: char, const Y: char, R> = PolyBase<Var2<X, Y, usize>, R>;
36pub type LPoly2<const X: char, const Y: char, R> = PolyBase<Var2<X, Y, isize>, R>;
38
39pub type Poly3 <const X: char, const Y: char, const Z: char, R> = PolyBase<Var3<X, Y, Z, usize>, R>;
41pub type LPoly3<const X: char, const Y: char, const Z: char, R> = PolyBase<Var3<X, Y, Z, isize>, R>;
43
44pub type PolyN <const X: char, R> = PolyBase<MultiVar<X, usize>, R>;
46pub type LPolyN<const X: char, R> = PolyBase<MultiVar<X, isize>, R>;
48
49#[derive(Clone, PartialEq, Eq, Default)]
53#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
54#[cfg_attr(feature = "serde", serde(transparent))]
55pub struct PolyBase<X, R>
56where
57 X: Mono,
58 R: Ring, for<'x> &'x R: RingOps<R>
59{
60 data: Lc<X, R>,
61 #[cfg_attr(feature = "serde", serde(skip))]
62 zero: (X, R)
63}
64
65impl<X, R> PolyBase<X, R>
66where X: Mono, R: Ring, for<'x> &'x R: RingOps<R> {
67 fn new(data: Lc<X, R>) -> Self {
68 Self { data, zero: (X::one(), R::zero()) }
69 }
70
71 pub fn from_const(r: R) -> Self {
72 Self::from((X::one(), r))
73 }
74
75 pub fn inner(&self) -> &Lc<X, R> {
76 &self.data
77 }
78
79 delegate! {
80 to self.data {
81 pub fn nterms(&self) -> usize;
82 pub fn any_term(&self) -> Option<(&X, &R)>;
83 #[call(is_singleton)] pub fn is_mono(&self) -> bool;
84 #[call(as_singleton)] pub fn as_mono(&self) -> Option<X>;
85 pub fn coeff(&self, x: &X) -> &R;
86 pub fn iter(&self) -> impl Iterator<Item = (&X, &R)>;
87 }
88 }
89
90 pub fn coeff_for(&self, i: X::Deg) -> &R {
91 self.data.coeff(&X::from(i))
92 }
93
94 pub fn is_const(&self) -> bool {
95 self.iter().all(|(x, _)| x.is_one())
96 }
97
98 pub fn const_term(&self) -> &R {
99 self.coeff(&X::one())
100 }
101
102 pub fn lead_term(&self) -> (&X, &R) {
103 self.iter().max_by(|t1, t2| MonoOrd::cmp_grlex(t1.0, t2.0))
104 .unwrap_or((&self.zero.0, &self.zero.1))
105 }
106
107 pub fn lead_coeff(&self) -> &R {
108 self.lead_term().1
109 }
110
111 pub fn lead_deg(&self) -> X::Deg {
112 self.lead_term().0.deg()
113 }
114
115 pub fn sort_terms_by<F>(&self, cmp: F) -> impl Iterator<Item = (&X, &R)>
116 where F: Fn(&X, &X) -> std::cmp::Ordering {
117 self.data.sort_terms_by(cmp)
118 }
119
120 pub fn to_string_by<F>(&self, cmp: F, descending: bool) -> String
121 where F: Fn(&X, &X) -> std::cmp::Ordering {
122 self.data.to_string_by(cmp, descending)
123 }
124}
125
126macro_rules! impl_var_specific {
127 ($I:ty) => {
128 impl<const X: char, R> PolyBase<Var<X, $I>, R>
130 where R: Ring, for<'x> &'x R: RingOps<R> {
131 pub fn variable() -> Self {
132 Self::from(Self::mono(1))
133 }
134
135 pub fn mono(i: $I) -> Var<X, $I> {
136 Var::from(i)
137 }
138
139 pub fn eval(&self, x: &R) -> R
140 where for<'x> &'x R: Pow<$I, Output = R> {
141 R::sum(self.iter().map(|(i, r)| {
142 r * i.eval(x)
143 }))
144 }
145 }
146
147 impl<const X: char, const Y: char, R> PolyBase<Var2<X, Y, $I>, R>
149 where R: Ring, for<'x> &'x R: RingOps<R> {
150 pub fn variable(i: usize) -> Self {
151 assert!(i < 2);
152 let d = if i == 0 { (1, 0) } else { (0, 1) };
153 Self::from(Var2::from(d))
154 }
155
156 pub fn mono(i: $I, j: $I) -> Var2<X, Y, $I> {
157 Var2::from((i, j))
158 }
159
160 pub fn eval(&self, x: &R, y: &R) -> R
161 where for<'x> &'x R: Pow<$I, Output = R> {
162 R::sum(self.iter().map(|(i, r)| {
163 r * i.eval(x, y)
164 }))
165 }
166 }
167
168 impl<const X: char, const Y: char, const Z: char, R> PolyBase<Var3<X, Y, Z, $I>, R>
170 where R: Ring, for<'x> &'x R: RingOps<R> {
171 pub fn variable(i: usize) -> Self {
172 assert!(i < 3);
173 let d = match i {
174 0 => (1, 0, 0),
175 1 => (0, 1, 0),
176 2 => (0, 0, 1),
177 _ => panic!()
178 };
179 Self::from(Var3::from(d))
180 }
181
182 pub fn mono(i: $I, j: $I, k: $I) -> Var3<X, Y, Z, $I> {
183 Var3::from((i, j, k))
184 }
185
186 pub fn eval(&self, x: &R, y: &R, z: &R) -> R
187 where for<'x> &'x R: Pow<$I, Output = R> {
188 R::sum(self.iter().map(|(i, r)| {
189 r * i.eval(x, y, z)
190 }))
191 }
192 }
193
194 impl<const X: char, R> PolyBase<MultiVar<X, $I>, R>
196 where R: Ring, for<'x> &'x R: RingOps<R> {
197 pub fn variable(i: usize) -> Self {
198 let d = MultiDeg::from((i, 1));
199 Self::from(MultiVar::from(d)) }
201
202 pub fn mono<const N: usize>(degs: [$I; N]) -> MultiVar<X, $I> {
203 MultiVar::from(degs)
204 }
205
206 pub fn lead_term_for(&self, k: usize) -> Option<(&MultiVar<X, $I>, &R)> {
207 self.iter()
208 .filter(|(x, _)| x.deg_for(k) > 0)
209 .max_by(|(x, _), (y, _)|
210 Ord::cmp( &x.deg_for(k), &y.deg_for(k))
211 .then_with(||
212 MultiVar::cmp_grlex(&x, &y)
213 )
214 )
215 }
216 }
217 };
218}
219
220impl_var_specific!(usize);
221impl_var_specific!(isize);
222
223impl<X, R> From<X> for PolyBase<X, R>
224where X: Mono, R: Ring, for<'x> &'x R: RingOps<R> {
225 fn from(x: X) -> Self {
226 Self::from((x, R::one()))
227 }
228}
229
230impl<X, R> From<(X, R)> for PolyBase<X, R>
231where X: Mono, R: Ring, for<'x> &'x R: RingOps<R> {
232 fn from(pair: (X, R)) -> Self {
233 let t = Lc::from(pair);
234 Self::from(t)
235 }
236}
237
238impl<X, R> FromIterator<(X, R)> for PolyBase<X, R>
239where X: Mono, R: Ring, for<'x> &'x R: RingOps<R> {
240 fn from_iter<T: IntoIterator<Item = (X, R)>>(iter: T) -> Self {
241 Self::from(Lc::from_iter(iter))
242 }
243}
244
245impl<X, R> From<Lc<X, R>> for PolyBase<X, R>
246where X: Mono, R: Ring, for<'x> &'x R: RingOps<R> {
247 fn from(data: Lc<X, R>) -> Self {
248 Self::new(data)
249 }
250}
251
252impl<X, R> From<PolyBase<X, R>> for Lc<X, R>
253where X: Mono, R: Ring, for<'x> &'x R: RingOps<R> {
254 fn from(poly: PolyBase<X, R>) -> Self {
255 poly.data
256 }
257}
258
259impl<X, R> FromStr for PolyBase<X, R>
260where X: Mono + FromStr, R: Ring + FromStr, for<'x> &'x R: RingOps<R> {
261 type Err = ParseErr;
262
263 fn from_str(s: &str) -> Result<Self, Self::Err> {
264 if let Ok(r) = R::from_str(s) {
265 Ok(Self::from_const(r))
266 } else if let Ok(x) = X::from_str(s) {
267 Ok(Self::from(x))
268 } else {
269 Err(ParseErr::invalid(s, &Self::math_symbol()))
271 }
272 }
273}
274
275impl<X, R> IntoIterator for PolyBase<X, R>
276where X: Mono, R: Ring, for<'x> &'x R: RingOps<R> {
277 type Item = (X, R);
278 type IntoIter = <Lc<X, R> as IntoIterator>::IntoIter;
279
280 fn into_iter(self) -> Self::IntoIter {
281 self.data.into_iter()
282 }
283}
284
285impl<X, R> Display for PolyBase<X, R>
286where X: Mono, R: Ring, for<'x> &'x R: RingOps<R> {
287 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
288 f.write_str(&self.to_string_by(X::cmp, true))
289 }
290}
291
292impl<X, R> Debug for PolyBase<X, R>
293where X: Mono, R: Ring, for<'x> &'x R: RingOps<R> {
294 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
295 Display::fmt(self, f)
296 }
297}
298
299impl<X, R> Zero for PolyBase<X, R>
300where X: Mono, R: Ring, for<'x> &'x R: RingOps<R> {
301 fn zero() -> Self {
302 Self::from(Lc::zero())
303 }
304
305 fn is_zero(&self) -> bool {
306 self.data.is_zero()
307 }
308}
309
310impl<X, R> One for PolyBase<X, R>
311where X: Mono, R: Ring, for<'x> &'x R: RingOps<R> {
312 fn one() -> Self {
313 Self::from((X::one(), R::one()))
314 }
315
316 fn is_one(&self) -> bool {
317 self.is_const() && self.const_term().is_one()
318 }
319}
320
321impl<X, R> Neg for PolyBase<X, R>
322where X: Mono, R: Ring, for<'x> &'x R: RingOps<R> {
323 type Output = Self;
324 fn neg(self) -> Self::Output {
325 Self::from(-self.data)
326 }
327}
328
329impl<X, R> Neg for &PolyBase<X, R>
330where X: Mono, R: Ring, for<'x> &'x R: RingOps<R> {
331 type Output = PolyBase<X, R>;
332 fn neg(self) -> Self::Output {
333 PolyBase::from(-&self.data)
334 }
335}
336
337macro_rules! impl_assop {
338 ($trait:ident, $method:ident) => {
339 #[auto_ops]
340 impl<X, R> $trait<&PolyBase<X, R>> for PolyBase<X, R>
341 where X: Mono, R: Ring, for<'x> &'x R: RingOps<R> {
342 fn $method(&mut self, rhs: &PolyBase<X, R>) {
343 self.data.$method(&rhs.data)
344 }
345 }
346 };
347}
348
349impl_assop!(AddAssign, add_assign);
350impl_assop!(SubAssign, sub_assign);
351
352#[auto_ops]
353impl<X, R> MulAssign<&R> for PolyBase<X, R>
354where X: Mono, R: Ring, for<'x> &'x R: RingOps<R> {
355 fn mul_assign(&mut self, rhs: &R) {
356 self.data *= rhs
357 }
358}
359
360#[auto_ops]
361impl<X, R> MulAssign<&PolyBase<X, R>> for PolyBase<X, R>
362where X: Mono, R: Ring, for<'x> &'x R: RingOps<R> {
363 fn mul_assign(&mut self, rhs: &PolyBase<X, R>) {
364 if rhs.is_one() {
365 } else if rhs.is_const() {
367 *self *= rhs.const_term()
368 } else if self.is_const() {
369 *self = rhs * self.const_term()
370 } else {
371 self.data *= &rhs.data
372 }
373 }
374}
375
376macro_rules! impl_pow_unsigned {
377 ($t:ty) => {
378 impl<X, R> Pow<$t> for &PolyBase<X, R>
379 where X: Mono, R: Ring, for<'x> &'x R: RingOps<R> {
380 type Output = PolyBase<X, R>;
381 fn pow(self, n: $t) -> Self::Output {
382 let mut res = PolyBase::one();
383 for _ in 0..n {
384 res *= self
385 }
386 res
387 }
388 }
389 };
390}
391
392impl_pow_unsigned!(u32);
393impl_pow_unsigned!(u64);
394impl_pow_unsigned!(usize);
395
396macro_rules! impl_pow_signed {
397 ($t:ty) => {
398 impl<X, R> Pow<$t> for &PolyBase<X, R>
399 where X: Mono, R: Ring, for<'x> &'x R: RingOps<R> {
400 type Output = PolyBase<X, R>;
401 fn pow(self, n: $t) -> Self::Output {
402 if n >= 0 {
403 self.pow(n as usize)
404 } else {
405 let inv = self.inv().unwrap();
406 (&inv).pow(-n as usize)
407 }
408 }
409 }
410 }
411}
412
413impl_pow_signed!(i32);
414impl_pow_signed!(i64);
415impl_pow_signed!(isize);
416
417macro_rules! impl_alg_op {
418 ($trait:ident) => {
419 impl<X, R> $trait<Self> for PolyBase<X, R>
420 where X: Mono, R: Ring, for<'x> &'x R: RingOps<R> {}
421
422 impl<X, R> $trait<PolyBase<X, R>> for &PolyBase<X, R>
423 where X: Mono, R: Ring, for<'x> &'x R: RingOps<R> {}
424 };
425}
426
427impl_alg_op!(AddMonOps);
428impl_alg_op!(AddGrpOps);
429impl_alg_op!(MonOps);
430impl_alg_op!(RingOps);
431
432impl<X, R> MathType for PolyBase<X, R>
433where X: Mono, R: Ring, for<'x> &'x R: RingOps<R> {
434 fn math_symbol() -> String {
435 format!("{}[{}]", R::math_symbol(), X::math_symbol())
436 }
437}
438
439impl<X, R> AddMon for PolyBase<X, R>
440where X: Mono, R: Ring, for<'x> &'x R: RingOps<R> {}
441
442impl<X, R> AddGrp for PolyBase<X, R>
443where X: Mono, R: Ring, for<'x> &'x R: RingOps<R> {}
444
445impl<X, R> Mon for PolyBase<X, R>
446where X: Mono, R: Ring, for<'x> &'x R: RingOps<R> {}
447
448impl<X, R> Ring for PolyBase<X, R>
449where X: Mono, R: Ring, for<'x> &'x R: RingOps<R> {
450 fn inv(&self) -> Option<Self> {
451 if self.nterms() != 1 {
452 return None
453 }
454
455 let (x, a) = self.any_term()?; let (xinv, ainv) = (x.inv()?, a.inv()?);
457 let inv = Self::from((xinv, ainv));
458 Some(inv)
459 }
460
461 fn is_unit(&self) -> bool {
462 if self.nterms() == 1 {
463 let (x, a) = self.any_term().unwrap();
464 x.is_unit() && a.is_unit()
465 } else {
466 false
467 }
468 }
469
470 fn normalizing_unit(&self) -> Self {
471 let u = self.lead_coeff().normalizing_unit();
472 Self::from_const(u)
473 }
474}
475
476impl<const X: char, R> Poly<X, R>
479where R: Field, for<'x> &'x R: FieldOps<R> {
480 pub fn div_rem(&self, rhs: &Self) -> (Self, Self) {
481 let iter = |f: Self, g: &Self| -> (Self, Self) {
482 if f.lead_deg() < g.lead_deg() {
483 return (Self::zero(), f)
484 }
485
486 let (i, a) = f.lead_term(); let (j, b) = g.lead_term(); let k = i.deg() - j.deg(); let c = a / b;
491 let x = Var::from(k);
492 let q = Poly::from((x, c)); let r = f - &q * g;
494
495 (q, r)
496 };
497
498 let mut q = Self::zero();
499 let mut r = self.clone();
500
501 let i = self.lead_deg();
502 let j = rhs.lead_deg();
503
504 for _ in j ..= i { let (q1, r1) = iter(r, rhs);
506 q += q1;
507 r = r1;
508 }
509
510 (q, r)
511 }
512}
513
514#[auto_ops]
515impl<const X: char, R> Div<&Poly<X, R>> for Poly<X, R>
516where R: Field, for<'x> &'x R: FieldOps<R> {
517 type Output = Self;
518
519 fn div(self, rhs: &Poly<X, R>) -> Self {
520 self.div_rem(rhs).0
521 }
522}
523
524#[auto_ops]
525impl<const X: char, R> Rem<&Poly<X, R>> for Poly<X, R>
526where R: Field, for<'x> &'x R: FieldOps<R> {
527 type Output = Self;
528
529 fn rem(self, rhs: &Poly<X, R>) -> Self::Output {
530 self.div_rem(rhs).1
531 }
532}
533
534impl<const X: char, R> EucRingOps<Poly<X, R>> for Poly<X, R>
535where R: Field, for<'x> &'x R: FieldOps<R> {}
536
537impl<const X: char, R> EucRingOps<Poly<X, R>> for &Poly<X, R>
538where R: Field, for<'x> &'x R: FieldOps<R> {}
539
540impl<const X: char, R> EucRing for Poly<X, R>
541where R: Field, for<'x> &'x R: FieldOps<R> {}
542
543mod tex {
544 use crate::util::tex::TeX;
545 use super::*;
546
547 impl<X, R> TeX for PolyBase<X, R>
548 where X: Mono + TeX, R: Ring + TeX, for<'x> &'x R: RingOps<R> {
549 fn tex_math_symbol() -> String {
550 format!("{}[{}]", R::tex_math_symbol(), X::tex_math_symbol())
551 }
552
553 fn tex_string(&self) -> String {
554 use crate::util::format::lc;
555 let terms = self.sort_terms_by(|x, y| X::cmp_lex(x, y).reverse()).map(|(x, r)|
556 (x.tex_string(), r.tex_string())
557 );
558 lc(terms)
559 }
560 }
561}
562
563#[cfg(test)]
564mod tests {
565 use crate::num::Ratio;
566 use super::*;
567
568 #[test]
569 fn init() {
570 type P = Poly::<'x', i32>;
571
572 let x = P::mono;
573 let f = P::from_iter([(x(0), 1), (x(1), 2), (x(2), -3)]);
574 assert_eq!(f.data.coeff(&x(0)), &1);
575 assert_eq!(f.data.coeff(&x(1)), &2);
576 assert_eq!(f.data.coeff(&x(2)), &-3);
577 assert_eq!(f.data.coeff(&x(3)), &0);
578 }
579
580 #[test]
581 fn display_poly() {
582 type P = Poly::<'x', i32>;
583
584 let x = P::mono;
585 let f = P::from_iter([(x(0), 1), (x(1), 2), (x(2), -3)]);
586 assert_eq!(&f.to_string(), "-3x² + 2x + 1");
587 }
588
589 #[test]
590 fn display_lpoly() {
591 type P = LPoly::<'x', i32>;
592
593 let x = P::mono;
594 let f = P::from_iter([(x(-1), 4), (x(0), 2), (x(2), 3)]);
595 assert_eq!(&f.to_string(), "3x² + 2 + 4x⁻¹");
596 }
597
598 #[test]
599 fn display_poly2() {
600 type P = Poly2::<'x', 'y', i32>;
601
602 let xy = P::mono;
603 let f = P::from_iter([(xy(0, 0), 3), (xy(1, 0), 2), (xy(2, 3), 3)]);
604 assert_eq!(&f.to_string(), "3x²y³ + 2x + 3");
605 }
606
607 #[test]
608 fn display_mpoly() {
609 type P = PolyN::<'x', i32>;
610
611 let xn = P::mono;
612 let f = P::from_iter([
613 (xn([0,0,0]), 3),
614 (xn([1,0,0]), -1),
615 (xn([3,0,2]), 2),
616 ]);
617 assert_eq!(&f.to_string(), "2x₀³x₂² - x₀ + 3");
618 }
619
620 #[test]
621 fn display_mlpoly() {
622 type P = LPolyN::<'x', i32>;
623
624 let xn = P::mono;
625 let f = P::from_iter([
626 (xn([ 0,0,0]), 3),
627 (xn([ 1,0,0]), 1),
628 (xn([-3,1,3]), 2),
629 ]);
630 assert_eq!(&f.to_string(), "x₀ + 3 + 2x₀⁻³x₁x₂³");
631 }
632
633 #[test]
634 fn zero() {
635 type P = Poly::<'x', i32>;
636
637 let z = P::zero();
638 assert_eq!(z, P::from_iter([]));
639 assert!(z.is_zero());
640 }
641
642 #[test]
643 fn one() {
644 type P = Poly::<'x', i32>;
645
646 let x = P::mono;
647 let p = P::one();
648 assert_eq!(p, P::from_iter([(x(0), 1)]));
649 }
650
651 #[test]
652 fn variable() {
653 type P = Poly::<'x', i32>;
654
655 let x = P::mono;
656 let p = P::variable();
657 assert_eq!(p, P::from_iter([(x(1), 1)]));
658 }
659
660 #[test]
661 fn variable_bivar() {
662 type P = Poly2::<'x', 'y', i32>;
663
664 let xy = P::mono;
665 let p = P::variable(0);
666 let q = P::variable(1);
667 assert_eq!(p, P::from_iter([(xy(1, 0), 1)]));
668 assert_eq!(q, P::from_iter([(xy(0, 1), 1)]));
669 }
670
671 #[test]
672 fn variable_mvar() {
673 type P = PolyN::<'x', i32>;
674
675 let xn = P::mono;
676 let p = P::variable(0);
677 let q = P::variable(1);
678 assert_eq!(p, P::from_iter([(xn([1, 0]), 1)]));
679 assert_eq!(q, P::from_iter([(xn([0, 1]), 1)]));
680 }
681
682 #[test]
683 fn coeff() {
684 type P = Poly::<'x', i32>;
685
686 let x = P::mono;
687 let f = P::from_iter([(x(0), 2), (x(1), 3), (x(2), -4)]);
688
689 assert_eq!(f.coeff_for(0), &2);
690 assert_eq!(f.coeff_for(1), &3);
691 assert_eq!(f.coeff_for(2), &-4);
692 assert_eq!(f.coeff_for(3), &0);
693 }
694
695 #[test]
696 fn const_term() {
697 type P = Poly::<'x', i32>;
698 let x = P::mono;
699 let f = P::from_iter([(x(0), 2), (x(1), 3), (x(2), -4)]);
700 assert_eq!(f.const_term(), &2);
701
702 let f = P::from_iter([(x(1), 3), (x(2), -4)]);
703 assert_eq!(f.const_term(), &0);
704 }
705
706 #[test]
707 fn lead_term() {
708 type P = Poly::<'x', i32>;
709
710 let x = P::mono;
711 let f = P::from_iter([(x(0), 2), (x(1), 3), (x(2), -4)]);
712 let (m, a) = f.lead_term();
713
714 assert_eq!(m.deg(), 2);
715 assert_eq!(a, &-4);
716
717 let f = P::zero();
718 let (m, a) = f.lead_term();
719 assert_eq!(m.deg(), 0);
720 assert_eq!(a, &0);
721 }
722
723 #[test]
724 fn add() {
725 type P = Poly::<'x', i32>;
726
727 let x = P::mono;
728 let f = P::from_iter([(x(0), 2), (x(1), 3), (x(2), -4)]);
729 let g = P::from_iter([(x(0), -3), (x(1), -3), (x(3), 5)]);
730
731 assert_eq!(f + g, P::from_iter([(x(0), -1), (x(1), 0), (x(2), -4), (x(3), 5)]));
732 }
733
734 #[test]
735 fn neg() {
736 type P = Poly::<'x', i32>;
737
738 let x = P::mono;
739 let f = P::from_iter([(x(0), 2), (x(1), 3), (x(2), -4)]);
740
741 assert_eq!(-f, P::from_iter([(x(0), -2), (x(1), -3), (x(2), 4)]));
742 }
743
744 #[test]
745 fn sub() {
746 type P = Poly::<'x', i32>;
747 let x = P::mono;
748 let f = P::from_iter([(x(0), 2), (x(1), 3), (x(2), -4)]);
749 let g = P::from_iter([(x(0), -3), (x(1), -3), (x(3), 5)]);
750 assert_eq!(f - g, P::from_iter([(x(0), 5), (x(1), 6), (x(2), -4), (x(3), -5)]));
751 }
752
753 #[test]
754 fn mul() {
755 type P = Poly::<'x', i32>;
756
757 let x = P::mono;
758 let f = P::from_iter([(x(0), 2), (x(1), 3), (x(2), -4)]);
759 let g = P::from_iter([(x(0), -3), (x(1), -3), (x(3), 5)]);
760
761 assert_eq!(f * g, P::from_iter([(x(0), -6), (x(1), -15), (x(2), 3), (x(3), 22), (x(4), 15), (x(5), -20)]));
762 }
763
764 #[test]
765 fn mul_const() {
766 type P = Poly::<'x', i32>;
767
768 let x = P::mono;
769 let f = P::from_iter([(x(0), 2), (x(1), 3), (x(2), -4)]);
770 let g = P::from_const(3);
771
772 assert_eq!(&f * &g, P::from_iter([(x(0), 6), (x(1), 9), (x(2), -12)]));
773 assert_eq!(&g * &f, P::from_iter([(x(0), 6), (x(1), 9), (x(2), -12)]));
774 }
775
776 #[test]
777 fn pow() {
778 type P = Poly::<'x', i32>;
779
780 let x = P::mono;
781 let f = P::from_iter([(x(0), 3), (x(1), 2)]);
782
783 assert_eq!(f.pow(0), P::one());
784 assert_eq!(f.pow(1), f);
785 assert_eq!(f.pow(0), P::one());
786 assert_eq!(f.pow(2), P::from_iter([(x(0), 9), (x(1), 12), (x(2), 4)]));
787 }
788
789 #[test]
790 fn pow_laurent() {
791 type P = LPoly::<'x', i32>;
792
793 let x = P::mono;
794 let f = P::variable();
795
796 assert_eq!(f.pow(0), P::one());
797 assert_eq!(f.pow(-1), P::from((x(-1), 1)));
798 assert_eq!(f.pow(0), P::one());
799 assert_eq!(f.pow(-2), P::from((x(-2), 1)));
800 }
801
802 #[test]
803 fn inv() {
804 type P = Poly::<'x', i32>;
805
806 let x = P::mono;
807 let f = P::from_const(1);
808 assert!(f.is_unit());
809 assert_eq!(f.inv(), Some(P::from_const(1)));
810
811 let f = P::from_const(0);
812 assert!(!f.is_unit());
813 assert_eq!(f.inv(), None);
814
815 let f = P::from_const(2);
816 assert!(!f.is_unit());
817 assert_eq!(f.inv(), None);
818
819 let f = P::variable();
820 assert!(!f.is_unit());
821 assert_eq!(f.inv(), None);
822
823 let f = P::from_iter([(x(0), 1), (x(1), 1)]);
824 assert!(!f.is_unit());
825 assert_eq!(f.inv(), None);
826 }
827
828 #[test]
829 fn inv_rat() {
830 type R = Ratio<i32>;
831 type P = Poly::<'x', R>;
832
833 let x = P::mono;
834 let f = P::from_const(R::from(1));
835
836 assert!(f.is_unit());
837 assert_eq!(f.inv(), Some(P::from_const(R::from(1))));
838
839 let f = P::from_const(R::zero());
840 assert!(!f.is_unit());
841 assert_eq!(f.inv(), None);
842
843 let f = P::from_const(R::from(2));
844 assert!(f.is_unit());
845 assert_eq!(f.inv(), Some(P::from_const(R::new(1, 2))));
846
847 let f = P::variable();
848 assert!(!f.is_unit());
849 assert_eq!(f.inv(), None);
850
851 let f = P::from_iter([(x(0), R::one()), (x(1), R::one())]);
852 assert!(!f.is_unit());
853 assert_eq!(f.inv(), None);
854 }
855
856 #[test]
857 fn inv_laurent() {
858 type P = LPoly::<'x', i32>;
859
860 let x = P::mono;
861 let f = P::from_const(1);
862 assert!(f.is_unit());
863 assert_eq!(f.inv(), Some(P::from_const(1)));
864
865 let f = P::from_const(0);
866 assert!(!f.is_unit());
867 assert_eq!(f.inv(), None);
868
869 let f = P::from_const(2);
870 assert!(!f.is_unit());
871 assert_eq!(f.inv(), None);
872
873 let f = P::variable();
874 assert!(f.is_unit());
875 assert_eq!(f.inv(), Some(P::from((x(-1), 1))));
876
877 let f = P::from((x(1), 2));
878 assert!(!f.is_unit());
879 assert_eq!(f.inv(), None);
880
881 let f = P::from_iter([(x(0), 1), (x(1), 1)]);
882 assert!(!f.is_unit());
883 assert_eq!(f.inv(), None);
884 }
885
886 #[test]
887 fn inv_laurent_rat() {
888 type R = Ratio<i32>;
889 type P = LPoly::<'x', R>;
890
891 let x = P::mono;
892 let f = P::from_const(R::from(1));
893 assert!(f.is_unit());
894 assert_eq!(f.inv(), Some(P::from_const(R::from(1))));
895
896 let f = P::from_const(R::zero());
897 assert!(!f.is_unit());
898 assert_eq!(f.inv(), None);
899
900 let f = P::from_const(R::from(2));
901 assert!(f.is_unit());
902 assert_eq!(f.inv(), Some(P::from_const(R::new(1, 2))));
903
904 let f = P::variable();
905 assert!(f.is_unit());
906 assert_eq!(f.inv(), Some(P::from((x(-1), R::one()))));
907
908 let f = P::from((x(1), R::from(2)));
909 assert!(f.is_unit());
910 assert_eq!(f.inv(), Some(P::from((x(-1), R::new(1, 2)))));
911
912 let f = P::from_iter([(x(0), R::one()), (x(1), R::one())]);
913 assert!(!f.is_unit());
914 assert_eq!(f.inv(), None);
915 }
916
917 #[test]
918 fn div_rem() {
919 type R = Ratio<i32>;
920 type P = Poly::<'x', R>;
921
922 let x = P::mono;
923 let f = P::from_iter([(x(0), R::from(1)), (x(1), R::from(2)), (x(2), R::from(1))]);
924 let g = P::from_iter([(x(0), R::from(3)), (x(1), R::from(2))]);
925 let (q, r) = f.div_rem(&g);
926
927 assert_eq!(q, P::from_iter([(x(0), R::new(1, 4)), (x(1), R::new(1, 2))]));
928 assert_eq!(r, P::from_const( R::new(1, 4)) );
929 assert_eq!(f, q * &g + r);
930
931 let (q, r) = g.div_rem(&f);
932 assert_eq!(q, P::zero());
933 assert_eq!(r, g);
934 }
935
936 #[test]
937 fn from_str() {
938 type P = Poly::<'x', i32>;
939
940 assert_eq!(P::from_str("-3"), Ok(P::from_const(-3)));
941 assert_eq!(P::from_str("x"), Ok(P::variable()));
942
943 let e = P::from_str("y").unwrap_err();
945 assert_eq!(e.to_string(), "cannot parse \"y\" as Z[x]");
946
947 }
949
950 #[test]
951 fn eval_bivar() {
952 type P = Poly2::<'x', 'y', i32>;
953
954 let xy = P::mono;
955 let p = P::from_iter([(xy(0,0),3), (xy(1,0),2), (xy(0,1),-1), (xy(1,1),4)]);
956 let v = p.eval(&2, &3); assert_eq!(v, 28);
958 }
959
960 #[test]
961 fn lead_term_for() {
962 type P = PolyN::<'x', i32>;
963
964 let xn = P::mono;
965 let f = P::from_iter([
966 (xn([1,2,3]), 1),
967 (xn([2,1,3]), 2),
968 (xn([0,2,4]), 3),
969 (xn([5,5,5]), 0), ]);
971 assert_eq!(f.lead_term_for(0), Some((&xn([2,1,3]), &2)));
972 assert_eq!(f.lead_term_for(1), Some((&xn([1,2,3]), &1)));
973 assert_eq!(f.lead_term_for(2), Some((&xn([0,2,4]), &3)));
974 assert_eq!(f.lead_term_for(3), None);
975 }
976
977 #[test]
978 #[cfg(feature = "serde")]
979 fn serialize_univar() {
980 type P = Poly::<'x', i32>;
981
982 let x = P::mono;
983 let f = P::from_iter([(x(0), 1), (x(1), 2), (x(2), -3)]);
984
985 let ser = serde_json::to_string(&f).unwrap();
986 let des = serde_json::from_str(&ser).unwrap();
987 assert_eq!(f, des);
988 }
989
990 #[test]
991 #[cfg(feature = "serde")]
992 fn serialize_bivar() {
993 type P = LPoly2::<'x', 'y', i32>;
994
995 let xy = P::mono;
996 let f = P::from_iter([
997 (xy(0, 0), 3),
998 (xy(1, 0), 1),
999 (xy(-2, 13), -3)
1000 ]);
1001
1002 let ser = serde_json::to_string(&f).unwrap();
1003 dbg!(&ser);
1004 let des = serde_json::from_str(&ser).unwrap();
1005 assert_eq!(f, des);
1006 }
1007
1008 #[test]
1009 #[cfg(feature = "serde")]
1010 fn serialize_mvar() {
1011 type P = LPolyN::<'x', i32>;
1012
1013 let xn = P::mono;
1014 let f = P::from_iter([
1015 (xn([0,0,0]), 3),
1016 (xn([1,0,0]), -1),
1017 (xn([12,0,-2]), 12),
1018 ]);
1019
1020 let ser = serde_json::to_string(&f).unwrap();
1021 let des = serde_json::from_str(&ser).unwrap();
1022 assert_eq!(f, des);
1023 }
1024
1025 #[test]
1026 fn tex() {
1027 use crate::util::tex::TeX;
1028 type P = LPolyN::<'x', i32>;
1029
1030 assert_eq!(P::tex_math_symbol(), "\\mathbb{Z}[x_1,\\ldots]");
1031
1032 let xn = P::mono;
1033 let f = P::from_iter([
1034 (xn([ 0,0,0]), 3),
1035 (xn([ 3,0,1]), -1),
1036 (xn([-2,1,3]), -2),
1037 ]);
1038
1039 assert_eq!(f.tex_string(), "-x_0^3x_2 + 3 - 2x_0^{-2}x_1x_2^3");
1040 }
1041}