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 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 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
74fn 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 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_b: Rational, tight_c: Rational, tight_d: Rational, poly: Polynomial<Integer>, }
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 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); 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 if m_im >= Rational::ZERO {
233 write!(f, "+")?;
234 }
235 write!(f, "{}", m_im.decimal_string_approx())?;
236 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.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 if poly == &other.poly {
374 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 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 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 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 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 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 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 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 loop {
933 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 if &eps * &eps > w_mag_sq {
949 root.refine();
950 continue;
951 }
952
953 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 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 - δ
969 let inv_tight_b = &w_recip_re + δ
970 let inv_tight_c = &w_recip_im - δ
971 let inv_tight_d = &w_recip_im + δ
972
973 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 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}