algebraeon_rings/polynomial/
polynomial_structure.rs

1use super::super::structure::*;
2use crate::{
3    matrix::*,
4    parsing::{parse_integer_polynomial, parse_rational_polynomial},
5};
6use algebraeon_nzq::*;
7use algebraeon_sets::structure::*;
8use itertools::Itertools;
9use std::hash::Hash;
10use std::{
11    borrow::{Borrow, Cow},
12    fmt::Display,
13    marker::PhantomData,
14};
15
16#[derive(Debug, Clone)]
17pub struct Polynomial<Set> {
18    //vec![c0, c1, c2, c3, ..., cn] represents the polynomial c0 + c1*x + c2*x^2 + c3*x^3 + ... + cn * x^n
19    //if non-empty, the last item must not be zero
20    coeffs: Vec<Set>,
21}
22
23impl<Set> Polynomial<Set> {
24    pub fn from_coeffs(coeffs: Vec<impl Into<Set>>) -> Self {
25        #[allow(clippy::redundant_closure_for_method_calls)]
26        Self {
27            coeffs: coeffs.into_iter().map(|x| x.into()).collect(),
28        }
29    }
30
31    pub fn constant(x: Set) -> Self {
32        Self::from_coeffs(vec![x])
33    }
34
35    pub fn apply_map<ImgSet>(&self, f: impl Fn(&Set) -> ImgSet) -> Polynomial<ImgSet> {
36        Polynomial::from_coeffs(self.coeffs.iter().map(f).collect())
37    }
38
39    pub fn apply_map_into<ImgSet>(self, f: impl Fn(Set) -> ImgSet) -> Polynomial<ImgSet> {
40        Polynomial::from_coeffs(self.coeffs.into_iter().map(f).collect())
41    }
42
43    pub fn apply_map_with_powers<ImgSet>(
44        &self,
45        f: impl Fn((usize, &Set)) -> ImgSet,
46    ) -> Polynomial<ImgSet> {
47        Polynomial::from_coeffs(self.coeffs.iter().enumerate().map(f).collect())
48    }
49
50    pub fn apply_map_into_with_powers<ImgSet>(
51        self,
52        f: impl Fn((usize, Set)) -> ImgSet,
53    ) -> Polynomial<ImgSet> {
54        Polynomial::from_coeffs(self.coeffs.into_iter().enumerate().map(f).collect())
55    }
56}
57
58pub trait PolynomialFromStr: Sized {
59    type Err;
60
61    fn from_str(polynomial_str: &str, var: &str) -> Result<Self, Self::Err>;
62}
63
64impl PolynomialFromStr for Polynomial<Natural> {
65    type Err = ();
66
67    fn from_str(polynomial_str: &str, var: &str) -> Result<Self, ()> {
68        Ok(Self::from_coeffs(
69            Polynomial::<Integer>::from_str(polynomial_str, var)?
70                .into_coeffs()
71                .into_iter()
72                .map(Natural::try_from)
73                .collect::<Result<Vec<_>, _>>()?,
74        ))
75    }
76}
77
78impl PolynomialFromStr for Polynomial<Integer> {
79    type Err = ();
80
81    fn from_str(polynomial_str: &str, var: &str) -> Result<Self, ()> {
82        parse_integer_polynomial(polynomial_str, var).map_err(|_| ())
83    }
84}
85
86impl PolynomialFromStr for Polynomial<Rational> {
87    type Err = ();
88
89    fn from_str(polynomial_str: &str, var: &str) -> Result<Self, ()> {
90        parse_rational_polynomial(polynomial_str, var).map_err(|_| ())
91    }
92}
93
94#[derive(Debug, Clone)]
95pub struct PolynomialStructure<RS: Signature, RSB: BorrowedStructure<RS>> {
96    _coeff_ring: PhantomData<RS>,
97    coeff_ring: RSB,
98}
99
100impl<RS: Signature, RSB: BorrowedStructure<RS>> PolynomialStructure<RS, RSB> {
101    pub fn new(coeff_ring: RSB) -> Self {
102        Self {
103            _coeff_ring: PhantomData,
104            coeff_ring,
105        }
106    }
107
108    pub fn coeff_ring(&self) -> &RS {
109        self.coeff_ring.borrow()
110    }
111
112    pub fn into_coeff_ring(self) -> RSB {
113        self.coeff_ring
114    }
115}
116
117pub trait ToPolynomialSignature: Signature {
118    fn polynomials(&self) -> PolynomialStructure<Self, &Self> {
119        PolynomialStructure::new(self)
120    }
121
122    fn into_polynomials(self) -> PolynomialStructure<Self, Self> {
123        PolynomialStructure::new(self)
124    }
125}
126
127impl<RS: Signature> ToPolynomialSignature for RS {}
128
129impl<RS: Signature, RSB: BorrowedStructure<RS>> Signature for PolynomialStructure<RS, RSB> {}
130
131impl<RS: SetSignature, RSB: BorrowedStructure<RS>> SetSignature for PolynomialStructure<RS, RSB> {
132    type Set = Polynomial<RS::Set>;
133
134    fn is_element(&self, _x: &Self::Set) -> Result<(), String> {
135        Ok(())
136    }
137}
138
139impl<RS: Signature, RSB: BorrowedStructure<RS>> PartialEq for PolynomialStructure<RS, RSB> {
140    fn eq(&self, other: &Self) -> bool {
141        self.coeff_ring == other.coeff_ring
142    }
143}
144
145impl<RS: Signature, RSB: BorrowedStructure<RS>> Eq for PolynomialStructure<RS, RSB> {}
146
147impl<RS: SemiRingSignature + EqSignature + ToStringSignature, RSB: BorrowedStructure<RS>>
148    ToStringSignature for PolynomialStructure<RS, RSB>
149{
150    fn to_string(&self, elem: &Self::Set) -> String {
151        if self.num_coeffs(elem) == 0 {
152            "0".into()
153        } else {
154            let try_to_int = |c: &RS::Set| -> Option<Integer> {
155                if let Some(coeff_ring) = self.coeff_ring().try_char_zero_ring_restructure() {
156                    coeff_ring.try_to_int(c)
157                } else {
158                    None
159                }
160            };
161
162            let mut s = String::new();
163            for (idx, (power, coeff)) in elem.coeffs.iter().enumerate().rev().enumerate() {
164                let first = idx == 0;
165                let constant = power == 0;
166
167                if !self.coeff_ring().is_zero(coeff) {
168                    if let Some(c) = try_to_int(coeff) {
169                        if c > Integer::ZERO && !first {
170                            s += "+";
171                        }
172                        if c == Integer::ONE && !constant {
173                        } else if c == -Integer::ONE && !constant {
174                            s += "-";
175                        } else {
176                            s += &c.to_string();
177                        }
178                    } else {
179                        if !first {
180                            s += "+";
181                        }
182                        s += "(";
183                        s += &self.coeff_ring().to_string(coeff);
184                        s += ")";
185                    }
186                    if power == 0 {
187                    } else if power == 1 {
188                        s += "λ";
189                    } else {
190                        s += "λ";
191                        s += "^";
192                        s += &power.to_string();
193                    }
194                }
195            }
196            s
197        }
198    }
199}
200
201impl<RS: SemiRingEqSignature, RSB: BorrowedStructure<RS>> EqSignature
202    for PolynomialStructure<RS, RSB>
203{
204    fn equal(&self, a: &Self::Set, b: &Self::Set) -> bool {
205        for i in 0..std::cmp::max(a.coeffs.len(), b.coeffs.len()) {
206            if !self
207                .coeff_ring()
208                .equal(self.coeff(a, i).as_ref(), self.coeff(b, i).as_ref())
209            {
210                return false;
211            }
212        }
213        true
214    }
215}
216
217impl<RS: SemiRingEqSignature, RSB: BorrowedStructure<RS>> PolynomialStructure<RS, RSB> {
218    pub fn add_impl<'a, C: Borrow<RS::Set>>(
219        &self,
220        mut a: &'a Polynomial<C>,
221        mut b: &'a Polynomial<C>,
222    ) -> Polynomial<RS::Set> {
223        if a.coeffs.len() > b.coeffs.len() {
224            (a, b) = (b, a);
225        }
226        let x = a.coeffs.len();
227        let y = b.coeffs.len();
228
229        let mut coeffs = vec![];
230        let mut i = 0;
231        while i < x {
232            coeffs.push(
233                self.coeff_ring()
234                    .add(a.coeffs[i].borrow(), b.coeffs[i].borrow()),
235            );
236            i += 1;
237        }
238        while i < y {
239            coeffs.push(b.coeffs[i].borrow().to_owned());
240            i += 1;
241        }
242        Polynomial::from_coeffs(coeffs)
243    }
244
245    pub fn mul_naive(
246        &self,
247        a: &Polynomial<impl Borrow<RS::Set>>,
248        b: &Polynomial<impl Borrow<RS::Set>>,
249    ) -> Polynomial<RS::Set> {
250        let mut coeffs = Vec::with_capacity(a.coeffs.len() + b.coeffs.len());
251        for _k in 0..a.coeffs.len() + b.coeffs.len() {
252            coeffs.push(self.coeff_ring().zero());
253        }
254        for i in 0..a.coeffs.len() {
255            for j in 0..b.coeffs.len() {
256                self.coeff_ring().add_mut(
257                    &mut coeffs[i + j],
258                    &self
259                        .coeff_ring()
260                        .mul(a.coeffs[i].borrow(), b.coeffs[j].borrow()),
261                );
262            }
263        }
264        self.reduce_poly(Polynomial::from_coeffs(coeffs))
265    }
266}
267
268impl<RS: RingEqSignature, RSB: BorrowedStructure<RS>> PolynomialStructure<RS, RSB> {
269    /*
270    The idea behind Karatsuba is to reduce the number of multiplications needed
271
272    To do this, express a and b in the form
273
274    a(x) = a0(x) + a1(x) x^k
275    b(x) = b0(x) + b1(x) x^k
276
277    Then
278
279    a(x) * b(x) = (a0(x) + a1(x) x^k) * (b0(x) + b1(x) x^k)
280                = a0(x)b0(x) + (a0(x)b1(x) + a1(x)b0(x)) x^k + a1(x)b1(x) x^{2k}
281                = f0(x) + f1(x) x^k + f2(x) x^{2k}
282
283    where
284
285    f0(x)  = a0(x)b0(x)                         1 multiplication
286    f1(x)  = a0(x)b1(x) + a1(x)b0(x)            2 multiplications
287    f2(x)  = a1(x)b1(x)                         1 multiplication
288
289    To reduce the number of multiplications required to obtain f1(x), let
290
291    f3(x) := (a0(x) + a1(x))(b0(x) + b1(x))     1 multiplication
292
293    Then
294
295    f1(x) = a0(x)b1(x) + a1(x)b0(x)
296          = (a0(x) + a1(x))(b0(x) + b1(x)) - a0(x)b0(x) - a1(x)b1(x)
297          = f3(x) - f2(x) - f0(x)               0 multiplications
298
299    So a(x) * b(x) can be found with 3 multiplications
300    */
301    fn mul_karatsuba<'a, C: Borrow<RS::Set>>(
302        &self,
303        a: &'a Polynomial<C>,
304        b: &'a Polynomial<C>,
305    ) -> Polynomial<RS::Set> {
306        let n = std::cmp::max(a.coeffs.len(), b.coeffs.len());
307        if n <= 10 {
308            return self.mul_naive(a, b);
309        }
310
311        let k = n / 2;
312
313        let empty_slice: &[C] = &[];
314        let (a0, a1) = if k <= a.coeffs.len() {
315            a.coeffs.split_at(k)
316        } else {
317            (a.coeffs.as_slice(), empty_slice)
318        };
319        let (b0, b1) = if k <= b.coeffs.len() {
320            b.coeffs.split_at(k)
321        } else {
322            (b.coeffs.as_slice(), empty_slice)
323        };
324        let a0 = Polynomial::<&RS::Set> {
325            coeffs: a0.iter().map(|c| c.borrow()).collect(),
326        };
327        let a1 = Polynomial::<&RS::Set> {
328            coeffs: a1.iter().map(|c| c.borrow()).collect(),
329        };
330        let b0 = Polynomial::<&RS::Set> {
331            coeffs: b0.iter().map(|c| c.borrow()).collect(),
332        };
333        let b1 = Polynomial::<&RS::Set> {
334            coeffs: b1.iter().map(|c| c.borrow()).collect(),
335        };
336
337        debug_assert!(self.equal(
338            &a.apply_map(|c| c.borrow().clone()),
339            &self.add_impl(
340                &a0.clone().apply_map_into(|c| c.clone()),
341                &self.mul_var_pow(&a1.clone().apply_map_into(|c| c.clone()), k)
342            )
343        ));
344        debug_assert!(self.equal(
345            &b.apply_map(|c| c.borrow().clone()),
346            &self.add_impl(
347                &b0.clone().apply_map_into(|c| c.clone()),
348                &self.mul_var_pow(&b1.clone().apply_map_into(|c| c.clone()), k)
349            )
350        ));
351
352        let f0 = self.mul_karatsuba(&a0, &b0);
353        let f2 = self.mul_karatsuba(&a1, &b1);
354        let f3 = self.mul_karatsuba(&self.add_impl(&a0, &a1), &self.add_impl(&b0, &b1));
355        let f1 = self.sub(&f3, &self.add(&f2, &f0));
356
357        self.reduce_poly(self.add(
358            &self.add(&f0, &self.mul_var_pow(&f1, k)),
359            &self.mul_var_pow(&f2, 2 * k),
360        ))
361    }
362}
363
364impl<RS: SemiRingEqSignature, RSB: BorrowedStructure<RS>> RinglikeSpecializationSignature
365    for PolynomialStructure<RS, RSB>
366{
367    fn try_ring_restructure(&self) -> Option<impl EqSignature<Set = Self::Set> + RingSignature> {
368        self.coeff_ring()
369            .try_ring_restructure()
370            .map(|coeff_ring| coeff_ring.into_polynomials())
371    }
372}
373
374impl<RS: SemiRingEqSignature, RSB: BorrowedStructure<RS>> ZeroSignature
375    for PolynomialStructure<RS, RSB>
376{
377    fn zero(&self) -> Self::Set {
378        Polynomial { coeffs: vec![] }
379    }
380}
381
382impl<RS: SemiRingEqSignature, RSB: BorrowedStructure<RS>> AdditionSignature
383    for PolynomialStructure<RS, RSB>
384{
385    fn add(&self, a: &Self::Set, b: &Self::Set) -> Self::Set {
386        self.add_impl(a, b)
387    }
388}
389
390impl<RS: SemiRingEqSignature + CancellativeAdditionSignature, RSB: BorrowedStructure<RS>>
391    CancellativeAdditionSignature for PolynomialStructure<RS, RSB>
392{
393    fn try_sub(&self, a: &Self::Set, b: &Self::Set) -> Option<Self::Set> {
394        Some(Polynomial::from_coeffs(
395            (0..std::cmp::max(a.coeffs.len(), b.coeffs.len()))
396                .map(|i| {
397                    self.coeff_ring()
398                        .try_sub(self.coeff(a, i).as_ref(), self.coeff(b, i).as_ref())
399                })
400                .collect::<Option<_>>()?,
401        ))
402    }
403}
404
405impl<RS: SemiRingEqSignature, RSB: BorrowedStructure<RS>> TryNegateSignature
406    for PolynomialStructure<RS, RSB>
407{
408    fn try_neg(&self, a: &Self::Set) -> Option<Self::Set> {
409        Some(Polynomial::from_coeffs(
410            a.coeffs
411                .iter()
412                .map(|c| self.coeff_ring().try_neg(c))
413                .collect::<Option<_>>()?,
414        ))
415    }
416}
417
418impl<RS: SemiRingEqSignature, RSB: BorrowedStructure<RS>> AdditiveMonoidSignature
419    for PolynomialStructure<RS, RSB>
420{
421}
422
423impl<RS: RingEqSignature, RSB: BorrowedStructure<RS>> AdditiveGroupSignature
424    for PolynomialStructure<RS, RSB>
425{
426    fn neg(&self, a: &Self::Set) -> Self::Set {
427        Polynomial::from_coeffs(a.coeffs.iter().map(|c| self.coeff_ring().neg(c)).collect())
428    }
429
430    fn sub(&self, a: &Self::Set, b: &Self::Set) -> Self::Set {
431        self.reduce_poly(Polynomial::from_coeffs(
432            (0..std::cmp::max(a.coeffs.len(), b.coeffs.len()))
433                .map(|i| {
434                    self.coeff_ring()
435                        .sub(self.coeff(a, i).as_ref(), self.coeff(b, i).as_ref())
436                })
437                .collect(),
438        ))
439    }
440}
441
442impl<RS: SemiRingEqSignature, RSB: BorrowedStructure<RS>> OneSignature
443    for PolynomialStructure<RS, RSB>
444{
445    fn one(&self) -> Self::Set {
446        Polynomial::from_coeffs(vec![self.coeff_ring().one()])
447    }
448}
449
450impl<RS: SemiRingEqSignature, RSB: BorrowedStructure<RS>> MultiplicationSignature
451    for PolynomialStructure<RS, RSB>
452{
453    fn mul(&self, a: &Self::Set, b: &Self::Set) -> Self::Set {
454        if let Some(coeff_ring) = self.coeff_ring().try_ring_restructure() {
455            coeff_ring.polynomials().mul_karatsuba(a, b)
456        } else {
457            self.mul_naive(a, b)
458        }
459    }
460}
461
462impl<RS: SemiRingEqSignature, RSB: BorrowedStructure<RS>> CommutativeMultiplicationSignature
463    for PolynomialStructure<RS, RSB>
464{
465}
466
467impl<RS: SemiRingEqSignature, RSB: BorrowedStructure<RS>> MultiplicativeMonoidSignature
468    for PolynomialStructure<RS, RSB>
469{
470}
471
472impl<RS: SemiRingEqSignature, RSB: BorrowedStructure<RS>> MultiplicativeAbsorptionMonoidSignature
473    for PolynomialStructure<RS, RSB>
474{
475}
476
477impl<RS: SemiRingEqSignature, RSB: BorrowedStructure<RS>> LeftDistributiveMultiplicationOverAddition
478    for PolynomialStructure<RS, RSB>
479{
480}
481
482impl<RS: SemiRingEqSignature, RSB: BorrowedStructure<RS>>
483    RightDistributiveMultiplicationOverAddition for PolynomialStructure<RS, RSB>
484{
485}
486
487impl<RS: SemiRingEqSignature, RSB: BorrowedStructure<RS>> SemiRingSignature
488    for PolynomialStructure<RS, RSB>
489{
490}
491
492impl<RS: SemiRingEqSignature, RSB: BorrowedStructure<RS>> SemiModuleSignature<RS>
493    for PolynomialStructure<RS, RSB>
494{
495    fn ring(&self) -> &RS {
496        self.coeff_ring()
497    }
498
499    fn scalar_mul(&self, p: &Self::Set, x: &RS::Set) -> Self::Set {
500        self.reduce_poly(Polynomial::from_coeffs(
501            p.coeffs
502                .iter()
503                .map(|c| self.coeff_ring().mul(c, x))
504                .collect(),
505        ))
506    }
507}
508
509impl<RS: RingEqSignature, RSB: BorrowedStructure<RS>> AlgebraSignature<RS>
510    for PolynomialStructure<RS, RSB>
511{
512}
513
514impl<RS: SemiRingEqSignature + CharacteristicSignature, RSB: BorrowedStructure<RS>>
515    CharacteristicSignature for PolynomialStructure<RS, RSB>
516{
517    fn characteristic(&self) -> Natural {
518        self.coeff_ring().characteristic()
519    }
520}
521
522impl<RS: RingEqSignature, RSB: BorrowedStructure<RS>> RingSignature
523    for PolynomialStructure<RS, RSB>
524{
525}
526
527impl<R: MetaType> Polynomial<R>
528where
529    R::Signature: SemiRingEqSignature,
530{
531    pub fn into_coeffs(self) -> Vec<R> {
532        Self::structure().into_coeffs(self)
533    }
534
535    pub fn coeffs(&self) -> impl Iterator<Item = &R> {
536        Self::structure().structure_into_coeffs(self)
537    }
538}
539
540impl<RS: SemiRingEqSignature, RSB: BorrowedStructure<RS>> PolynomialStructure<RS, RSB> {
541    fn structure_into_coeffs(self, a: &Polynomial<RS::Set>) -> impl Iterator<Item = &RS::Set> {
542        (0..self.num_coeffs(a)).map(|i| &a.coeffs[i])
543    }
544
545    pub fn coeffs<'a>(&self, a: &'a Polynomial<RS::Set>) -> impl Iterator<Item = &'a RS::Set> {
546        (0..self.num_coeffs(a)).map(|i| &a.coeffs[i])
547    }
548
549    pub fn into_coeffs(&self, a: Polynomial<RS::Set>) -> Vec<RS::Set> {
550        self.reduce_poly(a).coeffs
551    }
552
553    pub fn num_coeffs(&self, p: &Polynomial<RS::Set>) -> usize {
554        let k = match self.degree(p) {
555            Some(n) => n + 1,
556            None => 0,
557        };
558        debug_assert_eq!(k, self.into_coeffs(p.clone()).len());
559        k
560    }
561
562    pub fn reduce_poly(&self, mut a: Polynomial<RS::Set>) -> Polynomial<RS::Set> {
563        loop {
564            if a.coeffs.is_empty() {
565                break;
566            }
567            if self
568                .coeff_ring()
569                .equal(a.coeffs.last().unwrap(), &self.coeff_ring().zero())
570            {
571                a.coeffs.pop();
572            } else {
573                break;
574            }
575        }
576        a
577    }
578
579    pub fn var(&self) -> Polynomial<RS::Set> {
580        Polynomial::from_coeffs(vec![self.coeff_ring().zero(), self.coeff_ring().one()])
581    }
582
583    pub fn var_pow(&self, n: usize) -> Polynomial<RS::Set> {
584        Polynomial::from_coeffs(
585            (0..=n)
586                .map(|i| {
587                    if i < n {
588                        self.coeff_ring().zero()
589                    } else {
590                        self.coeff_ring().one()
591                    }
592                })
593                .collect(),
594        )
595    }
596
597    pub fn constant_var_pow(&self, x: RS::Set, n: usize) -> Polynomial<RS::Set> {
598        Polynomial::from_coeffs(
599            (0..=n)
600                .map(|i| {
601                    if i < n {
602                        self.coeff_ring().zero()
603                    } else {
604                        x.clone()
605                    }
606                })
607                .collect(),
608        )
609    }
610
611    pub fn coeff<'a>(&self, a: &'a Polynomial<RS::Set>, i: usize) -> Cow<'a, RS::Set> {
612        match a.coeffs.get(i) {
613            Some(c) => Cow::Borrowed(c),
614            None => Cow::Owned(self.coeff_ring().zero()),
615        }
616    }
617
618    pub fn leading_coeff<'a>(&self, a: &'a Polynomial<RS::Set>) -> Option<&'a RS::Set> {
619        Some(a.coeffs.get(self.degree(a)?).unwrap())
620    }
621
622    pub fn evaluate(&self, p: &Polynomial<RS::Set>, x: &RS::Set) -> RS::Set {
623        // f(x) = a + bx + cx^2 + dx^3
624        // evaluate as f(x) = a + x(b + x(c + x(d)))
625        let mut y = self.coeff_ring().zero();
626        for c in p.coeffs.iter().rev() {
627            self.coeff_ring().mul_mut(&mut y, x);
628            self.coeff_ring().add_mut(&mut y, c);
629        }
630        y
631    }
632
633    /// evaluate p(x^k)
634    pub fn evaluate_at_var_pow(&self, p: Polynomial<RS::Set>, k: usize) -> Polynomial<RS::Set> {
635        if k == 0 {
636            Polynomial::constant(self.coeff_ring().sum(p.coeffs))
637        } else {
638            let mut coeffs = vec![];
639            for (i, c) in p.coeffs.into_iter().enumerate() {
640                if i != 0 {
641                    for _j in 0..(k - 1) {
642                        coeffs.push(self.coeff_ring().zero());
643                    }
644                }
645                coeffs.push(c);
646            }
647            Polynomial::from_coeffs(coeffs)
648        }
649    }
650
651    //find p(q(x))
652    pub fn compose(&self, p: &Polynomial<RS::Set>, q: &Polynomial<RS::Set>) -> Polynomial<RS::Set> {
653        PolynomialStructure::new(self.clone())
654            .evaluate(&p.apply_map(|c| Polynomial::constant(c.clone())), q)
655    }
656
657    //if n = deg(p)
658    //return x^n * p(1/x)
659    pub fn reversed(&self, p: &Polynomial<RS::Set>) -> Polynomial<RS::Set> {
660        Polynomial::from_coeffs(
661            self.reduce_poly(p.clone())
662                .coeffs
663                .into_iter()
664                .rev()
665                .collect(),
666        )
667    }
668
669    pub fn mul_var_pow(&self, p: &Polynomial<RS::Set>, n: usize) -> Polynomial<RS::Set> {
670        let mut coeffs = vec![];
671        for _i in 0..n {
672            coeffs.push(self.coeff_ring().zero());
673        }
674        for c in &p.coeffs {
675            coeffs.push(c.clone());
676        }
677        Polynomial { coeffs }
678    }
679
680    pub fn eval_var_pow(&self, p: &Polynomial<RS::Set>, n: usize) -> Polynomial<RS::Set> {
681        if n == 0 {
682            Polynomial::constant(self.coeff_ring().sum(p.coeffs.iter().collect()))
683        } else {
684            let gap = n - 1;
685            let mut coeffs = vec![];
686            for (i, coeff) in p.coeffs.iter().enumerate() {
687                if i != 0 {
688                    for _ in 0..gap {
689                        coeffs.push(self.coeff_ring().zero());
690                    }
691                }
692                coeffs.push(coeff.clone());
693            }
694            Polynomial { coeffs }
695        }
696    }
697
698    pub fn mul_scalar(&self, p: &Polynomial<RS::Set>, x: &RS::Set) -> Polynomial<RS::Set> {
699        self.reduce_poly(Polynomial::from_coeffs(
700            p.coeffs
701                .iter()
702                .map(|c| self.coeff_ring().mul(c, x))
703                .collect(),
704        ))
705    }
706
707    //zero -> None
708    //const -> 0
709    //linear -> 1
710    //quadratic -> 2
711    //...
712    pub fn degree(&self, p: &Polynomial<RS::Set>) -> Option<usize> {
713        //the polynomial representation might not be reduced
714        #[allow(clippy::manual_find)]
715        for i in (0..p.coeffs.len()).rev() {
716            if !self.coeff_ring().is_zero(&p.coeffs[i]) {
717                return Some(i);
718            }
719        }
720        None
721    }
722
723    pub fn as_constant(&self, p: &Polynomial<RS::Set>) -> Option<RS::Set> {
724        if self.num_coeffs(p) == 0 {
725            Some(self.coeff_ring().zero())
726        } else if self.num_coeffs(p) == 1 {
727            Some(p.coeffs[0].clone())
728        } else {
729            None
730        }
731    }
732
733    pub fn is_monic(&self, p: &Polynomial<RS::Set>) -> bool {
734        match self.leading_coeff(p) {
735            Some(lc) => self.coeff_ring().equal(lc, &self.coeff_ring().one()),
736            None => false,
737        }
738    }
739
740    pub fn derivative(&self, mut p: Polynomial<RS::Set>) -> Polynomial<RS::Set> {
741        p = self.reduce_poly(p);
742        if self.num_coeffs(&p) > 0 {
743            for i in 0..self.num_coeffs(&p) - 1 {
744                p.coeffs[i] = p.coeffs[i + 1].clone();
745                self.coeff_ring().mul_mut(
746                    &mut p.coeffs[i],
747                    &self.coeff_ring().from_nat(Natural::from(i + 1)),
748                );
749            }
750            p.coeffs.pop();
751        }
752        p
753    }
754}
755
756impl<RS: IntegralDomainSignature, RSB: BorrowedStructure<RS>> PolynomialStructure<RS, RSB> {
757    pub fn try_quorem(
758        &self,
759        a: &Polynomial<RS::Set>,
760        b: &Polynomial<RS::Set>,
761    ) -> Option<(Polynomial<RS::Set>, Polynomial<RS::Set>)> {
762        //try to find q such that q*b == a
763        // a0 + a1*x + a2*x^2 + ... + am*x^m = (q0 + q1*x + q2*x^2 + ... + qk*x^k) * (b0 + b1*x + b2*x^2 + ... + bn*x^n)
764        // 1 + x + x^2 + x^3 + x^4 + x^5 = (?1 + ?x + ?x^2) * (1 + x + x^2 + x^3)      m=6 k=3 n=4
765
766        let mut a = a.clone();
767
768        let m = self.num_coeffs(&a);
769        let n = self.num_coeffs(b);
770        if n == 0 {
771            None
772        } else if m < n {
773            Some((self.zero(), a))
774        } else {
775            let k = m - n + 1;
776            let mut q_coeffs = (0..k).map(|_i| self.coeff_ring().zero()).collect_vec();
777            for i in (0..k).rev() {
778                //a[i+n-1] = q[i] * b[n-1]
779                debug_assert!(!self.coeff_ring().is_zero(self.coeff(b, n - 1).as_ref()));
780                match self.coeff_ring().try_divide(
781                    self.coeff(&a, i + n - 1).as_ref(),
782                    self.coeff(b, n - 1).as_ref(),
783                ) {
784                    Some(qc) => {
785                        //a -= qc*x^i*b
786                        self.add_mut(
787                            &mut a,
788                            &self.neg(&self.mul_var_pow(&self.mul_scalar(b, &qc), i)),
789                        );
790                        q_coeffs[i] = qc;
791                    }
792                    None => {
793                        return None;
794                    }
795                }
796            }
797            Some((Polynomial::from_coeffs(q_coeffs), a))
798        }
799    }
800
801    pub fn div_impl(
802        &self,
803        a: &Polynomial<RS::Set>,
804        b: &Polynomial<RS::Set>,
805    ) -> Option<Polynomial<RS::Set>> {
806        match self.try_quorem(a, b) {
807            Some((q, r)) => {
808                debug_assert!(self.equal(&self.add(&self.mul(&q, b), &r), a));
809                if self.is_zero(&r) { Some(q) } else { None }
810            }
811            None => None,
812        }
813    }
814
815    //None if b = 0
816    //error if deg(a) < deg(b)
817    pub fn pseudorem(
818        &self,
819        mut a: Polynomial<RS::Set>,
820        b: &Polynomial<RS::Set>,
821    ) -> Option<Result<Polynomial<RS::Set>, &'static str>> {
822        let m = self.num_coeffs(&a);
823        let n = self.num_coeffs(b);
824
825        if n == 0 {
826            None
827        } else if m < n {
828            Some(Err("Should have deg(a) >= deg(b) for pseudo remainder"))
829        } else {
830            self.mul_mut(
831                &mut a,
832                &Polynomial::constant(
833                    self.coeff_ring()
834                        .nat_pow(self.coeff(b, n - 1).as_ref(), &Natural::from(m - n + 1)),
835                ),
836            );
837
838            if let Some((_q, r)) = self.try_quorem(&a, b) {
839                Some(Ok(r))
840            } else {
841                panic!();
842            }
843        }
844    }
845
846    /// Output: (r, s) where
847    ///     r is the pseudo remainder sequence
848    ///     s is the scalar subresultants
849    pub fn pseudo_remainder_subresultant_sequence(
850        &self,
851        mut a: Polynomial<RS::Set>,
852        mut b: Polynomial<RS::Set>,
853    ) -> (Vec<Polynomial<RS::Set>>, Vec<RS::Set>) {
854        match (self.degree(&a), self.degree(&b)) {
855            (None, None) => (vec![], vec![]),
856            (None, Some(_)) => (vec![b], vec![self.coeff_ring().one()]),
857            (Some(_), None) => (vec![a], vec![self.coeff_ring().one()]),
858            (Some(mut a_deg), Some(mut b_deg)) => {
859                if a_deg < b_deg {
860                    (a, b, a_deg, b_deg) = (b, a, b_deg, a_deg);
861                }
862                debug_assert!(a_deg >= b_deg);
863                let mut prs = vec![a.clone(), b.clone()];
864                let mut diff_deg = a_deg - b_deg;
865                let mut beta = self.coeff_ring().nat_pow(
866                    &self.coeff_ring().neg(&self.coeff_ring().one()),
867                    &Natural::from(diff_deg + 1),
868                );
869                let mut r = self.mul_scalar(&self.pseudorem(a, &b).unwrap().unwrap(), &beta);
870                let mut lc_b = self.leading_coeff(&b).unwrap().clone();
871                let mut gamma = self.coeff_ring().nat_pow(&lc_b, &Natural::from(diff_deg));
872                let mut ssres = vec![self.coeff_ring().one(), gamma.clone()];
873                gamma = self.coeff_ring().neg(&gamma);
874                loop {
875                    #[allow(clippy::single_match_else)]
876                    match self.degree(&r) {
877                        Some(r_deg) => {
878                            prs.push(r.clone());
879                            (a, b, b_deg, diff_deg) = (b, r, r_deg, b_deg - r_deg);
880                            beta = self.coeff_ring().mul(
881                                &self.coeff_ring().neg(&lc_b),
882                                &self.coeff_ring().nat_pow(&gamma, &Natural::from(diff_deg)),
883                            );
884                            r = self
885                                .try_divide(
886                                    &self.pseudorem(a, &b).unwrap().unwrap(),
887                                    &Polynomial::constant(beta),
888                                )
889                                .unwrap();
890                            lc_b = self.leading_coeff(&b).unwrap().clone();
891                            gamma = if diff_deg > 1 {
892                                self.coeff_ring()
893                                    .try_divide(
894                                        &self.coeff_ring().nat_pow(
895                                            &self.coeff_ring().neg(&lc_b),
896                                            &Natural::from(diff_deg),
897                                        ),
898                                        &self
899                                            .coeff_ring()
900                                            .nat_pow(&gamma, &Natural::from(diff_deg - 1)),
901                                    )
902                                    .unwrap()
903                            } else {
904                                self.coeff_ring().neg(&lc_b)
905                            };
906                            ssres.push(self.coeff_ring().neg(&gamma));
907                        }
908                        None => {
909                            debug_assert!(self.is_zero(&r));
910                            break;
911                        }
912                    }
913                }
914                (prs, ssres)
915            }
916        }
917    }
918
919    // efficiently compute the gcd of a and b up to scalar multipication using pseudo-remainder subresultant sequence
920    pub fn subresultant_gcd(
921        &self,
922        a: Polynomial<RS::Set>,
923        b: Polynomial<RS::Set>,
924    ) -> Polynomial<RS::Set> {
925        // The GCD (up to scalar mul) is the last subresultant pseudoremainder
926        let (mut prs, _) = self.pseudo_remainder_subresultant_sequence(a, b);
927        prs.pop().unwrap()
928    }
929
930    pub fn resultant(&self, a: Polynomial<RS::Set>, b: Polynomial<RS::Set>) -> RS::Set {
931        if self.is_zero(&a) || self.is_zero(&b) {
932            self.coeff_ring().zero()
933        } else {
934            let (mut prs, mut ssres) = self.pseudo_remainder_subresultant_sequence(a, b);
935            if self.degree(&prs.pop().unwrap()).unwrap() > 0 {
936                self.coeff_ring().zero()
937            } else {
938                ssres.pop().unwrap()
939            }
940        }
941    }
942
943    pub fn is_squarefree(&self, p: &Polynomial<RS::Set>) -> bool {
944        let dp = self.derivative(p.clone());
945        self.degree(&self.subresultant_gcd(p.clone(), dp)).unwrap() == 0
946    }
947
948    pub fn discriminant(&self, p: Polynomial<RS::Set>) -> Result<RS::Set, &'static str> {
949        match self.degree(&p) {
950            Some(n) => {
951                if n == 0 {
952                    Err("Discriminant of a constant polynomial is undefined.")
953                } else {
954                    let an = self.coeff(&p, n).as_ref().clone(); // leading coeff
955                    let dp = self.derivative(p.clone());
956                    let disc = self
957                        .coeff_ring()
958                        .try_divide(&self.resultant(p, dp), &an)
959                        .unwrap();
960                    // multiply by (-1)^{n(n+1)/2}
961                    match n % 4 {
962                        0 | 1 => Ok(disc),
963                        2 | 3 => Ok(self.coeff_ring().neg(&disc)),
964                        _ => unreachable!(),
965                    }
966                }
967            }
968            None => Err("Discriminant of zero polynomial is undefined."),
969        }
970    }
971}
972
973impl<RS: IntegralDomainSignature, RSB: BorrowedStructure<RS>> TryReciprocalSignature
974    for PolynomialStructure<RS, RSB>
975{
976    fn try_reciprocal(&self, a: &Self::Set) -> Option<Self::Set> {
977        self.try_divide(&self.one(), a)
978    }
979}
980
981impl<RS: IntegralDomainSignature, RSB: BorrowedStructure<RS>> CancellativeMultiplicationSignature
982    for PolynomialStructure<RS, RSB>
983{
984    fn try_divide(&self, a: &Self::Set, b: &Self::Set) -> Option<Self::Set> {
985        self.div_impl(a, b)
986    }
987}
988
989impl<RS: IntegralDomainSignature, RSB: BorrowedStructure<RS>> MultiplicativeIntegralMonoidSignature
990    for PolynomialStructure<RS, RSB>
991{
992}
993
994impl<RS: IntegralDomainSignature, RSB: BorrowedStructure<RS>> IntegralDomainSignature
995    for PolynomialStructure<RS, RSB>
996{
997}
998
999// #[derive(Debug, Clone, PartialEq, Eq)]
1000// pub struct PolynomialFactorOrderingStructure<Ring: RingSignature, RingB: BorrowedStructure<Ring>> {
1001//     _coeff_ring: PhantomData<Ring>,
1002//     coeff_ring: RingB,
1003// }
1004
1005// impl<Ring: RingSignature, RingB: BorrowedStructure<Ring>>
1006//     PolynomialFactorOrderingStructure<Ring, RingB>
1007// {
1008//     fn new(coeff_ring: RingB) -> Self {
1009//         Self {
1010//             _coeff_ring: PhantomData::default(),
1011//             coeff_ring,
1012//         }
1013//     }
1014
1015//     fn coeff_ring(&self) -> &Ring {
1016//         self.coeff_ring.borrow()
1017//     }
1018// }
1019
1020// impl<Ring: RingSignature, RingB: BorrowedStructure<Ring>> Signature
1021//     for PolynomialFactorOrderingStructure<Ring, RingB>
1022// {
1023// }
1024
1025// impl<Ring: RingSignature, RingB: BorrowedStructure<Ring>> SetSignature
1026//     for PolynomialFactorOrderingStructure<Ring, RingB>
1027// {
1028//     type Set = Polynomial<Ring::Set>;
1029
1030//     fn is_element(&self, x: &Self::Set) -> bool {
1031//         self.coeff_ring().polynomial_ring().is_element(x)
1032//     }
1033// }
1034
1035// impl<Ring: RingSignature, RingB: BorrowedStructure<Ring>> EqSignature
1036//     for PolynomialFactorOrderingStructure<Ring, RingB>
1037// {
1038//     fn equal(&self, a: &Self::Set, b: &Self::Set) -> bool {
1039//         self.coeff_ring().polynomial_ring().equal(a, b)
1040//     }
1041// }
1042
1043// impl<Ring: RingSignature, RingB: BorrowedStructure<Ring>> OrdSignature
1044//     for PolynomialFactorOrderingStructure<Ring, RingB>
1045// {
1046//     fn cmp(&self, a: &Self::Set, b: &Self::Set) -> std::cmp::Ordering {
1047//         std::cmp::Ordering::Equal
1048//     }
1049// }
1050
1051impl<RS: UniqueFactorizationMonoidSignature + IntegralDomainSignature, RSB: BorrowedStructure<RS>>
1052    UniqueFactorizationMonoidSignature for PolynomialStructure<RS, RSB>
1053{
1054    type FactoredExponent = NaturalCanonicalStructure;
1055
1056    fn factorization_exponents(&self) -> &Self::FactoredExponent {
1057        Natural::structure_ref()
1058    }
1059
1060    fn into_factorization_exponents(self) -> Self::FactoredExponent {
1061        Natural::structure()
1062    }
1063
1064    fn try_is_irreducible(&self, _a: &Self::Set) -> Option<bool> {
1065        None
1066    }
1067
1068    fn factorization_pow(&self, a: &Self::Set, k: &Natural) -> Self::Set {
1069        self.nat_pow(a, k)
1070    }
1071}
1072
1073impl<RS: GreatestCommonDivisorSignature, RSB: BorrowedStructure<RS>> PolynomialStructure<RS, RSB> {
1074    pub fn factor_primitive(
1075        &self,
1076        mut p: Polynomial<RS::Set>,
1077    ) -> Option<(RS::Set, Polynomial<RS::Set>)> {
1078        if self.is_zero(&p) {
1079            None
1080        } else {
1081            let g = self.coeff_ring().gcd_list(p.coeffs.iter().collect());
1082            for i in 0..p.coeffs.len() {
1083                p.coeffs[i] = self.coeff_ring().try_divide(&p.coeffs[i], &g).unwrap();
1084            }
1085            Some((g, p))
1086        }
1087    }
1088
1089    pub fn is_primitive(&self, p: Polynomial<RS::Set>) -> bool {
1090        match self.factor_primitive(p) {
1091            Some((unit, _)) => self.coeff_ring().is_unit(&unit),
1092            None => false,
1093        }
1094    }
1095
1096    pub fn primitive_part(&self, p: Polynomial<RS::Set>) -> Option<Polynomial<RS::Set>> {
1097        self.factor_primitive(p).map(|(_unit, prim)| prim)
1098    }
1099
1100    pub fn gcd_by_primitive_subresultant(
1101        &self,
1102        a: Polynomial<RS::Set>,
1103        b: Polynomial<RS::Set>,
1104    ) -> Polynomial<RS::Set> {
1105        if self.is_zero(&a) {
1106            b
1107        } else if self.is_zero(&b) {
1108            a
1109        } else {
1110            let (a_content, a_prim) = self.factor_primitive(a).unwrap();
1111            let (b_content, b_prim) = self.factor_primitive(b).unwrap();
1112            let g_content = self.coeff_ring().gcd(&a_content, &b_content);
1113            let g_prim = self
1114                .factor_primitive(self.subresultant_gcd(a_prim, b_prim))
1115                .unwrap()
1116                .1;
1117            self.mul(&Polynomial::constant(g_content), &g_prim)
1118        }
1119    }
1120}
1121
1122impl<FS: FieldSignature, FSB: BorrowedStructure<FS>> GreatestCommonDivisorSignature
1123    for PolynomialStructure<FS, FSB>
1124{
1125    fn gcd(&self, x: &Self::Set, y: &Self::Set) -> Self::Set {
1126        self.euclidean_gcd(x.clone(), y.clone())
1127    }
1128}
1129
1130impl<FS: FieldSignature, FSB: BorrowedStructure<FS>> BezoutDomainSignature
1131    for PolynomialStructure<FS, FSB>
1132{
1133    fn xgcd(&self, x: &Self::Set, y: &Self::Set) -> (Self::Set, Self::Set, Self::Set) {
1134        self.euclidean_xgcd(x.clone(), y.clone())
1135    }
1136}
1137
1138impl<RS: GreatestCommonDivisorSignature + CharZeroRingSignature, RSB: BorrowedStructure<RS>>
1139    PolynomialStructure<RS, RSB>
1140{
1141    #[allow(clippy::let_and_return)]
1142    pub fn primitive_squarefree_part(&self, f: Polynomial<RS::Set>) -> Polynomial<RS::Set> {
1143        if self.is_zero(&f) {
1144            f
1145        } else {
1146            let g = self.subresultant_gcd(f.clone(), self.derivative(f.clone()));
1147            let (_c, g_prim) = self.factor_primitive(g).unwrap();
1148            let (_c, f_prim) = self.factor_primitive(f).unwrap();
1149            let f_prim_sqfree = self.try_divide(&f_prim, &g_prim).unwrap();
1150            f_prim_sqfree
1151        }
1152    }
1153}
1154
1155impl<RS: FavoriteAssociateSignature + IntegralDomainSignature, RSB: BorrowedStructure<RS>>
1156    FavoriteAssociateSignature for PolynomialStructure<RS, RSB>
1157{
1158    fn factor_fav_assoc(
1159        &self,
1160        a: &Polynomial<RS::Set>,
1161    ) -> (Polynomial<RS::Set>, Polynomial<RS::Set>) {
1162        if self.is_zero(a) {
1163            (self.one(), self.zero())
1164        } else {
1165            let mut a = a.clone();
1166            let (u, _c) = self
1167                .coeff_ring()
1168                .factor_fav_assoc(&a.coeffs[self.num_coeffs(&a) - 1]);
1169            for i in 0..a.coeffs.len() {
1170                a.coeffs[i] = self.coeff_ring().try_divide(&a.coeffs[i], &u).unwrap();
1171            }
1172            (Polynomial::constant(u), a.clone())
1173        }
1174    }
1175}
1176
1177impl<RS: CharZeroRingSignature + EqSignature, RSB: BorrowedStructure<RS>> CharZeroRingSignature
1178    for PolynomialStructure<RS, RSB>
1179{
1180    fn try_to_int(&self, x: &Self::Set) -> Option<Integer> {
1181        self.coeff_ring().try_to_int(&self.as_constant(x)?)
1182    }
1183}
1184
1185impl<
1186    RS: IntegralDomainSignature + TryReciprocalSignature,
1187    RSB: BorrowedStructure<RS>,
1188    B: BorrowedStructure<PolynomialStructure<RS, RSB>>,
1189> CountableSetSignature for MultiplicativeMonoidUnitsStructure<PolynomialStructure<RS, RSB>, B>
1190where
1191    for<'a> MultiplicativeMonoidUnitsStructure<RS, &'a RS>: FiniteSetSignature<Set = RS::Set>,
1192{
1193    fn generate_all_elements(&self) -> impl Iterator<Item = Self::Set> + Clone {
1194        self.list_all_elements().into_iter()
1195    }
1196}
1197
1198impl<
1199    RS: IntegralDomainSignature + TryReciprocalSignature,
1200    RSB: BorrowedStructure<RS>,
1201    B: BorrowedStructure<PolynomialStructure<RS, RSB>>,
1202> FiniteSetSignature for MultiplicativeMonoidUnitsStructure<PolynomialStructure<RS, RSB>, B>
1203where
1204    for<'a> MultiplicativeMonoidUnitsStructure<RS, &'a RS>: FiniteSetSignature<Set = RS::Set>,
1205{
1206    fn list_all_elements(&self) -> Vec<Self::Set> {
1207        self.monoid()
1208            .coeff_ring()
1209            .units()
1210            .list_all_elements()
1211            .into_iter()
1212            .map(Polynomial::constant)
1213            .collect()
1214    }
1215}
1216
1217// pub trait InterpolatablePolynomials: ComRS {
1218//     fn interpolate(points: &Vec<(Self::ElemT, Self::ElemT)>) -> Option<Polynomial<Self>>;
1219// }
1220
1221impl<FS: FieldSignature, FSB: BorrowedStructure<FS>> EuclideanDivisionSignature
1222    for PolynomialStructure<FS, FSB>
1223{
1224    fn norm(&self, elem: &Self::Set) -> Option<Natural> {
1225        Some(Natural::from(self.degree(elem)?))
1226    }
1227
1228    fn quorem(&self, a: &Self::Set, b: &Self::Set) -> Option<(Self::Set, Self::Set)> {
1229        if self.is_zero(b) {
1230            None
1231        } else {
1232            Some(self.try_quorem(a, b).unwrap())
1233        }
1234    }
1235}
1236
1237impl<RS: IntegralDomainSignature, RSB: BorrowedStructure<RS>> PolynomialStructure<RS, RSB> {
1238    pub fn interpolate_by_lagrange_basis(
1239        &self,
1240        points: &[(RS::Set, RS::Set)],
1241    ) -> Option<Polynomial<RS::Set>> {
1242        /*
1243        points should be a list of pairs (xi, yi) where the xi are distinct
1244
1245        find f such that f(x1) = y1, f(x2) = y2, f(x3) = y3
1246        find f1(x), f2(x), f3(x) such that fi(xi)=1 and fi(xj)=0 if i!=j
1247
1248            (x-x2) (x-x3)         (x-x1) (x-x3)         (x-x1) (x-x2)
1249        f1= --------------    f2= --------------    f3= --------------
1250            (x1-x2)(x1-x3)        (x2-x1)(x2-x3)        (x3-x1)(x3-x2)
1251
1252        so f(x) = y1f1(x) + y2f2(x) + y3f3(x)
1253                = (   y1 (x-x2)(x-x3) (x2-x3)
1254                    + y2 (x1-x)(x-x3) (x1-x3)
1255                    + y3 (x1-x)(x2-x) (x1-x2) )
1256                  / (x1-x2)(x1-x3)(x2-x3)
1257
1258         */
1259        let mut numerator = self.zero();
1260        for i in 0..points.len() {
1261            let (_xi, yi) = &points[i];
1262            let mut term = Polynomial::constant(yi.clone());
1263
1264            #[allow(clippy::needless_range_loop)]
1265            for j in i + 1..points.len() {
1266                // (x - xj) for j<i
1267                let (xj, _yj) = &points[j];
1268                self.mul_mut(
1269                    &mut term,
1270                    &Polynomial::from_coeffs(vec![
1271                        self.coeff_ring().neg(xj),
1272                        self.coeff_ring().one(),
1273                    ]),
1274                );
1275            }
1276            #[allow(clippy::needless_range_loop)]
1277            for j in 0..i {
1278                // (xj - x) for i<j
1279                let (xj, _yj) = &points[j];
1280                self.mul_mut(
1281                    &mut term,
1282                    &Polynomial::from_coeffs(vec![
1283                        xj.clone(),
1284                        self.coeff_ring().neg(&self.coeff_ring().one()),
1285                    ]),
1286                );
1287            }
1288
1289            for j in 0..points.len() {
1290                for k in j + 1..points.len() {
1291                    if i != j && i != k {
1292                        let (xj, _yj) = &points[j];
1293                        let (xk, _yk) = &points[k];
1294                        self.mul_mut(
1295                            &mut term,
1296                            &Polynomial::constant(
1297                                self.coeff_ring().add(&self.coeff_ring().neg(xk), xj),
1298                            ),
1299                        );
1300                    }
1301                }
1302            }
1303            self.add_mut(&mut numerator, &term);
1304        }
1305
1306        let mut denominator = self.one();
1307        for i in 0..points.len() {
1308            let (xi, _yi) = &points[i];
1309            #[allow(clippy::needless_range_loop)]
1310            for j in i + 1..points.len() {
1311                let (xj, _yj) = &points[j];
1312                self.mul_mut(
1313                    &mut denominator,
1314                    &Polynomial::constant(self.coeff_ring().add(&self.coeff_ring().neg(xj), xi)),
1315                );
1316            }
1317        }
1318
1319        if self.is_zero(&denominator) {
1320            panic!("are the input points distinct?");
1321        }
1322
1323        self.try_divide(&numerator, &denominator)
1324    }
1325}
1326
1327impl<RS: ReducedHermiteAlgorithmSignature, RSB: BorrowedStructure<RS>>
1328    PolynomialStructure<RS, RSB>
1329{
1330    pub fn interpolate_by_linear_system(
1331        &self,
1332        points: &[(RS::Set, RS::Set)],
1333    ) -> Option<Polynomial<RS::Set>> {
1334        /*
1335        e.g. finding a degree 2 polynomial f(x)=a+bx+cx^2 such that
1336        f(1)=3
1337        f(2)=1
1338        f(3)=-2
1339        is the same as solving the linear system for a, b, c
1340        / 1 1 1 \ / a \   / 3  \
1341        | 1 2 4 | | b | = | 1  |
1342        \ 1 3 9 / \ c /   \ -2 /
1343        */
1344
1345        let matrix_structure = MatrixStructure::new(self.coeff_ring().clone());
1346
1347        let n = points.len();
1348        let mut mat = matrix_structure.zero(n, n);
1349        #[allow(clippy::needless_range_loop)]
1350        for r in 0..n {
1351            let (x, _y) = &points[r];
1352            let mut x_pow = self.coeff_ring().one();
1353            for c in 0..n {
1354                *mat.at_mut(r, c).unwrap() = x_pow.clone();
1355                self.coeff_ring().mul_mut(&mut x_pow, x);
1356            }
1357        }
1358
1359        // let mut output_vec = matrix_structure.zero(n, 1);
1360        // for r in 0..n {
1361        //     let (_x, y) = &points[r];
1362        //     *output_vec.at_mut(r, 0).unwrap() = y.clone();
1363        // }
1364
1365        matrix_structure
1366            .col_solve(mat, &points.iter().map(|(_x, y)| y.clone()).collect())
1367            .map(Polynomial::from_coeffs)
1368    }
1369}
1370
1371pub fn factor_primitive_fof<
1372    Ring: GreatestCommonDivisorSignature,
1373    Field: FieldSignature,
1374    Fof: FieldOfFractionsInclusion<Ring, Field>,
1375>(
1376    fof_inclusion: &Fof,
1377    p: &Polynomial<Field::Set>,
1378) -> (Field::Set, Polynomial<Ring::Set>) {
1379    let ring = fof_inclusion.domain();
1380    let field = fof_inclusion.range();
1381    let poly_ring = PolynomialStructure::new(ring.clone());
1382
1383    let div = fof_inclusion.domain().lcm_list(
1384        p.coeffs
1385            .iter()
1386            .map(|c| fof_inclusion.denominator(c))
1387            .collect(),
1388    );
1389
1390    let (mul, prim) = poly_ring
1391        .factor_primitive(p.apply_map(|c| {
1392            fof_inclusion
1393                .try_preimage(&field.mul(&fof_inclusion.image(&div), c))
1394                .unwrap()
1395        }))
1396        .unwrap();
1397
1398    (
1399        field
1400            .try_divide(&fof_inclusion.image(&mul), &fof_inclusion.image(&div))
1401            .unwrap(),
1402        prim,
1403    )
1404}
1405
1406impl<Field: MetaType> Polynomial<Field>
1407where
1408    Field::Signature: FieldSignature,
1409    Polynomial<Field>:
1410        MetaType<Signature = PolynomialStructure<Field::Signature, Field::Signature>>,
1411    PrincipalIntegerMap<Field::Signature, Field::Signature>:
1412        FieldOfFractionsInclusion<IntegerCanonicalStructure, Field::Signature>,
1413{
1414    pub fn factor_primitive_fof(&self) -> (Field, Polynomial<Integer>) {
1415        factor_primitive_fof(
1416            &PrincipalIntegerMap::new(Self::structure().coeff_ring().clone()),
1417            self,
1418        )
1419    }
1420
1421    pub fn primitive_part_fof(&self) -> Polynomial<Integer> {
1422        self.factor_primitive_fof().1
1423    }
1424}
1425
1426impl<R: MetaType> MetaType for Polynomial<R> {
1427    type Signature = PolynomialStructure<R::Signature, R::Signature>;
1428
1429    fn structure() -> Self::Signature {
1430        PolynomialStructure::new(R::structure())
1431    }
1432}
1433
1434impl<R: MetaType> Polynomial<R>
1435where
1436    R::Signature: RingEqSignature<Set = R>,
1437{
1438    #[allow(unused)]
1439    fn reduce(self) -> Self {
1440        Self::structure().reduce_poly(self)
1441    }
1442}
1443
1444impl<R: MetaType> Display for Polynomial<R>
1445where
1446    R::Signature: SemiRingSignature + EqSignature + ToStringSignature,
1447{
1448    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1449        write!(f, "{}", Self::structure().to_string(self))
1450    }
1451}
1452
1453impl<R: MetaType> PartialEq for Polynomial<R>
1454where
1455    R::Signature: SemiRingEqSignature,
1456{
1457    fn eq(&self, other: &Self) -> bool {
1458        Self::structure().equal(self, other)
1459    }
1460}
1461
1462impl<R: MetaType> Eq for Polynomial<R> where R::Signature: SemiRingEqSignature {}
1463
1464impl<R: MetaType + Hash> Hash for Polynomial<R>
1465where
1466    R::Signature: SemiRingEqSignature,
1467{
1468    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
1469        Self::structure()
1470            .reduce_poly(self.clone())
1471            .coeffs
1472            .hash(state);
1473    }
1474}
1475
1476impl<R: MetaType> Polynomial<R>
1477where
1478    R::Signature: SemiRingEqSignature<Set = R>,
1479{
1480    pub fn var() -> Self {
1481        Self::structure().var()
1482    }
1483
1484    pub fn var_pow(n: usize) -> Self {
1485        Self::structure().var_pow(n)
1486    }
1487
1488    pub fn coeff<'a>(&'a self, i: usize) -> Cow<'a, R> {
1489        Self::structure().coeff(self, i).clone()
1490    }
1491
1492    pub fn leading_coeff(&self) -> Option<R> {
1493        Self::structure().leading_coeff(self).cloned()
1494    }
1495
1496    pub fn mul_scalar(&self, x: &R) -> Self {
1497        Self::structure().mul_scalar(self, x)
1498    }
1499
1500    pub fn evaluate(&self, x: &R) -> R {
1501        Self::structure().evaluate(self, x)
1502    }
1503
1504    pub fn evaluate_at_var_pow(self, k: usize) -> Self {
1505        Self::structure().evaluate_at_var_pow(self, k)
1506    }
1507
1508    pub fn mul_var_pow(&self, n: usize) -> Self {
1509        Self::structure().mul_var_pow(self, n)
1510    }
1511
1512    pub fn eval_var_pow(&self, n: usize) -> Self {
1513        Self::structure().eval_var_pow(self, n)
1514    }
1515
1516    //find p(q(x))
1517    pub fn compose(p: &Self, q: &Self) -> Self {
1518        Self::structure().compose(p, q)
1519    }
1520
1521    pub fn num_coeffs(&self) -> usize {
1522        Self::structure().num_coeffs(self)
1523    }
1524
1525    //if n = deg(p)
1526    //return x^n * p(1/x)
1527    pub fn reversed(&self) -> Self {
1528        Self::structure().reversed(self)
1529    }
1530
1531    pub fn degree(&self) -> Option<usize> {
1532        Self::structure().degree(self)
1533    }
1534
1535    pub fn as_constant(&self) -> Option<R> {
1536        Self::structure().as_constant(self)
1537    }
1538
1539    pub fn is_monic(&self) -> bool {
1540        Self::structure().is_monic(self)
1541    }
1542
1543    pub fn derivative(self) -> Self {
1544        Self::structure().derivative(self)
1545    }
1546}
1547
1548impl<R: MetaType> Polynomial<R>
1549where
1550    R::Signature: IntegralDomainSignature,
1551{
1552    pub fn try_quorem(a: &Self, b: &Self) -> Option<(Self, Self)> {
1553        Self::structure().try_quorem(a, b)
1554    }
1555
1556    pub fn pseudorem(a: &Self, b: &Self) -> Option<Result<Polynomial<R>, &'static str>> {
1557        Self::structure().pseudorem(a.clone(), b)
1558    }
1559
1560    pub fn pseudo_remainder_subresultant_sequence(a: Self, b: Self) -> (Vec<Self>, Vec<R>) {
1561        Self::structure().pseudo_remainder_subresultant_sequence(a, b)
1562    }
1563
1564    pub fn subresultant_gcd(a: &Self, b: &Self) -> Self {
1565        Self::structure().subresultant_gcd(a.clone(), b.clone())
1566    }
1567
1568    pub fn resultant(a: &Self, b: &Self) -> R {
1569        Self::structure().resultant(a.clone(), b.clone())
1570    }
1571
1572    pub fn is_squarefree(&self) -> bool {
1573        Self::structure().is_squarefree(self)
1574    }
1575
1576    pub fn discriminant(self) -> Result<R, &'static str> {
1577        Self::structure().discriminant(self)
1578    }
1579
1580    pub fn interpolate_by_lagrange_basis(points: &[(R, R)]) -> Option<Self> {
1581        Self::structure().interpolate_by_lagrange_basis(points)
1582    }
1583}
1584
1585impl<R: MetaType> Polynomial<R>
1586where
1587    R::Signature: ReducedHermiteAlgorithmSignature,
1588{
1589    pub fn interpolate_by_linear_system(points: &[(R, R)]) -> Option<Self> {
1590        Self::structure().interpolate_by_linear_system(points)
1591    }
1592}
1593
1594impl<R: MetaType> Polynomial<R>
1595where
1596    R::Signature: GreatestCommonDivisorSignature,
1597{
1598    pub fn factor_primitive(self) -> Option<(R, Polynomial<R>)> {
1599        Self::structure().factor_primitive(self)
1600    }
1601
1602    pub fn primitive_part(self) -> Option<Polynomial<R>> {
1603        Self::structure().primitive_part(self)
1604    }
1605
1606    pub fn gcd_by_primitive_subresultant(a: Polynomial<R>, b: Polynomial<R>) -> Polynomial<R> {
1607        Self::structure().gcd_by_primitive_subresultant(a, b)
1608    }
1609}
1610
1611impl<R: MetaType> Polynomial<R>
1612where
1613    R::Signature: GreatestCommonDivisorSignature + CharZeroRingSignature,
1614{
1615    pub fn primitive_squarefree_part(&self) -> Self {
1616        Self::structure().primitive_squarefree_part(self.clone())
1617    }
1618}
1619
1620#[allow(clippy::single_match, clippy::single_match_else, clippy::erasing_op)]
1621#[cfg(test)]
1622mod tests {
1623    use super::*;
1624    use crate::finite_fields::quaternary_field::*;
1625
1626    #[test]
1627    fn nat_poly_display() {
1628        let p = Polynomial::<Natural>::from_coeffs(vec![Natural::ONE, Natural::ONE, Natural::ONE]);
1629        println!("{}", p);
1630    }
1631
1632    #[test]
1633    fn test_constant_var_pow() {
1634        let ring = Polynomial::<Integer>::structure();
1635        let p = ring.constant_var_pow(Integer::from(2), 7);
1636        let q = ring.mul(&ring.from_int(Integer::from(2)), &ring.var_pow(7));
1637        assert_eq!(p, q);
1638    }
1639
1640    #[test]
1641    fn test_display_poly_over_display_canonical_ring() {
1642        let f = Polynomial {
1643            coeffs: vec![
1644                Integer::from(-2),
1645                Integer::from(1),
1646                Integer::from(2),
1647                Integer::from(4),
1648            ],
1649        };
1650
1651        //test that this compiles
1652        println!("{}", f);
1653        println!("{}", f.into_ergonomic());
1654        //    Integer : Display
1655        // => CanonicalRS<Integer> : DisplayableRSStructure
1656        // => PolynomialStructure<CanonicalRS<Integer>> : DisplayableRSStructure
1657        // => CanonicalRS<Polynomial<Integer>> : DisplayableRSStructure
1658        // => Polynomial<Integer> : Display AND RSElement<CanonicalRS<Polynomial<Integer>>> : Display
1659    }
1660
1661    #[test]
1662    fn invariant_reduction() {
1663        let unreduced = Polynomial::<Integer>::from_coeffs(vec![
1664            Integer::from(0),
1665            Integer::from(1),
1666            Integer::from(0),
1667            Integer::from(0),
1668        ]);
1669        let reduced = Polynomial::from_coeffs(vec![Integer::from(0), Integer::from(1)]);
1670        assert_eq!(unreduced, reduced);
1671
1672        let unreduced = Polynomial::from_coeffs(vec![
1673            Integer::from(0),
1674            Integer::from(0),
1675            Integer::from(0),
1676            Integer::from(0),
1677        ]);
1678        let reduced = Polynomial::<Integer>::zero();
1679        assert_eq!(unreduced, reduced);
1680    }
1681
1682    #[test]
1683    fn divisibility_over_integers() {
1684        let x = &Polynomial::<Integer>::var().into_ergonomic();
1685
1686        let a = (2 * x + 1) * (3 * x + 2) * (4 * x + 5) * (5 * x + 6) * (6 * x + 7);
1687        let b = (2 * x + 1) * (3 * x + 2) * (4 * x + 5);
1688        match Polynomial::try_divide(a.ref_set(), b.ref_set()) {
1689            Some(c) => {
1690                println!("{:?} {:?} {:?}", a, b, c);
1691                assert_eq!(a, b * c.into_ergonomic());
1692            }
1693            None => panic!(),
1694        }
1695
1696        let a = (2 * x + 1) * (3 * x + 2) * (4 * x + 5) * (5 * x + 6) * (6 * x + 7);
1697        let b = (2 * x + 1) * (3 * x + 2) * (4 * x + 5) + 1;
1698        match Polynomial::try_divide(a.ref_set(), b.ref_set()) {
1699            Some(_) => panic!(),
1700            None => {}
1701        }
1702
1703        let a = (2 * x + 1) * (3 * x + 2) * (4 * x + 5);
1704        let b = (2 * x + 1) * (3 * x + 2) * (4 * x + 5) * (5 * x + 6) * (6 * x + 7);
1705        match Polynomial::try_divide(a.ref_set(), b.ref_set()) {
1706            Some(_) => panic!(),
1707            None => {}
1708        }
1709
1710        let a = (2 * x + 1) * (3 * x + 2) * (4 * x + 5);
1711        let b = 0 * x;
1712        match Polynomial::try_divide(a.ref_set(), b.ref_set()) {
1713            Some(_) => panic!(),
1714            None => {}
1715        }
1716
1717        let a = 0 * x;
1718        let b = (x - x) + 5;
1719        match Polynomial::try_divide(a.ref_set(), b.ref_set()) {
1720            Some(c) => {
1721                assert_eq!(c, Polynomial::zero());
1722            }
1723            None => panic!(),
1724        }
1725
1726        let a = 3087 * x - 8805 * x.pow(2) + 607 * x.pow(3) + x.pow(4);
1727        let b = (x - x) + 1;
1728        match Polynomial::try_divide(a.ref_set(), b.ref_set()) {
1729            Some(c) => {
1730                assert_eq!(c.into_ergonomic(), a);
1731            }
1732            None => panic!(),
1733        }
1734    }
1735
1736    #[test]
1737    fn divisibility_over_f4() {
1738        let x = &Polynomial::<QuaternaryField>::var().into_ergonomic();
1739
1740        let a = 1 + x + x.pow(2);
1741        let b = Polynomial::constant(QuaternaryField::Alpha).into_ergonomic() + x;
1742        match Polynomial::try_divide(a.ref_set(), b.ref_set()) {
1743            Some(c) => {
1744                println!("{:?} {:?} {:?}", a, b, c);
1745                assert_eq!(a, b * c.into_ergonomic());
1746            }
1747            None => panic!(),
1748        }
1749    }
1750
1751    #[test]
1752    fn euclidean() {
1753        let x = &Polynomial::<Rational>::var().into_ergonomic();
1754
1755        let a = 1 + x + 3 * x.pow(2) + x.pow(3) + 7 * x.pow(4) + x.pow(5);
1756        let b = 1 + x + 3 * x.pow(2) + 2 * x.pow(3);
1757        let (q, r) = Polynomial::quorem(a.ref_set(), b.ref_set()).unwrap();
1758        let (q, r) = (q.into_ergonomic(), r.into_ergonomic());
1759        println!("{:?} = {:?} * {:?} + {:?}", a, b, q, r);
1760        assert_eq!(a, &b * &q + &r);
1761
1762        let a = 3 * x;
1763        let b = 2 * x;
1764        let (q, r) = Polynomial::quorem(a.ref_set(), b.ref_set()).unwrap();
1765        let (q, r) = (q.into_ergonomic(), r.into_ergonomic());
1766        println!("{:?} = {:?} * {:?} + {:?}", a, b, q, r);
1767        assert_eq!(a, &b * &q + &r);
1768
1769        let a = 3 * x + 5;
1770        let b = 2 * x + 1;
1771        let c = 1 + x + x.pow(2);
1772        let x = &a * &b;
1773        let y = &b * &c;
1774
1775        let g = Polynomial::gcd(x.ref_set(), y.ref_set());
1776
1777        println!("gcd({:?} , {:?}) = {:?}", x, y, g);
1778        Polynomial::try_divide(&g, b.ref_set()).unwrap();
1779        Polynomial::try_divide(b.ref_set(), &g).unwrap();
1780    }
1781
1782    #[test]
1783    fn test_pseudo_remainder() {
1784        let x = &Polynomial::<Integer>::var().into_ergonomic();
1785        {
1786            let f = (x.pow(8) + x.pow(6) - 3 * x.pow(4) - 3 * x.pow(3) + 8 * x.pow(2) + 2 * x - 5)
1787                .into_verbose();
1788            let g = (3 * x.pow(6) + 5 * x.pow(4) - 4 * x.pow(2) - 9 * x + 21).into_verbose();
1789
1790            println!("f = {}", f);
1791            println!("g = {}", g);
1792
1793            let r1 = Polynomial::pseudorem(&f, &g).unwrap().unwrap();
1794            println!("r1 = {}", r1);
1795            assert_eq!(
1796                r1.clone().into_ergonomic(),
1797                -15 * x.pow(4) + 3 * x.pow(2) - 9
1798            );
1799
1800            let r2 = Polynomial::pseudorem(&g, &r1).unwrap().unwrap();
1801            println!("r2 = {}", r2);
1802            assert_eq!(r2.into_ergonomic(), 15795 * x.pow(2) + 30375 * x - 59535);
1803        }
1804        println!();
1805        {
1806            let f = (4 * x.pow(3) + 2 * x - 7).into_verbose();
1807            let g = Polynomial::zero();
1808
1809            println!("f = {}", f);
1810            println!("g = {}", g);
1811
1812            if Polynomial::pseudorem(&f, &g).is_some() {
1813                panic!()
1814            }
1815        }
1816        println!();
1817        {
1818            let f = (3 * x.pow(6) + 5 * x.pow(4) - 4 * x.pow(2) - 9 * x + 21).into_verbose();
1819            let g = (x.pow(8) + x.pow(6) - 3 * x.pow(4) - 3 * x.pow(3) + 8 * x.pow(2) + 2 * x - 5)
1820                .into_verbose();
1821
1822            println!("f = {}", f);
1823            println!("g = {}", g);
1824
1825            if let Err(_msg) = Polynomial::pseudorem(&f, &g).unwrap() {
1826            } else {
1827                panic!();
1828            }
1829        }
1830    }
1831
1832    #[test]
1833    fn integer_primitive_and_assoc() {
1834        let x = &Polynomial::<Integer>::var().into_ergonomic();
1835        let p1 = (-2 - 4 * x.pow(2)).into_verbose();
1836        let (g, p2) = p1.factor_primitive().unwrap();
1837        assert_eq!(g, Integer::from(2));
1838        let (u, p3) = p2.factor_fav_assoc();
1839        assert_eq!(u.coeffs[0], Integer::from(-1));
1840        assert_eq!(p3.into_ergonomic(), 1 + 2 * x.pow(2));
1841    }
1842
1843    #[test]
1844    fn test_evaluate() {
1845        let x = &Polynomial::<Integer>::var().into_ergonomic();
1846        let f = (1 + x + 3 * x.pow(2) + x.pow(3) + 7 * x.pow(4) + x.pow(5)).into_verbose();
1847        assert_eq!(f.evaluate(&Integer::from(3)), Integer::from(868));
1848
1849        let f = Polynomial::zero();
1850        assert_eq!(f.evaluate(&Integer::from(3)), Integer::from(0));
1851    }
1852
1853    #[test]
1854    fn test_interpolate_by_lagrange_basis() {
1855        for points in [
1856            vec![
1857                (Rational::from(-2), Rational::from(-5)),
1858                (Rational::from(7), Rational::from(4)),
1859                (Rational::from(-1), Rational::from(-3)),
1860                (Rational::from(4), Rational::from(1)),
1861            ],
1862            vec![(Rational::from(0), Rational::from(0))],
1863            vec![(Rational::from(0), Rational::from(1))],
1864            vec![],
1865            vec![
1866                (Rational::from(0), Rational::from(0)),
1867                (Rational::from(1), Rational::from(1)),
1868                (Rational::from(2), Rational::from(2)),
1869            ],
1870        ] {
1871            let f = Polynomial::interpolate_by_lagrange_basis(&points).unwrap();
1872            for (inp, out) in &points {
1873                assert_eq!(&f.evaluate(inp), out);
1874            }
1875        }
1876
1877        //f(x)=2x
1878        if let Some(f) = Polynomial::interpolate_by_lagrange_basis(&[
1879            (Integer::from(0), Integer::from(0)),
1880            (Integer::from(1), Integer::from(2)),
1881        ]) {
1882            assert_eq!(
1883                f,
1884                Polynomial::from_coeffs(vec![Integer::from(0), Integer::from(2)])
1885            );
1886        } else {
1887            panic!();
1888        }
1889
1890        //f(x)=1/2x does not have integer coefficients
1891        if let Some(_f) = Polynomial::interpolate_by_lagrange_basis(&[
1892            (Integer::from(0), Integer::from(0)),
1893            (Integer::from(2), Integer::from(1)),
1894        ]) {
1895            panic!();
1896        }
1897    }
1898
1899    #[test]
1900    fn test_interpolate_by_linear_system() {
1901        for points in [
1902            vec![
1903                (Rational::from(-2), Rational::from(-5)),
1904                (Rational::from(7), Rational::from(4)),
1905                (Rational::from(-1), Rational::from(-3)),
1906                (Rational::from(4), Rational::from(1)),
1907            ],
1908            vec![(Rational::from(0), Rational::from(0))],
1909            vec![(Rational::from(0), Rational::from(1))],
1910            vec![],
1911            vec![
1912                (Rational::from(0), Rational::from(0)),
1913                (Rational::from(1), Rational::from(1)),
1914                (Rational::from(2), Rational::from(2)),
1915            ],
1916        ] {
1917            let f = Polynomial::interpolate_by_linear_system(&points).unwrap();
1918            for (inp, out) in &points {
1919                assert_eq!(&f.evaluate(inp), out);
1920            }
1921        }
1922
1923        //f(x)=2x
1924        if let Some(f) = Polynomial::interpolate_by_linear_system(&[
1925            (Integer::from(0), Integer::from(0)),
1926            (Integer::from(1), Integer::from(2)),
1927        ]) {
1928            assert_eq!(
1929                f,
1930                Polynomial::from_coeffs(vec![Integer::from(0), Integer::from(2)])
1931            );
1932        } else {
1933            panic!();
1934        }
1935
1936        //f(x)=1/2x does not have integer coefficients
1937        if let Some(_f) = Polynomial::interpolate_by_linear_system(&[
1938            (Integer::from(0), Integer::from(0)),
1939            (Integer::from(2), Integer::from(1)),
1940        ]) {
1941            panic!();
1942        }
1943    }
1944
1945    #[test]
1946    fn test_derivative() {
1947        let x = &Polynomial::<Integer>::var().into_ergonomic();
1948        let f = (2 + 3 * x - x.pow(2) + 7 * x.pow(3)).into_verbose();
1949        let g = (3 - 2 * x + 21 * x.pow(2)).into_verbose();
1950        assert_eq!(f.derivative(), g);
1951
1952        let f = Polynomial::<Integer>::zero();
1953        let g = Polynomial::<Integer>::zero();
1954        assert_eq!(f.derivative(), g);
1955
1956        let f = Polynomial::<Integer>::one();
1957        let g = Polynomial::<Integer>::zero();
1958        assert_eq!(f.derivative(), g);
1959    }
1960
1961    #[test]
1962    fn test_monic() {
1963        assert!(!Polynomial::<Integer>::zero().is_monic());
1964        assert!(Polynomial::<Integer>::one().is_monic());
1965        let x = &Polynomial::<Integer>::var().into_ergonomic();
1966        let f = (2 + 3 * x - x.pow(2) + 7 * x.pow(3) + x.pow(4)).into_verbose();
1967        let g = (3 - 2 * x + 21 * x.pow(2)).into_verbose();
1968        assert!(f.is_monic());
1969        assert!(!g.is_monic());
1970    }
1971
1972    #[test]
1973    fn test_nat_var() {
1974        let x = Polynomial::<Natural>::var();
1975        println!("{}", x);
1976    }
1977
1978    #[test]
1979    fn test_eval_var_pow() {
1980        let p = Polynomial::<Integer>::from_coeffs(vec![1, 2, 3]);
1981        assert_eq!(p.eval_var_pow(0), Polynomial::from_coeffs(vec![6]));
1982        assert_eq!(p.eval_var_pow(1), Polynomial::from_coeffs(vec![1, 2, 3]));
1983        assert_eq!(
1984            p.eval_var_pow(2),
1985            Polynomial::from_coeffs(vec![1, 0, 2, 0, 3])
1986        );
1987        assert_eq!(
1988            p.eval_var_pow(3),
1989            Polynomial::from_coeffs(vec![1, 0, 0, 2, 0, 0, 3])
1990        );
1991
1992        let p = Polynomial::<Integer>::from_coeffs(vec![4]);
1993        assert_eq!(p.eval_var_pow(0), Polynomial::from_coeffs(vec![4]));
1994        assert_eq!(p.eval_var_pow(1), Polynomial::from_coeffs(vec![4]));
1995        assert_eq!(p.eval_var_pow(2), Polynomial::from_coeffs(vec![4]));
1996
1997        let p = Polynomial::<Integer>::zero();
1998        assert_eq!(p.eval_var_pow(0), Polynomial::zero());
1999        assert_eq!(p.eval_var_pow(1), Polynomial::zero());
2000        assert_eq!(p.eval_var_pow(2), Polynomial::zero());
2001    }
2002
2003    #[test]
2004    fn test_subresultant_gcd() {
2005        let x = &Polynomial::<Integer>::var().into_ergonomic();
2006
2007        let f = (x.pow(8) + x.pow(6) - 3 * x.pow(4) - 3 * x.pow(3) + 8 * x.pow(2) + 2 * x - 5)
2008            .into_verbose();
2009        let g = (3 * x.pow(6) + 5 * x.pow(4) - 4 * x.pow(2) - 9 * x + 21).into_verbose();
2010        assert_eq!(
2011            Polynomial::subresultant_gcd(&f, &g),
2012            Polynomial::constant(Integer::from(260_708))
2013        );
2014
2015        let f = (3 * x.pow(6) + 5 * x.pow(4) - 4 * x.pow(2) - 9 * x + 21).into_verbose();
2016        let g = (x.pow(8) + x.pow(6) - 3 * x.pow(4) - 3 * x.pow(3) + 8 * x.pow(2) + 2 * x - 5)
2017            .into_verbose();
2018        assert_eq!(
2019            Polynomial::subresultant_gcd(&f, &g),
2020            Polynomial::constant(Integer::from(260_708))
2021        );
2022
2023        let f = ((x + 2).pow(2) * (2 * x - 3).pow(2)).into_verbose();
2024        let g = ((3 * x - 1) * (2 * x - 3).pow(2)).into_verbose();
2025        assert_eq!(
2026            Polynomial::subresultant_gcd(&f, &g).into_ergonomic(),
2027            7056 - 9408 * x + 3136 * x.pow(2)
2028        );
2029
2030        let f = (x.pow(4) + 1).into_verbose();
2031        let g = (3 * x.pow(2)).into_verbose();
2032        println!(
2033            "{:#?}",
2034            Polynomial::pseudo_remainder_subresultant_sequence(f.clone(), g.clone())
2035        );
2036        println!("{:#?}", Polynomial::resultant(&f, &g));
2037    }
2038
2039    // #[test]
2040    // fn test_squarefree_part_by_yuns() {
2041    //     let x = &Ergonomic::new(Polynomial::<Integer>::var());
2042    //     let f = ((x + 1).pow(3) * (2 * x + 3).pow(2)).elem();
2043    //     let g = ((x + 1) * (2 * x + 3)).elem();
2044    //     assert_eq!(squarefree_part_by_yuns(&f), g);
2045    // }
2046
2047    #[test]
2048    fn test_discriminant() {
2049        let x = &Polynomial::<Integer>::var().into_ergonomic();
2050        // Constant -> undefined
2051        debug_assert!((0 * x.pow(0)).into_verbose().discriminant().is_err());
2052        debug_assert!((1 * x.pow(0)).into_verbose().discriminant().is_err());
2053        debug_assert!((2 * x.pow(0)).into_verbose().discriminant().is_err());
2054
2055        // Linear f(x) = ax+b -> disc(f) = 1
2056        debug_assert_eq!(
2057            (3 * x.pow(1) + 2).into_verbose().discriminant().unwrap(),
2058            Integer::from(1)
2059        );
2060
2061        // Quadratic f(x) = ax^2 + bx + c  ->  disc(f) = b^2-4ac
2062        debug_assert_eq!(
2063            (x.pow(2) + 1).into_verbose().discriminant().unwrap(),
2064            Integer::from(-4)
2065        );
2066        debug_assert_eq!(
2067            (3 * x.pow(2) + 1).into_verbose().discriminant().unwrap(),
2068            Integer::from(-12)
2069        );
2070        debug_assert_eq!(
2071            (x.pow(2) + 3).into_verbose().discriminant().unwrap(),
2072            Integer::from(-12)
2073        );
2074        debug_assert_eq!(
2075            (3 * x.pow(2) + 3).into_verbose().discriminant().unwrap(),
2076            Integer::from(-36)
2077        );
2078        debug_assert_eq!(
2079            (x.pow(2) + x.pow(1) + 1)
2080                .into_verbose()
2081                .discriminant()
2082                .unwrap(),
2083            Integer::from(1 - 4)
2084        );
2085        debug_assert_eq!(
2086            (x.pow(2) + 2 * x.pow(1) + 1)
2087                .into_verbose()
2088                .discriminant()
2089                .unwrap(),
2090            Integer::from(4 - 4)
2091        );
2092        debug_assert_eq!(
2093            (x.pow(2) + 3 * x.pow(1) + 1)
2094                .into_verbose()
2095                .discriminant()
2096                .unwrap(),
2097            Integer::from(9 - 4)
2098        );
2099
2100        //Cubic f(x) = ax^3 + bx^2 + cx + d  ->  disc(f) = b^2c^2 - 4ac^3 - 4b^3d - 27a^2d^2 + 18abcd
2101        for (a, b, c, d) in [
2102            (1, 0, 0, 0),
2103            (1, 0, 1, 0),
2104            (1, 0, 0, 1),
2105            (1, 1, 1, 1),
2106            (3, 1, 1, 1),
2107            (3, 3, 3, 3),
2108            (2, 3, 5, 7),
2109            (7, 5, 3, 2),
2110        ] {
2111            println!(
2112                "{}",
2113                (a * x.pow(3) + b * x.pow(2) + c * x.pow(1) + d).into_verbose()
2114            );
2115            println!(
2116                "{:?}",
2117                (a * x.pow(3) + b * x.pow(2) + c * x.pow(1) + d)
2118                    .into_verbose()
2119                    .discriminant()
2120            );
2121            debug_assert_eq!(
2122                (a * x.pow(3) + b * x.pow(2) + c * x.pow(1) + d)
2123                    .into_verbose()
2124                    .discriminant()
2125                    .unwrap(),
2126                Integer::from(
2127                    b * b * c * c - 4 * a * c * c * c - 4 * b * b * b * d - 27 * a * a * d * d
2128                        + 18 * a * b * c * d
2129                )
2130            );
2131        }
2132    }
2133
2134    #[test]
2135    fn test_factor_primitive_fof() {
2136        for (f, exp) in [
2137            (
2138                Polynomial::from_coeffs(vec![
2139                    Rational::from_integers(1, 2),
2140                    Rational::from_integers(1, 3),
2141                ]),
2142                Polynomial::from_coeffs(vec![Integer::from(3), Integer::from(2)]),
2143            ),
2144            (
2145                Polynomial::from_coeffs(vec![
2146                    Rational::from_integers(4, 1),
2147                    Rational::from_integers(6, 1),
2148                ]),
2149                Polynomial::from_coeffs(vec![Integer::from(2), Integer::from(3)]),
2150            ),
2151        ] {
2152            let (mul, ans) = f.factor_primitive_fof();
2153            assert!(Polynomial::are_associate(&ans, &exp));
2154            assert_eq!(
2155                Polynomial::mul(
2156                    &ans.apply_map(|c| Rational::from(c)),
2157                    &Polynomial::constant(mul)
2158                ),
2159                f
2160            );
2161        }
2162    }
2163}