algebraeon_rings/isolated_algebraic/complex/
mod.rs

1use super::bisection_gen::RationalSimpleBetweenGenerator;
2use super::poly_tools::*;
3use super::real::RealAlgebraic;
4use crate::polynomial::*;
5use crate::structure::*;
6use algebraeon_nzq::*;
7use algebraeon_sets::structure::*;
8use boxes::*;
9use std::{collections::HashSet, fmt::Display, str::FromStr};
10mod boxes;
11mod polynomial;
12
13fn bisect_box(
14    poly: &Polynomial<Integer>,
15    n: usize,
16    a: &Rational,
17    b: &Rational,
18    c: &Rational,
19    d: &Rational,
20) -> (
21    (usize, Rational, Rational, Rational, Rational),
22    (usize, Rational, Rational, Rational, Rational),
23) {
24    let ba = b - a;
25    let dc = d - c;
26    if ba >= dc {
27        //bisect (a, b)
28        for m in RationalSimpleBetweenGenerator::new_between_middle(
29            a,
30            b,
31            &Rational::from_integers(Integer::from(1), Integer::from(3)),
32        ) {
33            #[allow(clippy::single_match)]
34            match (
35                poly.count_complex_roots(a, &m, c, d),
36                poly.count_complex_roots(&m, b, c, d),
37            ) {
38                (Some(n1), Some(n2)) => {
39                    debug_assert_eq!(n1 + n2, n);
40                    return (
41                        (n1, a.clone(), m.clone(), c.clone(), d.clone()),
42                        (n2, m, b.clone(), c.clone(), d.clone()),
43                    );
44                }
45                _ => {}
46            }
47        }
48    } else {
49        //bisect (c, d)
50        for m in RationalSimpleBetweenGenerator::new_between_middle(
51            c,
52            d,
53            &Rational::from_integers(Integer::from(1), Integer::from(3)),
54        ) {
55            #[allow(clippy::single_match)]
56            match (
57                poly.count_complex_roots(a, b, c, &m),
58                poly.count_complex_roots(a, b, &m, d),
59            ) {
60                (Some(n1), Some(n2)) => {
61                    debug_assert_eq!(n1 + n2, n);
62                    return (
63                        (n1, a.clone(), b.clone(), c.clone(), m.clone()),
64                        (n2, a.clone(), b.clone(), m, d.clone()),
65                    );
66                }
67                _ => {}
68            }
69        }
70    }
71    unreachable!()
72}
73
74//box gen must yield boxes which converge to some root of the polynomial
75fn identify_complex_root(
76    poly: Polynomial<Integer>,
77    mut box_gen: impl Iterator<Item = (Rational, Rational, Rational, Rational)>,
78) -> ComplexAlgebraic {
79    let poly = poly.primitive_squarefree_part();
80    //find the irreducible factor poly which contains the root being converged to
81    let (mut a, mut b, mut c, mut d) = box_gen.next().unwrap();
82
83    let irr_poly = {
84        let (_unit, factors) = poly.factor().into_unit_and_powers().unwrap();
85        let irr_polys = factors.into_iter().map(|(f, _k)| f).collect::<Vec<_>>();
86        let mut possible_irr_poly_idxs: HashSet<_> = (0..irr_polys.len()).collect();
87        loop {
88            debug_assert!(!possible_irr_poly_idxs.is_empty());
89            possible_irr_poly_idxs
90                .retain(|idx| irr_polys[*idx].count_complex_roots(&a, &b, &c, &d) != Some(0));
91            if possible_irr_poly_idxs.len() == 1 {
92                break;
93            }
94            (a, b, c, d) = box_gen.next().unwrap();
95        }
96        debug_assert_eq!(possible_irr_poly_idxs.len(), 1);
97        irr_polys
98            .into_iter()
99            .nth(possible_irr_poly_idxs.into_iter().next().unwrap())
100            .unwrap()
101    };
102
103    let mut roots = irr_poly.all_complex_roots_irreducible();
104    let mut possible_roots: HashSet<_> = (0..roots.len()).collect();
105    loop {
106        debug_assert!(!possible_roots.is_empty());
107        possible_roots.retain(|idx| match &roots[*idx] {
108            ComplexAlgebraic::Real(RealAlgebraic::Rational(root)) => {
109                &a < root && root < &b && c < Rational::ZERO && Rational::ZERO < d
110            }
111            ComplexAlgebraic::Real(RealAlgebraic::Real(root)) => {
112                &a < root.tight_b()
113                    && root.tight_a() < &b
114                    && c < Rational::ZERO
115                    && Rational::ZERO < d
116            }
117            ComplexAlgebraic::Complex(root) => {
118                a < root.tight_b && root.tight_a < b && c < root.tight_d && root.tight_c < d
119            }
120        });
121        if possible_roots.len() == 1 {
122            break;
123        }
124        (a, b, c, d) = box_gen.next().unwrap();
125        for idx in &possible_roots {
126            match &mut roots[*idx] {
127                ComplexAlgebraic::Real(RealAlgebraic::Rational(_root)) => {}
128                ComplexAlgebraic::Real(RealAlgebraic::Real(root)) => {
129                    root.refine();
130                }
131                ComplexAlgebraic::Complex(root) => {
132                    root.refine();
133                }
134            }
135        }
136    }
137    debug_assert_eq!(possible_roots.len(), 1);
138    let ans = roots
139        .into_iter()
140        .nth(possible_roots.into_iter().next().unwrap())
141        .unwrap();
142    #[cfg(debug_assertions)]
143    ans.check_invariants().unwrap();
144    ans
145}
146
147#[derive(Debug, Clone)]
148pub struct ComplexAlgebraicRoot {
149    tight_a: Rational, //tight lower bound for the real part
150    tight_b: Rational, //tight upper bound for the real part
151    tight_c: Rational, //tight lower bound for the imaginary part
152    tight_d: Rational, //tight upper bound for the imaginary part
153
154    poly: Polynomial<Integer>, //a primitive irreducible polynomial of degree >= 2 with a unique non-real complex root in the box defined by (a, b, c, d)
155}
156
157impl Display for ComplexAlgebraicRoot {
158    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
159        if self.poly.num_coeffs() == 3 {
160            //quadratic
161            let a = self.poly.coeff(2);
162            let b = self.poly.coeff(1);
163            let c = self.poly.coeff(0);
164            debug_assert!(a.as_ref() > &Integer::ZERO);
165
166            let d = b.as_ref() * b.as_ref() - Integer::from(4) * a.as_ref() * c.as_ref();
167            let mut d_sq = Integer::ONE;
168            let mut d_sqfreee = Integer::ONE;
169            let (d_sign, d_factors) = d.factor().into_unit_and_powers().unwrap();
170            for (d_factor, k) in d_factors {
171                d_sq *= d_factor.nat_pow(&(&k / Natural::TWO));
172                if k % Natural::TWO == Natural::ONE {
173                    d_sqfreee *= d_factor;
174                }
175            }
176            debug_assert_eq!(d_sign, -Integer::ONE); //because we are a real number
177            debug_assert_eq!(-d, &d_sqfreee * &d_sq * &d_sq);
178
179            let two_a = Integer::TWO * a.as_ref();
180
181            let x = Rational::from_integers(-b.as_ref(), two_a.clone());
182            let y = Rational::from_integers(d_sq, two_a);
183            debug_assert!(y > Rational::ZERO);
184            let r = d_sqfreee;
185            let r_str = {
186                if r == Integer::ONE {
187                    String::from("i")
188                } else {
189                    String::from("i√") + &r.to_string()
190                }
191            };
192
193            let mut tight_c_abs = self.tight_c.clone();
194            if tight_c_abs < Rational::ZERO {
195                tight_c_abs = -tight_c_abs;
196            }
197
198            let mut tight_d_abs = self.tight_d.clone();
199            if tight_d_abs < Rational::ZERO {
200                tight_d_abs = -tight_d_abs;
201            }
202
203            let sign = tight_c_abs < tight_d_abs;
204            match (x, y) {
205                (Rational::ZERO, Rational::ONE) => {
206                    write!(f, "{}{}", if sign { "" } else { "-" }, r_str)?;
207                }
208                (Rational::ZERO, y) => {
209                    write!(f, "{}{}{}", if sign { "" } else { "-" }, y, r_str)?;
210                }
211                (x, Rational::ONE) => {
212                    write!(f, "{}{}{}", x, if sign { "+" } else { "-" }, r_str)?;
213                }
214                (x, y) => {
215                    write!(f, "{}{}{}{}", x, if sign { "+" } else { "-" }, y, r_str)?;
216                }
217            }
218        } else {
219            let mut root = self.clone();
220            root.refine_to_accuracy(&Rational::from_integers(
221                Integer::from(1),
222                Integer::from(100),
223            ));
224
225            let m_re = (&root.tight_a + &root.tight_b) / Rational::TWO;
226            let m_im = (&root.tight_c + &root.tight_d) / Rational::TWO;
227
228            write!(f, "≈")?;
229            write!(f, "{}", m_re.decimal_string_approx())?;
230            // write!(f, "±");
231            // write!(f, "{}", decimal_string_approx(self.accuracy_re() / Rational::TWO));
232            if m_im >= Rational::ZERO {
233                write!(f, "+")?;
234            }
235            write!(f, "{}", m_im.decimal_string_approx())?;
236            // write!(f, "±");
237            // write!(f, "{}", decimal_string_approx(self.accuracy_im() / Rational::TWO));
238            write!(f, "i")?;
239        }
240        Ok(())
241    }
242}
243
244impl ComplexAlgebraicRoot {
245    pub fn check_invariants(&self) -> Result<(), &'static str> {
246        if self.tight_a >= self.tight_b {
247            return Err("tight a should be strictly less than b");
248        }
249        if self.tight_c >= self.tight_d {
250            return Err("tight c should be strictly less than d");
251        }
252        // if !(self.wide_a < self.wide_b) {
253        //     return Err("wide a should be strictly less than b");
254        // }
255        // if !(self.wide_c < self.wide_d) {
256        //     return Err("wide c should be strictly less than d");
257        // }
258
259        if !self.poly.is_irreducible() {
260            return Err("Isolated complex root minimal polynomial should be irreducible");
261        }
262
263        if self.poly.degree().unwrap() < 2 {
264            return Err("Isolated complex root minimal polynomial should have degree at least 2");
265        }
266
267        match self.poly.count_complex_roots(
268            &self.tight_a,
269            &self.tight_b,
270            &self.tight_c,
271            &self.tight_d,
272        ) {
273            Some(1) => {}
274            Some(_) => {
275                return Err("Isolated complex root must exactly 1 root with none on the boundary");
276            }
277            None => {
278                return Err(
279                    "Isolated complex root must contain exactly 1 root with none on the boundary",
280                );
281            }
282        }
283
284        let real_roots_in_box = if self.tight_c < Rational::ZERO && Rational::ZERO < self.tight_d {
285            self.poly
286                .all_real_roots()
287                .into_iter()
288                .filter(|x| {
289                    &RealAlgebraic::Rational(self.tight_a.clone()) < x
290                        && x < &RealAlgebraic::Rational(self.tight_b.clone())
291                })
292                .collect::<Vec<_>>()
293        } else {
294            vec![]
295        };
296        if !real_roots_in_box.is_empty() {
297            return Err("Isolated complex root must not be a real root");
298        }
299
300        Ok(())
301    }
302
303    pub fn accuracy_re(&self) -> Rational {
304        &self.tight_b - &self.tight_a
305    }
306
307    pub fn accuracy_im(&self) -> Rational {
308        &self.tight_d - &self.tight_c
309    }
310
311    fn conj(mut self) -> Self {
312        (self.tight_c, self.tight_d) = (-self.tight_d, -self.tight_c);
313        self
314    }
315
316    pub fn neg_mut(&mut self) {
317        self.poly = Polynomial::compose(
318            &self.poly,
319            &Polynomial::from_coeffs(vec![Integer::from(0), Integer::from(-1)]),
320        )
321        .fav_assoc();
322        (self.tight_a, self.tight_b) = (-self.tight_b.clone(), -self.tight_a.clone());
323        (self.tight_c, self.tight_d) = (-self.tight_d.clone(), -self.tight_c.clone());
324    }
325
326    #[allow(clippy::should_implement_trait)]
327    pub fn neg(mut self) -> Self {
328        self.neg_mut();
329        self
330    }
331
332    pub fn refine(&mut self) {
333        let ((n1, a1, b1, c1, d1), (n2, a2, b2, c2, d2)) = bisect_box(
334            &self.poly,
335            1,
336            &self.tight_a,
337            &self.tight_b,
338            &self.tight_c,
339            &self.tight_d,
340        );
341
342        match (n1, n2) {
343            (1, 0) => {
344                self.tight_a = a1;
345                self.tight_b = b1;
346                self.tight_c = c1;
347                self.tight_d = d1;
348            }
349            (0, 1) => {
350                self.tight_a = a2;
351                self.tight_b = b2;
352                self.tight_c = c2;
353                self.tight_d = d2;
354            }
355            _ => {
356                unreachable!();
357            }
358        }
359
360        #[cfg(debug_assertions)]
361        self.check_invariants().unwrap();
362    }
363
364    pub fn refine_to_accuracy(&mut self, accuracy: &Rational) {
365        while &self.accuracy_re() > accuracy || &self.accuracy_im() > accuracy {
366            self.refine();
367        }
368    }
369
370    pub fn equal(&self, other: &Self) -> bool {
371        let poly = &self.poly;
372        //polys should be irreducible primitive fav-assoc so this is valid
373        if poly == &other.poly {
374            //find the overlap of the two isolating boxes
375
376            /*
377                There are only two possibilities:
378                 - A and C contain a root and B is empty, so self != other
379                 - B contains a root and both A and C are empty, so self == other
380
381                          +----------------+
382                          |                |
383                          |           C    |
384                +---------+--------+       |
385                |         |   B    |       |
386                |         +--------+-------+
387                |   A              |
388                |                  |
389                +------------------+
390
391            */
392
393            //is there any overlap at all?
394            if self.tight_a < other.tight_b
395                && other.tight_a < self.tight_b
396                && self.tight_c < other.tight_d
397                && other.tight_c < self.tight_d
398            {
399                let overlap_a = std::cmp::max(&self.tight_a, &other.tight_a);
400                let overlap_b = std::cmp::min(&self.tight_b, &other.tight_b);
401                let overlap_c = std::cmp::max(&self.tight_c, &other.tight_c);
402                let overlap_d = std::cmp::min(&self.tight_d, &other.tight_d);
403
404                let n = poly
405                    .count_complex_roots(overlap_a, overlap_b, overlap_c, overlap_d)
406                    .unwrap();
407
408                return match n {
409                    0 => false,
410                    1 => true,
411                    _ => panic!(),
412                };
413            }
414        }
415        false
416    }
417
418    pub fn apply_poly(&mut self, poly: &Polynomial<Rational>) -> ComplexAlgebraic {
419        let poly = Polynomial::rem(poly, &self.min_poly());
420        if let Some(rat) = poly.as_constant() {
421            ComplexAlgebraic::Real(RealAlgebraic::Rational(rat))
422        } else {
423            let ans_poly = self
424                .min_poly()
425                .algebraic_number_field_unchecked()
426                .min_poly(&poly)
427                .primitive_part_fof();
428
429            identify_complex_root(
430                ans_poly,
431                (0..).map(|i| {
432                    if i != 0 {
433                        self.refine();
434                    }
435
436                    // eg: c + bx + ax^2 = c + x(b + x(a))
437                    let mut coeffs = poly.coeffs().collect::<Vec<_>>().into_iter().rev();
438                    let lc = coeffs.next().unwrap();
439                    let mut ans = mul_box_rat(
440                        (&self.tight_a, &self.tight_b, &self.tight_c, &self.tight_d),
441                        lc,
442                    );
443                    for (i, c) in coeffs.enumerate() {
444                        if i != 0 {
445                            ans = mul_boxes(
446                                (&ans.0, &ans.1, &ans.2, &ans.3),
447                                (&self.tight_a, &self.tight_b, &self.tight_c, &self.tight_d),
448                            );
449                        }
450                        ans = add_box_rat((&ans.0, &ans.1, &ans.2, &ans.3), c);
451                    }
452
453                    ans
454                }),
455            )
456        }
457    }
458
459    pub fn min_poly(&self) -> Polynomial<Rational> {
460        self.poly.apply_map(|c| Rational::from(c)).fav_assoc()
461    }
462}
463
464#[derive(Debug, Clone, CanonicalStructure)]
465#[canonical_structure(eq)]
466pub enum ComplexAlgebraic {
467    Real(RealAlgebraic),
468    Complex(ComplexAlgebraicRoot),
469}
470
471impl From<RealAlgebraic> for ComplexAlgebraic {
472    fn from(value: RealAlgebraic) -> Self {
473        Self::Real(value)
474    }
475}
476
477impl TryFrom<ComplexAlgebraic> for RealAlgebraic {
478    type Error = ();
479
480    fn try_from(value: ComplexAlgebraic) -> Result<Self, Self::Error> {
481        match value {
482            ComplexAlgebraic::Real(real_algebraic) => Ok(real_algebraic),
483            ComplexAlgebraic::Complex(_) => Err(()),
484        }
485    }
486}
487
488impl ComplexAlgebraic {
489    pub fn i() -> Self {
490        let i = ComplexAlgebraic::Complex(ComplexAlgebraicRoot {
491            tight_a: Rational::from_integers(Integer::from(-1), Integer::from(1)),
492            tight_b: Rational::from_integers(Integer::from(1), Integer::from(1)),
493            tight_c: Rational::from_integers(Integer::from(0), Integer::from(1)),
494            tight_d: Rational::from_integers(Integer::from(2), Integer::from(1)),
495            poly: Polynomial::from_coeffs(vec![Integer::ONE, Integer::ZERO, Integer::ONE]),
496        });
497        #[cfg(debug_assertions)]
498        i.check_invariants().unwrap();
499        i
500    }
501}
502
503impl ComplexAlgebraic {
504    pub fn check_invariants(&self) -> Result<(), &'static str> {
505        match self {
506            ComplexAlgebraic::Real(x) => match x.check_invariants() {
507                Ok(()) => {}
508                Err(e) => {
509                    return Err(e);
510                }
511            },
512            ComplexAlgebraic::Complex(x) => match x.check_invariants() {
513                Ok(()) => {}
514                Err(e) => {
515                    return Err(e);
516                }
517            },
518        }
519        Ok(())
520    }
521
522    pub fn eq_mut(&mut self, other: &mut Self) -> bool {
523        match (self, other) {
524            (ComplexAlgebraic::Real(a), ComplexAlgebraic::Real(b)) => {
525                RealAlgebraic::cmp_mut(a, b).is_eq()
526            }
527            (ComplexAlgebraic::Real(_a), ComplexAlgebraic::Complex(_b)) => false,
528            (ComplexAlgebraic::Complex(_a), ComplexAlgebraic::Real(_b)) => false,
529            (ComplexAlgebraic::Complex(a), ComplexAlgebraic::Complex(b)) => a.equal(b),
530        }
531    }
532
533    pub fn apply_poly(&mut self, poly: &Polynomial<Rational>) -> Self {
534        match self {
535            ComplexAlgebraic::Real(reat_alg) => ComplexAlgebraic::Real(reat_alg.apply_poly(poly)),
536            ComplexAlgebraic::Complex(cpx_root) => cpx_root.apply_poly(poly),
537        }
538    }
539
540    pub fn degree(&self) -> usize {
541        self.min_poly().degree().unwrap()
542    }
543
544    pub fn real_part(&self) -> RealAlgebraic {
545        ComplexAlgebraic::structure()
546            .mul(
547                &ComplexAlgebraic::structure().add(self, &self.conjugate()),
548                &Self::Real(RealAlgebraic::Rational(Rational::ONE_HALF)),
549            )
550            .try_into()
551            .unwrap()
552    }
553
554    pub fn imag_part(&self) -> RealAlgebraic {
555        ComplexAlgebraic::structure()
556            .mul(
557                &ComplexAlgebraic::structure().sub(self, &self.conjugate()),
558                &ComplexAlgebraic::structure().mul(
559                    &Self::i(),
560                    &Self::Real(RealAlgebraic::Rational(-Rational::ONE_HALF)),
561                ),
562            )
563            .try_into()
564            .unwrap()
565    }
566}
567
568pub enum ComplexIsolatingRegion<'a> {
569    Rational(&'a Rational),
570    RealInterval(&'a Rational, &'a Rational),
571    Box(&'a Rational, &'a Rational, &'a Rational, &'a Rational),
572}
573
574impl ComplexAlgebraic {
575    pub fn refine(&mut self) {
576        match self {
577            ComplexAlgebraic::Real(x) => x.refine(),
578            ComplexAlgebraic::Complex(z) => z.refine(),
579        }
580    }
581
582    pub fn isolate<'a>(&'a self) -> ComplexIsolatingRegion<'a> {
583        match self {
584            ComplexAlgebraic::Real(x) => match x.isolate() {
585                crate::isolated_algebraic::RealIsolatingRegion::Rational(r) => {
586                    ComplexIsolatingRegion::Rational(r)
587                }
588                crate::isolated_algebraic::RealIsolatingRegion::Interval(a, b) => {
589                    ComplexIsolatingRegion::RealInterval(a, b)
590                }
591            },
592            ComplexAlgebraic::Complex(z) => {
593                ComplexIsolatingRegion::Box(&z.tight_a, &z.tight_b, &z.tight_c, &z.tight_d)
594            }
595        }
596    }
597}
598
599impl PartialEq for ComplexAlgebraic {
600    fn eq(&self, other: &Self) -> bool {
601        Self::eq_mut(&mut self.clone(), &mut other.clone())
602    }
603}
604
605impl Eq for ComplexAlgebraic {}
606
607impl Display for ComplexAlgebraic {
608    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
609        match self {
610            ComplexAlgebraic::Real(a) => write!(f, "{}", a),
611            ComplexAlgebraic::Complex(a) => write!(f, "{}", a),
612        }
613    }
614}
615
616impl ToStringSignature for ComplexAlgebraicCanonicalStructure {
617    fn to_string(&self, elem: &Self::Set) -> String {
618        format!("{}", elem)
619    }
620}
621
622impl RinglikeSpecializationSignature for ComplexAlgebraicCanonicalStructure {
623    fn try_ring_restructure(&self) -> Option<impl EqSignature<Set = Self::Set> + RingSignature> {
624        Some(self.clone())
625    }
626
627    fn try_char_zero_ring_restructure(
628        &self,
629    ) -> Option<impl EqSignature<Set = Self::Set> + CharZeroRingSignature> {
630        Some(self.clone())
631    }
632}
633
634impl ZeroSignature for ComplexAlgebraicCanonicalStructure {
635    fn zero(&self) -> Self::Set {
636        ComplexAlgebraic::Real(RealAlgebraic::Rational(Rational::zero()))
637    }
638}
639
640impl AdditionSignature for ComplexAlgebraicCanonicalStructure {
641    fn add(&self, alg1: &Self::Set, alg2: &Self::Set) -> Self::Set {
642        // println!("add {:?} {:?}", alg1, alg2);
643        // alg1.check_invariants().unwrap();
644        // alg2.check_invariants().unwrap();
645
646        fn add_real(mut cpx: ComplexAlgebraicRoot, real: RealAlgebraic) -> ComplexAlgebraic {
647            match real {
648                RealAlgebraic::Rational(rat) => {
649                    cpx.tight_a += &rat;
650                    cpx.tight_b += &rat;
651                    //compose with x - n/d = dx - n
652                    cpx.poly = Polynomial::compose(
653                        &cpx.poly.apply_map(|c| Rational::from(c)),
654                        &Polynomial::from_coeffs(vec![-rat, Rational::ONE]),
655                    )
656                    .primitive_part_fof();
657
658                    let cpx = ComplexAlgebraic::Complex(cpx);
659
660                    #[cfg(debug_assertions)]
661                    cpx.check_invariants().unwrap();
662                    cpx
663                }
664                RealAlgebraic::Real(mut real) => identify_complex_root(
665                    root_sum_poly(&cpx.poly, real.poly()),
666                    (0..).map(|i| {
667                        if i != 0 {
668                            cpx.refine();
669                            real.refine();
670                        }
671                        let ans_tight_a = &cpx.tight_a + real.tight_a();
672                        let ans_tight_b = &cpx.tight_b + real.tight_b();
673                        let ans_tight_c = cpx.tight_c.clone();
674                        let ans_tight_d = cpx.tight_d.clone();
675                        (ans_tight_a, ans_tight_b, ans_tight_c, ans_tight_d)
676                    }),
677                ),
678            }
679        }
680
681        match (alg1, alg2) {
682            (ComplexAlgebraic::Real(real1), ComplexAlgebraic::Real(real2)) => {
683                ComplexAlgebraic::Real(RealAlgebraic::add(real1, real2))
684            }
685            (ComplexAlgebraic::Real(real1), ComplexAlgebraic::Complex(cpx2)) => {
686                add_real(cpx2.clone(), real1.clone())
687            }
688            (ComplexAlgebraic::Complex(cpx1), ComplexAlgebraic::Real(real2)) => {
689                add_real(cpx1.clone(), real2.clone())
690            }
691            (ComplexAlgebraic::Complex(cpx1), ComplexAlgebraic::Complex(cpx2)) => {
692                let mut cpx1 = cpx1.clone();
693                let mut cpx2 = cpx2.clone();
694
695                identify_complex_root(
696                    root_sum_poly(&cpx1.poly, &cpx2.poly),
697                    (0..).map(|i| {
698                        if i != 0 {
699                            cpx1.refine();
700                            cpx2.refine();
701                        }
702                        add_boxes(
703                            (&cpx1.tight_a, &cpx1.tight_b, &cpx1.tight_c, &cpx1.tight_d),
704                            (&cpx2.tight_a, &cpx2.tight_b, &cpx2.tight_c, &cpx2.tight_d),
705                        )
706                    }),
707                )
708            }
709        }
710    }
711}
712
713impl CancellativeAdditionSignature for ComplexAlgebraicCanonicalStructure {
714    fn try_sub(&self, a: &Self::Set, b: &Self::Set) -> Option<Self::Set> {
715        Some(self.sub(a, b))
716    }
717}
718
719impl TryNegateSignature for ComplexAlgebraicCanonicalStructure {
720    fn try_neg(&self, a: &Self::Set) -> Option<Self::Set> {
721        Some(self.neg(a))
722    }
723}
724
725impl AdditiveMonoidSignature for ComplexAlgebraicCanonicalStructure {}
726
727impl AdditiveGroupSignature for ComplexAlgebraicCanonicalStructure {
728    fn neg(&self, a: &Self::Set) -> Self::Set {
729        match a {
730            ComplexAlgebraic::Real(root) => ComplexAlgebraic::Real(RealAlgebraic::neg(root)),
731            ComplexAlgebraic::Complex(root) => ComplexAlgebraic::Complex(root.clone().neg()),
732        }
733    }
734}
735
736impl OneSignature for ComplexAlgebraicCanonicalStructure {
737    fn one(&self) -> Self::Set {
738        ComplexAlgebraic::Real(RealAlgebraic::Rational(Rational::one()))
739    }
740}
741
742impl MultiplicationSignature for ComplexAlgebraicCanonicalStructure {
743    fn mul(&self, alg1: &Self::Set, alg2: &Self::Set) -> Self::Set {
744        // println!("mul {:?} {:?}", alg1, alg2);
745        // alg1.check_invariants().unwrap();
746        // alg2.check_invariants().unwrap();
747
748        fn mul_real(mut cpx: ComplexAlgebraicRoot, real: RealAlgebraic) -> ComplexAlgebraic {
749            match real {
750                RealAlgebraic::Rational(rat) => match rat.cmp(&Rational::ZERO) {
751                    std::cmp::Ordering::Equal => ComplexAlgebraic::zero(),
752                    std::cmp::Ordering::Less => mul_real(cpx.neg(), RealAlgebraic::Rational(-rat)),
753                    std::cmp::Ordering::Greater => {
754                        debug_assert!(rat > Rational::ZERO);
755                        cpx.tight_a *= &rat;
756                        cpx.tight_b *= &rat;
757                        cpx.tight_c *= &rat;
758                        cpx.tight_d *= &rat;
759                        cpx.poly = root_rat_mul_poly(cpx.poly, &rat);
760                        #[cfg(debug_assertions)]
761                        assert!(cpx.check_invariants().is_ok());
762                        ComplexAlgebraic::Complex(cpx)
763                    }
764                },
765                RealAlgebraic::Real(mut real) => {
766                    identify_complex_root(
767                        root_product_poly(&cpx.poly, real.poly()),
768                        (0..).map(|i| {
769                            if i != 0 {
770                                cpx.refine();
771                                real.refine();
772                            }
773
774                            let mut pts_re = vec![];
775                            let mut pts_im = vec![];
776                            for (re, im) in [
777                                (&cpx.tight_a, &cpx.tight_c),
778                                (&cpx.tight_a, &cpx.tight_d),
779                                (&cpx.tight_b, &cpx.tight_c),
780                                (&cpx.tight_b, &cpx.tight_d),
781                            ] {
782                                for t in [real.tight_a(), real.tight_b()] {
783                                    pts_re.push(t * re);
784                                    pts_im.push(t * im);
785                                }
786                            }
787
788                            let ans_tight_a = pts_re.iter().min().unwrap().clone();
789                            let ans_tight_b = pts_re.into_iter().max().unwrap();
790                            let ans_tight_c = pts_im.iter().min().unwrap().clone();
791                            let ans_tight_d = pts_im.into_iter().max().unwrap();
792
793                            //allow the bounds to expand a little bit so that the bounds are simpler
794                            let diff_re = &ans_tight_b - &ans_tight_a;
795                            let diff_im = &ans_tight_d - &ans_tight_c;
796                            let ans_tight_a = Rational::simplest_rational_in_closed_interval(
797                                &(&ans_tight_a - (&diff_re * Rational::from_str("1/10").unwrap())),
798                                &ans_tight_a,
799                            );
800                            let ans_tight_b = Rational::simplest_rational_in_closed_interval(
801                                &ans_tight_b,
802                                &(&ans_tight_b + (&diff_re * Rational::from_str("1/10").unwrap())),
803                            );
804                            let ans_tight_c = Rational::simplest_rational_in_closed_interval(
805                                &(&ans_tight_c - (&diff_im * Rational::from_str("1/10").unwrap())),
806                                &ans_tight_c,
807                            );
808                            let ans_tight_d = Rational::simplest_rational_in_closed_interval(
809                                &ans_tight_d,
810                                &(&ans_tight_d + (&diff_im * Rational::from_str("1/10").unwrap())),
811                            );
812                            (ans_tight_a, ans_tight_b, ans_tight_c, ans_tight_d)
813                        }),
814                    )
815                }
816            }
817        }
818
819        match (alg1, alg2) {
820            (ComplexAlgebraic::Real(real1), ComplexAlgebraic::Real(real2)) => {
821                ComplexAlgebraic::Real(RealAlgebraic::mul(real1, real2))
822            }
823            (ComplexAlgebraic::Real(real1), ComplexAlgebraic::Complex(cpx2)) => {
824                mul_real(cpx2.clone(), real1.clone())
825            }
826            (ComplexAlgebraic::Complex(cpx1), ComplexAlgebraic::Real(real2)) => {
827                mul_real(cpx1.clone(), real2.clone())
828            }
829            (ComplexAlgebraic::Complex(cpx1), ComplexAlgebraic::Complex(cpx2)) => {
830                let mut cpx1 = cpx1.clone();
831                let mut cpx2 = cpx2.clone();
832
833                identify_complex_root(
834                    root_product_poly(&cpx1.poly, &cpx2.poly),
835                    (0..).map(|i| {
836                        if i != 0 {
837                            cpx1.refine();
838                            cpx2.refine();
839                        }
840
841                        let (ans_tight_a, ans_tight_b, ans_tight_c, ans_tight_d) = mul_boxes(
842                            (&cpx1.tight_a, &cpx1.tight_b, &cpx1.tight_c, &cpx1.tight_d),
843                            (&cpx2.tight_a, &cpx2.tight_b, &cpx2.tight_c, &cpx2.tight_d),
844                        );
845
846                        //allow the bounds to expand a little bit so that the bounds are simpler
847                        let diff_re = &ans_tight_b - &ans_tight_a;
848                        let diff_im = &ans_tight_d - &ans_tight_c;
849                        let ans_tight_a = Rational::simplest_rational_in_closed_interval(
850                            &(&ans_tight_a - (&diff_re * Rational::from_str("1/10").unwrap())),
851                            &ans_tight_a,
852                        );
853                        let ans_tight_b = Rational::simplest_rational_in_closed_interval(
854                            &ans_tight_b,
855                            &(&ans_tight_b + (&diff_re * Rational::from_str("1/10").unwrap())),
856                        );
857                        let ans_tight_c = Rational::simplest_rational_in_closed_interval(
858                            &(&ans_tight_c - (&diff_im * Rational::from_str("1/10").unwrap())),
859                            &ans_tight_c,
860                        );
861                        let ans_tight_d = Rational::simplest_rational_in_closed_interval(
862                            &ans_tight_d,
863                            &(&ans_tight_d + (&diff_im * Rational::from_str("1/10").unwrap())),
864                        );
865
866                        (ans_tight_a, ans_tight_b, ans_tight_c, ans_tight_d)
867                    }),
868                )
869            }
870        }
871    }
872}
873
874impl CommutativeMultiplicationSignature for ComplexAlgebraicCanonicalStructure {}
875
876impl MultiplicativeMonoidSignature for ComplexAlgebraicCanonicalStructure {}
877
878impl MultiplicativeAbsorptionMonoidSignature for ComplexAlgebraicCanonicalStructure {}
879
880impl LeftDistributiveMultiplicationOverAddition for ComplexAlgebraicCanonicalStructure {}
881
882impl RightDistributiveMultiplicationOverAddition for ComplexAlgebraicCanonicalStructure {}
883
884impl SemiRingSignature for ComplexAlgebraicCanonicalStructure {}
885
886impl RingSignature for ComplexAlgebraicCanonicalStructure {
887    fn is_reduced(&self) -> Result<bool, String> {
888        Ok(true)
889    }
890}
891
892impl CharacteristicSignature for ComplexAlgebraicCanonicalStructure {
893    fn characteristic(&self) -> Natural {
894        Natural::ZERO
895    }
896}
897
898impl TryReciprocalSignature for ComplexAlgebraicCanonicalStructure {
899    fn try_reciprocal(&self, a: &Self::Set) -> Option<Self::Set> {
900        // println!("inv {:?}", a);
901        // a.check_invariants().unwrap();
902
903        match a {
904            ComplexAlgebraic::Real(a) => Some(ComplexAlgebraic::Real(a.try_reciprocal()?)),
905            ComplexAlgebraic::Complex(a) => {
906                let mut root = a.clone();
907
908                let inv_poly = Polynomial::from_coeffs(
909                    root.poly
910                        .coeffs()
911                        .collect::<Vec<_>>()
912                        .into_iter()
913                        .rev()
914                        .collect(),
915                )
916                .fav_assoc();
917                debug_assert!(inv_poly.is_irreducible());
918
919                // println!("root = {} = {:?}", root, root);
920                // println!("inv_poly = {}", inv_poly);
921                // for root in inv_poly.all_complex_roots() {
922                //     println!("root = {}", root);
923                // }
924
925                // z = the root represented by self
926                // a = the center of the approximation
927                // eps = the radius of the approximation
928
929                //result used to get region which contains the reciprocal
930                // if for some 0 < lambda < 1 we have |z - a| < eps <= (1 - lambda) |a| then |1/z - 1/a| < eps / lambda |a|^2
931
932                loop {
933                    //estimate eps such that |z - a| < eps
934                    let eps = ((&root.tight_b - &root.tight_a) + (&root.tight_d - &root.tight_c))
935                        / Rational::TWO;
936
937                    let w_re = (&root.tight_a + &root.tight_b) / Rational::TWO;
938                    let w_im = (&root.tight_c + &root.tight_d) / Rational::TWO;
939                    let w_mag_sq = &w_re * &w_re + &w_im * &w_im;
940
941                    // println!(
942                    //     "w = {} + {} i",
943                    //     decimal_string_approx(w_re.clone()),
944                    //     decimal_string_approx(w_im.clone())
945                    // );
946
947                    //refine until eps < |a|
948                    if &eps * &eps > w_mag_sq {
949                        root.refine();
950                        continue;
951                    }
952
953                    // find 0 < lambda < 1 such that eps < (1 - lambda) * |a|
954                    let mut lambda = Rational::ONE_HALF;
955                    #[allow(clippy::assign_op_pattern)]
956                    while &eps * &eps >= (Rational::ONE - &lambda) * &w_mag_sq {
957                        lambda = lambda * &Rational::ONE_HALF;
958                    }
959                    let lambda = lambda;
960                    // println!("lambda = {}", lambda);
961
962                    // |1/z - 1/a| < eps / lambda |a|^2
963
964                    let w_recip_re = w_re / &w_mag_sq;
965                    let w_recip_im = -w_im / &w_mag_sq;
966                    let delta = &eps / (lambda * w_mag_sq);
967
968                    let inv_tight_a = &w_recip_re - &delta;
969                    let inv_tight_b = &w_recip_re + &delta;
970                    let inv_tight_c = &w_recip_im - &delta;
971                    let inv_tight_d = &w_recip_im + &delta;
972
973                    // println!(
974                    //     "w_inv = {} + {} i",
975                    //     decimal_string_approx(w_recip_re),
976                    //     decimal_string_approx(w_recip_im)
977                    // );
978                    // println!(
979                    //     "eps = {}  delta = {}",
980                    //     decimal_string_approx(eps),
981                    //     decimal_string_approx(delta)
982                    // );
983
984                    if let Some(count) = inv_poly.count_complex_roots(
985                        &inv_tight_a,
986                        &inv_tight_b,
987                        &inv_tight_c,
988                        &inv_tight_d,
989                    ) {
990                        if count == 0 {
991                            unreachable!();
992                        } else if count == 1 {
993                            let ans = ComplexAlgebraic::Complex(ComplexAlgebraicRoot {
994                                tight_a: inv_tight_a,
995                                tight_b: inv_tight_b,
996                                tight_c: inv_tight_c,
997                                tight_d: inv_tight_d,
998                                poly: inv_poly,
999                            });
1000                            #[cfg(debug_assertions)]
1001                            ans.check_invariants().unwrap();
1002                            return Some(ans);
1003                        }
1004                    }
1005
1006                    root.refine();
1007                }
1008            }
1009        }
1010    }
1011}
1012
1013impl CancellativeMultiplicationSignature for ComplexAlgebraicCanonicalStructure {
1014    fn try_divide(&self, a: &Self::Set, b: &Self::Set) -> Option<Self::Set> {
1015        Some(self.mul(a, &self.try_reciprocal(b)?))
1016    }
1017}
1018
1019impl MultiplicativeIntegralMonoidSignature for ComplexAlgebraicCanonicalStructure {}
1020
1021impl IntegralDomainSignature for ComplexAlgebraicCanonicalStructure {}
1022
1023impl FieldSignature for ComplexAlgebraicCanonicalStructure {}
1024
1025impl CharZeroRingSignature for ComplexAlgebraicCanonicalStructure {
1026    fn try_to_int(&self, alg: &Self::Set) -> Option<Integer> {
1027        match alg {
1028            ComplexAlgebraic::Real(real_alg) => real_alg.try_to_int(),
1029            ComplexAlgebraic::Complex(_) => None,
1030        }
1031    }
1032}
1033
1034impl CharZeroFieldSignature for ComplexAlgebraicCanonicalStructure {
1035    fn try_to_rat(&self, x: &Self::Set) -> Option<Rational> {
1036        match x {
1037            ComplexAlgebraic::Real(real_algebraic) => {
1038                RealAlgebraic::structure().try_to_rat(real_algebraic)
1039            }
1040            ComplexAlgebraic::Complex(_) => None,
1041        }
1042    }
1043}
1044
1045impl ComplexSubsetSignature for ComplexAlgebraicCanonicalStructure {
1046    fn as_f32_real_and_imaginary_parts(&self, z: &Self::Set) -> (f32, f32) {
1047        match z {
1048            ComplexAlgebraic::Real(z) => z.as_f32_real_and_imaginary_parts(),
1049            ComplexAlgebraic::Complex(z) => {
1050                let mut z = z.clone();
1051                z.refine_to_accuracy(&Rational::from_integers(
1052                    Integer::from(1),
1053                    Integer::from(100000000i64),
1054                ));
1055                (
1056                    ((z.tight_a + z.tight_b) / Rational::from(2)).as_f32(),
1057                    ((z.tight_c + z.tight_d) / Rational::from(2)).as_f32(),
1058                )
1059            }
1060        }
1061    }
1062
1063    fn as_f64_real_and_imaginary_parts(&self, z: &Self::Set) -> (f64, f64) {
1064        match z {
1065            ComplexAlgebraic::Real(z) => z.as_f64_real_and_imaginary_parts(),
1066            ComplexAlgebraic::Complex(z) => {
1067                let mut z = z.clone();
1068                z.refine_to_accuracy(&Rational::from_integers(
1069                    Integer::from(1),
1070                    Integer::from(1000000000000000000i64),
1071                ));
1072                (
1073                    ((z.tight_a + z.tight_b) / Rational::from(2)).as_f64(),
1074                    ((z.tight_c + z.tight_d) / Rational::from(2)).as_f64(),
1075                )
1076            }
1077        }
1078    }
1079}
1080
1081impl ComplexConjugateSignature for ComplexAlgebraicCanonicalStructure {
1082    fn conjugate(&self, x: &Self::Set) -> Self::Set {
1083        match x {
1084            ComplexAlgebraic::Real(x) => ComplexAlgebraic::Real(x.clone()),
1085            ComplexAlgebraic::Complex(x) => ComplexAlgebraic::Complex(x.clone().conj()),
1086        }
1087    }
1088}
1089
1090impl PositiveRealNthRootSignature for ComplexAlgebraicCanonicalStructure {
1091    fn nth_root(&self, x: &Self::Set, n: usize) -> Result<Self::Set, ()> {
1092        match x {
1093            ComplexAlgebraic::Real(x) => Ok(ComplexAlgebraic::Real(x.nth_root(n)?)),
1094            ComplexAlgebraic::Complex(_) => Err(()),
1095        }
1096    }
1097}
1098
1099impl ComplexAlgebraic {
1100    pub fn min_poly(&self) -> Polynomial<Rational> {
1101        match self {
1102            ComplexAlgebraic::Real(real_algebraic) => real_algebraic.min_poly(),
1103            ComplexAlgebraic::Complex(complex_root) => complex_root.min_poly(),
1104        }
1105    }
1106}
1107
1108impl<B: BorrowedStructure<ComplexAlgebraicCanonicalStructure>>
1109    IntegralDomainExtensionAllPolynomialRoots<
1110        IntegerCanonicalStructure,
1111        ComplexAlgebraicCanonicalStructure,
1112    > for PrincipalIntegerMap<ComplexAlgebraicCanonicalStructure, B>
1113{
1114    fn all_roots(&self, polynomial: &Polynomial<Integer>) -> Vec<ComplexAlgebraic> {
1115        polynomial.all_complex_roots()
1116    }
1117}
1118
1119impl<B: BorrowedStructure<ComplexAlgebraicCanonicalStructure>>
1120    IntegralDomainExtensionAllPolynomialRoots<
1121        RationalCanonicalStructure,
1122        ComplexAlgebraicCanonicalStructure,
1123    > for PrincipalRationalMap<ComplexAlgebraicCanonicalStructure, B>
1124{
1125    fn all_roots(&self, polynomial: &Polynomial<Rational>) -> Vec<ComplexAlgebraic> {
1126        polynomial.all_complex_roots()
1127    }
1128}
1129
1130#[cfg(test)]
1131mod tests {
1132    use super::*;
1133
1134    #[test]
1135    fn test_apply_poly() {
1136        let x = &Polynomial::<Rational>::var().into_ergonomic();
1137
1138        let f = (2 * x.pow(2) - 4 * x - 3).into_verbose();
1139        let g = (3 * x.pow(3) + 7 * x - 1).into_verbose();
1140        //h(x) = f(g(x))
1141        let h = Polynomial::compose(&f, &g);
1142
1143        println!("f = {}", f);
1144        println!("g = {}", g);
1145        println!("h = {}", h);
1146
1147        for x in h.primitive_part_fof().all_complex_roots() {
1148            println!();
1149            println!("x = {} deg = {}", x, x.min_poly().degree().unwrap());
1150            let gx = x.clone().apply_poly(&g);
1151            println!("gx = {}", gx);
1152            let fgx = gx.clone().apply_poly(&f);
1153            println!("fgx = {}", fgx);
1154            debug_assert_eq!(fgx, ComplexAlgebraic::zero());
1155        }
1156
1157        let i = &ComplexAlgebraic::i().into_ergonomic();
1158        let a = (2 + 3 * i).into_verbose();
1159        let f = (x.pow(10)).into_verbose();
1160        assert_eq!(
1161            a.clone().apply_poly(&f),
1162            (-341_525 - 145_668 * i).into_verbose()
1163        );
1164    }
1165
1166    #[test]
1167    fn test_all_complex_roots() {
1168        let f = Polynomial::<Integer>::from_coeffs(vec![-1, -1, 0, 0, 0, 1]);
1169        let roots = f.all_complex_roots();
1170        assert_eq!(roots.len(), Polynomial::degree(&f).unwrap());
1171        for root in &roots {
1172            root.check_invariants().unwrap();
1173        }
1174    }
1175
1176    #[test]
1177    fn test_complex_equal() {
1178        let x = &Polynomial::<Integer>::var().into_ergonomic();
1179        let f = (x.pow(5) - x + 1).into_verbose();
1180        assert!(f.is_irreducible());
1181        let mut count = 0;
1182        for a in f.all_complex_roots() {
1183            for b in f.all_complex_roots() {
1184                if a == b {
1185                    count += 1;
1186                }
1187            }
1188        }
1189        assert_eq!(count, f.degree().unwrap());
1190    }
1191
1192    #[test]
1193    fn test_complex_root_sum() {
1194        let f = Polynomial::<Integer>::from_coeffs(vec![1, 0, 0, 1]);
1195        let roots = f.all_complex_roots();
1196        let s = ComplexAlgebraic::sum(roots.iter().collect());
1197        println!("{:?}", s);
1198        assert_eq!(s, ComplexAlgebraic::zero());
1199
1200        let f = Polynomial::<Integer>::from_coeffs(vec![7, -3, 42, 9]);
1201        println!("f = {}", f);
1202        let roots = f.all_complex_roots();
1203        for root in &roots {
1204            println!("root = {}", root);
1205        }
1206        let s = ComplexAlgebraic::sum(roots.iter().collect());
1207        println!("root sum = {:?}", s);
1208        assert_eq!(
1209            s,
1210            ComplexAlgebraic::Real(RealAlgebraic::Rational(Rational::from_integers(
1211                Integer::from(-14),
1212                Integer::from(3)
1213            )))
1214        );
1215    }
1216
1217    #[test]
1218    fn test_complex_mul() {
1219        let f = Polynomial::<Integer>::from_coeffs(vec![1, 0, 0, 1]);
1220        let roots = f.all_complex_roots();
1221        let s = ComplexAlgebraic::product(roots.iter().collect());
1222        println!("{:?}", s);
1223        assert_eq!(s, ComplexAlgebraic::one().neg());
1224
1225        let f = Polynomial::<Integer>::from_coeffs(vec![7, -3, 42, 9]);
1226        println!("f = {}", f);
1227        let roots = f.all_complex_roots();
1228        for root in &roots {
1229            println!("root = {}", root);
1230        }
1231        let s = ComplexAlgebraic::product(roots.iter().collect());
1232        println!("root prod = {:?}", s);
1233        assert_eq!(
1234            s,
1235            ComplexAlgebraic::Real(RealAlgebraic::Rational(Rational::from_integers(
1236                Integer::from(-7),
1237                Integer::from(9)
1238            )))
1239        );
1240    }
1241
1242    #[test]
1243    fn test_complex_inv() {
1244        let x = &Polynomial::<Integer>::var().into_ergonomic();
1245        let f = (x.pow(4) - x + 1).into_verbose();
1246
1247        for root in f.all_complex_roots() {
1248            assert_eq!(
1249                ComplexAlgebraic::mul(&root.try_reciprocal().unwrap(), &root),
1250                ComplexAlgebraic::one()
1251            );
1252        }
1253    }
1254}