1#![allow(clippy::items_after_test_module)]
5
6use oxilean_kernel::{BinderInfo, Declaration, Environment, Expr, Level, Name};
7use std::f64::consts::PI;
8
9use super::complex_type::Complex;
10use super::types::{MobiusTransform, C64};
11
12#[allow(dead_code)]
13pub fn app(f: Expr, a: Expr) -> Expr {
14 Expr::App(Box::new(f), Box::new(a))
15}
16#[allow(dead_code)]
17pub fn app2(f: Expr, a: Expr, b: Expr) -> Expr {
18 app(app(f, a), b)
19}
20#[allow(dead_code)]
21pub fn app3(f: Expr, a: Expr, b: Expr, c: Expr) -> Expr {
22 app(app2(f, a, b), c)
23}
24pub fn cst(s: &str) -> Expr {
25 Expr::Const(Name::str(s), vec![])
26}
27#[allow(dead_code)]
28pub fn prop() -> Expr {
29 Expr::Sort(Level::zero())
30}
31pub fn type0() -> Expr {
32 Expr::Sort(Level::succ(Level::zero()))
33}
34pub fn pi(bi: BinderInfo, name: &str, dom: Expr, body: Expr) -> Expr {
35 Expr::Pi(bi, Name::str(name), Box::new(dom), Box::new(body))
36}
37pub fn arrow(a: Expr, b: Expr) -> Expr {
38 pi(BinderInfo::Default, "_", a, b)
39}
40#[allow(dead_code)]
41pub fn impl_pi(name: &str, dom: Expr, body: Expr) -> Expr {
42 pi(BinderInfo::Implicit, name, dom, body)
43}
44pub fn bvar(n: u32) -> Expr {
45 Expr::BVar(n)
46}
47pub fn real_ty() -> Expr {
48 cst("Real")
49}
50pub fn complex_ty() -> Expr {
51 cst("Complex")
52}
53pub fn nat_ty() -> Expr {
54 cst("Nat")
55}
56pub fn complex_type_decl() -> Expr {
58 type0()
59}
60pub fn complex_mk_ty() -> Expr {
62 arrow(real_ty(), arrow(real_ty(), complex_ty()))
63}
64pub fn complex_re_ty() -> Expr {
66 arrow(complex_ty(), real_ty())
67}
68pub fn complex_im_ty() -> Expr {
70 arrow(complex_ty(), real_ty())
71}
72pub fn complex_add_ty() -> Expr {
74 arrow(complex_ty(), arrow(complex_ty(), complex_ty()))
75}
76pub fn complex_mul_ty() -> Expr {
78 arrow(complex_ty(), arrow(complex_ty(), complex_ty()))
79}
80pub fn complex_neg_ty() -> Expr {
82 arrow(complex_ty(), complex_ty())
83}
84pub fn complex_conj_ty() -> Expr {
86 arrow(complex_ty(), complex_ty())
87}
88pub fn complex_norm_sq_ty() -> Expr {
90 arrow(complex_ty(), real_ty())
91}
92pub fn complex_abs_ty() -> Expr {
94 arrow(complex_ty(), real_ty())
95}
96pub fn complex_arg_ty() -> Expr {
98 arrow(complex_ty(), real_ty())
99}
100pub fn complex_exp_ty() -> Expr {
102 arrow(complex_ty(), complex_ty())
103}
104pub fn complex_log_ty() -> Expr {
106 arrow(complex_ty(), complex_ty())
107}
108pub fn complex_pow_ty() -> Expr {
110 arrow(complex_ty(), arrow(nat_ty(), complex_ty()))
111}
112pub fn complex_sqrt_ty() -> Expr {
114 arrow(complex_ty(), complex_ty())
115}
116pub fn complex_of_real_ty() -> Expr {
118 arrow(real_ty(), complex_ty())
119}
120pub fn complex_i_ty() -> Expr {
122 complex_ty()
123}
124pub fn euler_formula_ty() -> Expr {
126 pi(
127 BinderInfo::Default,
128 "theta",
129 real_ty(),
130 app2(
131 app(cst("Eq"), complex_ty()),
132 app(
133 cst("Complex.exp"),
134 app2(
135 cst("Complex.mul"),
136 cst("Complex.I"),
137 app(cst("Complex.ofReal"), bvar(0)),
138 ),
139 ),
140 app2(
141 cst("Complex.add"),
142 app(cst("Complex.ofReal"), app(cst("Real.cos"), bvar(0))),
143 app2(
144 cst("Complex.mul"),
145 cst("Complex.I"),
146 app(cst("Complex.ofReal"), app(cst("Real.sin"), bvar(0))),
147 ),
148 ),
149 ),
150 )
151}
152pub fn de_moivre_theorem_ty() -> Expr {
154 pi(
155 BinderInfo::Default,
156 "theta",
157 real_ty(),
158 pi(
159 BinderInfo::Default,
160 "n",
161 nat_ty(),
162 app2(
163 app(cst("Eq"), complex_ty()),
164 app2(
165 cst("Complex.pow"),
166 app2(
167 cst("Complex.add"),
168 app(cst("Complex.ofReal"), app(cst("Real.cos"), bvar(1))),
169 app2(
170 cst("Complex.mul"),
171 cst("Complex.I"),
172 app(cst("Complex.ofReal"), app(cst("Real.sin"), bvar(1))),
173 ),
174 ),
175 bvar(0),
176 ),
177 app2(
178 cst("Complex.add"),
179 app(
180 cst("Complex.ofReal"),
181 app(
182 cst("Real.cos"),
183 app2(cst("Real.mul"), app(cst("Nat.cast"), bvar(0)), bvar(1)),
184 ),
185 ),
186 app2(
187 cst("Complex.mul"),
188 cst("Complex.I"),
189 app(
190 cst("Complex.ofReal"),
191 app(
192 cst("Real.sin"),
193 app2(cst("Real.mul"), app(cst("Nat.cast"), bvar(0)), bvar(1)),
194 ),
195 ),
196 ),
197 ),
198 ),
199 ),
200 )
201}
202pub fn fundamental_theorem_algebra_ty() -> Expr {
204 pi(
205 BinderInfo::Default,
206 "p",
207 app(cst("Polynomial"), complex_ty()),
208 arrow(
209 app(cst("Polynomial.degree_pos"), bvar(0)),
210 app(
211 cst("Exists"),
212 pi(
213 BinderInfo::Default,
214 "z",
215 complex_ty(),
216 app2(
217 app(cst("Eq"), complex_ty()),
218 app2(cst("Polynomial.eval"), bvar(0), bvar(1)),
219 app(
220 cst("Complex.ofReal"),
221 app(
222 cst("Real.ofNat"),
223 Expr::Lit(oxilean_kernel::Literal::Nat(0)),
224 ),
225 ),
226 ),
227 ),
228 ),
229 ),
230 )
231}
232pub fn liouville_theorem_ty() -> Expr {
234 pi(
235 BinderInfo::Default,
236 "f",
237 arrow(complex_ty(), complex_ty()),
238 arrow(
239 app(cst("IsEntire"), bvar(0)),
240 arrow(
241 app(cst("IsBounded"), bvar(0)),
242 app(cst("IsConstant"), bvar(0)),
243 ),
244 ),
245 )
246}
247pub fn cauchy_integral_theorem_ty() -> Expr {
249 pi(
250 BinderInfo::Default,
251 "f",
252 arrow(complex_ty(), complex_ty()),
253 pi(
254 BinderInfo::Default,
255 "C",
256 app(cst("ClosedCurve"), complex_ty()),
257 arrow(
258 app(cst("IsHolomorphic"), bvar(1)),
259 app2(
260 app(cst("Eq"), complex_ty()),
261 app2(cst("ContourIntegral"), bvar(1), bvar(0)),
262 app(
263 cst("Complex.ofReal"),
264 Expr::Lit(oxilean_kernel::Literal::Nat(0)),
265 ),
266 ),
267 ),
268 ),
269 )
270}
271pub fn roots_of_unity_ty() -> Expr {
273 pi(
274 BinderInfo::Default,
275 "n",
276 nat_ty(),
277 arrow(
278 app2(
279 cst("Nat.lt"),
280 Expr::Lit(oxilean_kernel::Literal::Nat(0)),
281 bvar(0),
282 ),
283 app2(
284 app(cst("Eq"), nat_ty()),
285 app(cst("Fintype.card"), app(cst("rootsOfUnity"), bvar(0))),
286 bvar(0),
287 ),
288 ),
289 )
290}
291pub fn cauchy_riemann_ty() -> Expr {
294 pi(
295 BinderInfo::Default,
296 "f",
297 arrow(complex_ty(), complex_ty()),
298 app2(
299 app(cst("Iff"), prop()),
300 app(cst("IsHolomorphic"), bvar(0)),
301 app(cst("SatisfiesCauchyRiemann"), bvar(0)),
302 ),
303 )
304}
305pub fn cauchy_integral_formula_ty() -> Expr {
307 pi(
308 BinderInfo::Default,
309 "f",
310 arrow(complex_ty(), complex_ty()),
311 pi(
312 BinderInfo::Default,
313 "C",
314 app(cst("ClosedCurve"), complex_ty()),
315 pi(
316 BinderInfo::Default,
317 "z0",
318 complex_ty(),
319 arrow(
320 app(cst("IsHolomorphicOn"), app2(cst("Pair"), bvar(2), bvar(1))),
321 arrow(
322 app2(cst("InsideCurve"), bvar(0), bvar(1)),
323 app2(
324 app(cst("Eq"), complex_ty()),
325 app(bvar(2), bvar(0)),
326 app2(cst("ContourIntegralFormula"), bvar(2), bvar(1)),
327 ),
328 ),
329 ),
330 ),
331 ),
332 )
333}
334pub fn residue_theorem_ty() -> Expr {
336 pi(
337 BinderInfo::Default,
338 "f",
339 arrow(complex_ty(), complex_ty()),
340 pi(
341 BinderInfo::Default,
342 "C",
343 app(cst("ClosedCurve"), complex_ty()),
344 arrow(
345 app(cst("IsMeromorphicOn"), app2(cst("Pair"), bvar(1), bvar(0))),
346 app2(
347 app(cst("Eq"), complex_ty()),
348 app2(cst("ContourIntegral"), bvar(1), bvar(0)),
349 app2(cst("ResidueSum"), bvar(1), bvar(0)),
350 ),
351 ),
352 ),
353 )
354}
355pub fn analytic_continuation_ty() -> Expr {
357 pi(
358 BinderInfo::Default,
359 "f",
360 arrow(complex_ty(), complex_ty()),
361 pi(
362 BinderInfo::Default,
363 "g",
364 arrow(complex_ty(), complex_ty()),
365 arrow(
366 app(cst("IsEntire"), bvar(1)),
367 arrow(
368 app(cst("IsEntire"), bvar(0)),
369 arrow(
370 app2(cst("AgreeOnOpenSet"), bvar(1), bvar(0)),
371 app2(cst("FunEq"), bvar(1), bvar(0)),
372 ),
373 ),
374 ),
375 ),
376 )
377}
378pub fn picard_little_theorem_ty() -> Expr {
380 pi(
381 BinderInfo::Default,
382 "f",
383 arrow(complex_ty(), complex_ty()),
384 arrow(
385 app(cst("IsEntire"), bvar(0)),
386 arrow(
387 app2(cst("Not"), prop(), app(cst("IsConstant"), bvar(0))),
388 app2(cst("OmitsAtMostOne"), bvar(0), complex_ty()),
389 ),
390 ),
391 )
392}
393pub fn picard_great_theorem_ty() -> Expr {
395 pi(
396 BinderInfo::Default,
397 "f",
398 arrow(complex_ty(), complex_ty()),
399 pi(
400 BinderInfo::Default,
401 "z0",
402 complex_ty(),
403 arrow(
404 app2(cst("IsEssentialSingularity"), bvar(1), bvar(0)),
405 app2(cst("DenseImageNearPoint"), bvar(1), bvar(0)),
406 ),
407 ),
408 )
409}
410pub fn weierstrass_factorization_ty() -> Expr {
412 pi(
413 BinderInfo::Default,
414 "f",
415 arrow(complex_ty(), complex_ty()),
416 arrow(
417 app(cst("IsEntire"), bvar(0)),
418 app2(cst("HasWeierstrassFactorization"), bvar(0), complex_ty()),
419 ),
420 )
421}
422pub fn meromorphic_riemann_sphere_ty() -> Expr {
424 pi(
425 BinderInfo::Default,
426 "f",
427 arrow(complex_ty(), complex_ty()),
428 app2(
429 app(cst("Iff"), prop()),
430 app(cst("IsMeromorphicOnSphere"), bvar(0)),
431 app(cst("IsRationalFunction"), bvar(0)),
432 ),
433 )
434}
435pub fn riemann_mapping_theorem_ty() -> Expr {
437 pi(
438 BinderInfo::Default,
439 "U",
440 app(cst("OpenSet"), complex_ty()),
441 arrow(
442 app(cst("IsSimplyConnected"), bvar(0)),
443 arrow(
444 app2(cst("ProperSubset"), bvar(0), complex_ty()),
445 app2(cst("ConformallyEquivalent"), bvar(0), cst("UnitDisk")),
446 ),
447 ),
448 )
449}
450pub fn mobius_group_ty() -> Expr {
452 app(cst("IsGroup"), cst("MobiusGroup"))
453}
454pub fn mobius_conformal_ty() -> Expr {
456 pi(
457 BinderInfo::Default,
458 "m",
459 cst("MobiusGroup"),
460 app(cst("IsConformalAutomorphism"), bvar(0)),
461 )
462}
463pub fn laurent_series_ty() -> Expr {
465 pi(
466 BinderInfo::Default,
467 "f",
468 arrow(complex_ty(), complex_ty()),
469 pi(
470 BinderInfo::Default,
471 "z0",
472 complex_ty(),
473 arrow(
474 app2(cst("IsIsolatedSingularity"), bvar(1), bvar(0)),
475 app2(cst("HasLaurentSeries"), bvar(1), bvar(0)),
476 ),
477 ),
478 )
479}
480pub fn argument_principle_ty() -> Expr {
482 pi(
483 BinderInfo::Default,
484 "f",
485 arrow(complex_ty(), complex_ty()),
486 pi(
487 BinderInfo::Default,
488 "C",
489 app(cst("ClosedCurve"), complex_ty()),
490 arrow(
491 app(cst("IsMeromorphicOn"), app2(cst("Pair"), bvar(1), bvar(0))),
492 app2(
493 app(cst("Eq"), nat_ty()),
494 app2(cst("WindingNumberIntegral"), bvar(1), bvar(0)),
495 app2(
496 cst("Nat.sub"),
497 app2(cst("CountZeros"), bvar(1), bvar(0)),
498 app2(cst("CountPoles"), bvar(1), bvar(0)),
499 ),
500 ),
501 ),
502 ),
503 )
504}
505pub fn rouche_theorem_ty() -> Expr {
507 pi(
508 BinderInfo::Default,
509 "f",
510 arrow(complex_ty(), complex_ty()),
511 pi(
512 BinderInfo::Default,
513 "g",
514 arrow(complex_ty(), complex_ty()),
515 pi(
516 BinderInfo::Default,
517 "C",
518 app(cst("ClosedCurve"), complex_ty()),
519 arrow(
520 app2(
521 cst("DominatesOnCurve"),
522 bvar(2),
523 app2(cst("Pair"), bvar(1), bvar(0)),
524 ),
525 app2(
526 app(cst("Eq"), nat_ty()),
527 app2(cst("CountZeros"), bvar(2), bvar(0)),
528 app2(
529 cst("CountZeros"),
530 app2(cst("FunAdd"), bvar(2), bvar(1)),
531 bvar(0),
532 ),
533 ),
534 ),
535 ),
536 ),
537 )
538}
539pub fn mittag_leffler_theorem_ty() -> Expr {
541 pi(
542 BinderInfo::Default,
543 "poles",
544 app(cst("List"), complex_ty()),
545 pi(
546 BinderInfo::Default,
547 "parts",
548 app(cst("List"), app(cst("LaurentPrincipalPart"), complex_ty())),
549 arrow(
550 app2(cst("CompatiblePolesAndParts"), bvar(1), bvar(0)),
551 app(
552 cst("Exists"),
553 pi(
554 BinderInfo::Default,
555 "f",
556 arrow(complex_ty(), complex_ty()),
557 app2(
558 cst("HasPrescribedPoles"),
559 bvar(0),
560 app2(cst("Pair"), bvar(2), bvar(1)),
561 ),
562 ),
563 ),
564 ),
565 ),
566 )
567}
568pub fn runge_theorem_ty() -> Expr {
570 pi(
571 BinderInfo::Default,
572 "K",
573 app(cst("CompactSet"), complex_ty()),
574 pi(
575 BinderInfo::Default,
576 "f",
577 arrow(complex_ty(), complex_ty()),
578 arrow(
579 app(
580 cst("IsHolomorphicOnCompact"),
581 app2(cst("Pair"), bvar(1), bvar(0)),
582 ),
583 app2(
584 cst("UniformlyApproximableBy"),
585 app2(cst("Pair"), bvar(1), bvar(0)),
586 cst("RationalFunctions"),
587 ),
588 ),
589 ),
590 )
591}
592pub fn hardy_banach_ty() -> Expr {
594 pi(
595 BinderInfo::Default,
596 "p",
597 real_ty(),
598 arrow(
599 app2(
600 cst("Real.le"),
601 Expr::Lit(oxilean_kernel::Literal::Nat(1)),
602 bvar(0),
603 ),
604 app(cst("IsBanachSpace"), app(cst("HardySpace"), bvar(0))),
605 ),
606 )
607}
608pub fn nevanlinna_first_theorem_ty() -> Expr {
610 pi(
611 BinderInfo::Default,
612 "f",
613 arrow(complex_ty(), complex_ty()),
614 arrow(
615 app(cst("IsMeromorphic"), bvar(0)),
616 app(cst("NevanlinnaFirstFundamentalTheorem"), bvar(0)),
617 ),
618 )
619}
620pub fn nevanlinna_second_theorem_ty() -> Expr {
622 pi(
623 BinderInfo::Default,
624 "f",
625 arrow(complex_ty(), complex_ty()),
626 arrow(
627 app(cst("IsEntire"), bvar(0)),
628 app2(
629 app(cst("Real.le"), prop()),
630 app(cst("NevanlinnaDeficiencySum"), bvar(0)),
631 Expr::Lit(oxilean_kernel::Literal::Nat(2)),
632 ),
633 ),
634 )
635}
636pub fn bloch_theorem_ty() -> Expr {
638 pi(
639 BinderInfo::Default,
640 "f",
641 arrow(complex_ty(), complex_ty()),
642 arrow(
643 app(cst("IsHolomorphicOnDisk"), bvar(0)),
644 app2(cst("ImageContainsDisk"), bvar(0), cst("BlochConstant")),
645 ),
646 )
647}
648pub fn weierstrass_p_ty() -> Expr {
650 pi(
651 BinderInfo::Default,
652 "L",
653 app(cst("Lattice"), complex_ty()),
654 app(cst("IsEllipticFunction"), app(cst("WeierstrassP"), bvar(0))),
655 )
656}
657pub fn elliptic_liouville_ty() -> Expr {
659 pi(
660 BinderInfo::Default,
661 "L",
662 app(cst("Lattice"), complex_ty()),
663 pi(
664 BinderInfo::Default,
665 "f",
666 arrow(complex_ty(), complex_ty()),
667 arrow(
668 app2(cst("IsEllipticFunctionForLattice"), bvar(0), bvar(1)),
669 arrow(
670 app(cst("IsBounded"), bvar(0)),
671 app(cst("IsConstant"), bvar(0)),
672 ),
673 ),
674 ),
675 )
676}
677pub fn modular_form_finite_dim_ty() -> Expr {
679 pi(
680 BinderInfo::Default,
681 "k",
682 nat_ty(),
683 app(
684 cst("IsFiniteDimensional"),
685 app(cst("ModularFormSpace"), bvar(0)),
686 ),
687 )
688}
689pub fn hartogs_theorem_ty() -> Expr {
691 pi(
692 BinderInfo::Default,
693 "n",
694 nat_ty(),
695 pi(
696 BinderInfo::Default,
697 "U",
698 app(cst("OpenSet"), app(cst("CVec"), bvar(0))),
699 pi(
700 BinderInfo::Default,
701 "K",
702 app(cst("CompactSet"), app(cst("CVec"), bvar(1))),
703 arrow(
704 app2(cst("IsCompactlyContained"), bvar(0), bvar(1)),
705 arrow(
706 app(cst("IsSimplyConnected"), bvar(1)),
707 app2(cst("HolomorphicFunctionsExtend"), bvar(1), bvar(0)),
708 ),
709 ),
710 ),
711 ),
712 )
713}
714pub fn oka_theorem_ty() -> Expr {
716 pi(
717 BinderInfo::Default,
718 "D",
719 app(cst("Domain"), cst("CnSpace")),
720 app2(
721 app(cst("Iff"), prop()),
722 app(cst("IsPseudoconvex"), bvar(0)),
723 app(cst("IsDomainOfHolomorphy"), bvar(0)),
724 ),
725 )
726}
727pub fn bohr_theorem_ty() -> Expr {
729 pi(
730 BinderInfo::Default,
731 "f",
732 arrow(complex_ty(), complex_ty()),
733 arrow(
734 app(cst("IsHolomorphicOnDisk"), bvar(0)),
735 arrow(
736 app(cst("BoundedByOneOnDisk"), bvar(0)),
737 app2(
738 cst("PowerSeriesConvergesInDisk"),
739 bvar(0),
740 cst("BohrConstant"),
741 ),
742 ),
743 ),
744 )
745}
746pub fn paley_wiener_theorem_ty() -> Expr {
748 pi(
749 BinderInfo::Default,
750 "f",
751 arrow(real_ty(), complex_ty()),
752 app2(
753 app(cst("Iff"), prop()),
754 app(cst("IsBandlimited"), bvar(0)),
755 app(cst("FourierTransformHasCompactSupport"), bvar(0)),
756 ),
757 )
758}
759pub fn hadamard_factorization_ty() -> Expr {
761 pi(
762 BinderInfo::Default,
763 "f",
764 arrow(complex_ty(), complex_ty()),
765 pi(
766 BinderInfo::Default,
767 "rho",
768 real_ty(),
769 arrow(
770 app(cst("IsEntire"), bvar(1)),
771 arrow(
772 app2(cst("HasFiniteOrder"), bvar(1), bvar(0)),
773 app2(cst("HasHadamardFactorization"), bvar(1), bvar(0)),
774 ),
775 ),
776 ),
777 )
778}
779pub fn schwarz_pick_lemma_ty() -> Expr {
781 pi(
782 BinderInfo::Default,
783 "f",
784 arrow(complex_ty(), complex_ty()),
785 arrow(
786 app(cst("IsSelfMapOfDisk"), bvar(0)),
787 app(cst("IsHyperbolicContraction"), bvar(0)),
788 ),
789 )
790}
791pub fn jensen_formula_ty() -> Expr {
793 pi(
794 BinderInfo::Default,
795 "f",
796 arrow(complex_ty(), complex_ty()),
797 pi(
798 BinderInfo::Default,
799 "r",
800 real_ty(),
801 arrow(
802 app(cst("IsHolomorphicOnDisk"), bvar(1)),
803 arrow(
804 app2(
805 cst("Real.lt"),
806 Expr::Lit(oxilean_kernel::Literal::Nat(0)),
807 bvar(0),
808 ),
809 app2(cst("JensenEquality"), bvar(1), bvar(0)),
810 ),
811 ),
812 ),
813 )
814}
815pub fn phragmen_lindelof_ty() -> Expr {
817 pi(
818 BinderInfo::Default,
819 "f",
820 arrow(complex_ty(), complex_ty()),
821 pi(
822 BinderInfo::Default,
823 "S",
824 app(cst("OpenSector"), complex_ty()),
825 arrow(
826 app(cst("IsHolomorphicOn"), app2(cst("Pair"), bvar(1), bvar(0))),
827 arrow(
828 app(
829 cst("BoundedOnBoundary"),
830 app2(cst("Pair"), bvar(1), bvar(0)),
831 ),
832 app(cst("BoundedOn"), app2(cst("Pair"), bvar(1), bvar(0))),
833 ),
834 ),
835 ),
836 )
837}
838pub fn riemann_zeta_meromorphic_ty() -> Expr {
840 app(cst("IsMeromorphic"), cst("RiemannZeta"))
841}
842pub fn riemann_hypothesis_ty() -> Expr {
844 pi(
845 BinderInfo::Default,
846 "s",
847 complex_ty(),
848 arrow(
849 app2(cst("IsNontrivialZeroOfZeta"), bvar(0), cst("RiemannZeta")),
850 app2(
851 app(cst("Eq"), real_ty()),
852 app(cst("Complex.re"), bvar(0)),
853 Expr::Lit(oxilean_kernel::Literal::Nat(0)),
854 ),
855 ),
856 )
857}
858#[allow(dead_code)]
860pub fn build_complex_env(env: &mut Environment) -> Result<(), String> {
861 let _ = env.add(Declaration::Axiom {
862 name: Name::str("Complex"),
863 univ_params: vec![],
864 ty: complex_type_decl(),
865 });
866 let _ = env.add(Declaration::Axiom {
867 name: Name::str("Complex.mk"),
868 univ_params: vec![],
869 ty: complex_mk_ty(),
870 });
871 let _ = env.add(Declaration::Axiom {
872 name: Name::str("Complex.re"),
873 univ_params: vec![],
874 ty: complex_re_ty(),
875 });
876 let _ = env.add(Declaration::Axiom {
877 name: Name::str("Complex.im"),
878 univ_params: vec![],
879 ty: complex_im_ty(),
880 });
881 let _ = env.add(Declaration::Axiom {
882 name: Name::str("Complex.add"),
883 univ_params: vec![],
884 ty: complex_add_ty(),
885 });
886 let _ = env.add(Declaration::Axiom {
887 name: Name::str("Complex.mul"),
888 univ_params: vec![],
889 ty: complex_mul_ty(),
890 });
891 let _ = env.add(Declaration::Axiom {
892 name: Name::str("Complex.neg"),
893 univ_params: vec![],
894 ty: complex_neg_ty(),
895 });
896 let _ = env.add(Declaration::Axiom {
897 name: Name::str("Complex.conj"),
898 univ_params: vec![],
899 ty: complex_conj_ty(),
900 });
901 let _ = env.add(Declaration::Axiom {
902 name: Name::str("Complex.normSq"),
903 univ_params: vec![],
904 ty: complex_norm_sq_ty(),
905 });
906 let _ = env.add(Declaration::Axiom {
907 name: Name::str("Complex.abs"),
908 univ_params: vec![],
909 ty: complex_abs_ty(),
910 });
911 let _ = env.add(Declaration::Axiom {
912 name: Name::str("Complex.arg"),
913 univ_params: vec![],
914 ty: complex_arg_ty(),
915 });
916 let _ = env.add(Declaration::Axiom {
917 name: Name::str("Complex.exp"),
918 univ_params: vec![],
919 ty: complex_exp_ty(),
920 });
921 let _ = env.add(Declaration::Axiom {
922 name: Name::str("Complex.log"),
923 univ_params: vec![],
924 ty: complex_log_ty(),
925 });
926 let _ = env.add(Declaration::Axiom {
927 name: Name::str("Complex.pow"),
928 univ_params: vec![],
929 ty: complex_pow_ty(),
930 });
931 let _ = env.add(Declaration::Axiom {
932 name: Name::str("Complex.sqrt"),
933 univ_params: vec![],
934 ty: complex_sqrt_ty(),
935 });
936 let _ = env.add(Declaration::Axiom {
937 name: Name::str("Complex.ofReal"),
938 univ_params: vec![],
939 ty: complex_of_real_ty(),
940 });
941 let _ = env.add(Declaration::Axiom {
942 name: Name::str("Complex.I"),
943 univ_params: vec![],
944 ty: complex_i_ty(),
945 });
946 let _ = env.add(Declaration::Axiom {
947 name: Name::str("Complex.euler_formula"),
948 univ_params: vec![],
949 ty: euler_formula_ty(),
950 });
951 let _ = env.add(Declaration::Axiom {
952 name: Name::str("Complex.de_moivre"),
953 univ_params: vec![],
954 ty: de_moivre_theorem_ty(),
955 });
956 let _ = env.add(Declaration::Axiom {
957 name: Name::str("Complex.fundamental_theorem_algebra"),
958 univ_params: vec![],
959 ty: fundamental_theorem_algebra_ty(),
960 });
961 let _ = env.add(Declaration::Axiom {
962 name: Name::str("Complex.liouville"),
963 univ_params: vec![],
964 ty: liouville_theorem_ty(),
965 });
966 let _ = env.add(Declaration::Axiom {
967 name: Name::str("Complex.cauchy_integral"),
968 univ_params: vec![],
969 ty: cauchy_integral_theorem_ty(),
970 });
971 let _ = env.add(Declaration::Axiom {
972 name: Name::str("Complex.roots_of_unity_card"),
973 univ_params: vec![],
974 ty: roots_of_unity_ty(),
975 });
976 let _ = env.add(Declaration::Axiom {
977 name: Name::str("ComplexAnalysis.cauchy_riemann"),
978 univ_params: vec![],
979 ty: cauchy_riemann_ty(),
980 });
981 let _ = env.add(Declaration::Axiom {
982 name: Name::str("ComplexAnalysis.cauchy_integral_formula"),
983 univ_params: vec![],
984 ty: cauchy_integral_formula_ty(),
985 });
986 let _ = env.add(Declaration::Axiom {
987 name: Name::str("ComplexAnalysis.residue_theorem"),
988 univ_params: vec![],
989 ty: residue_theorem_ty(),
990 });
991 let _ = env.add(Declaration::Axiom {
992 name: Name::str("ComplexAnalysis.analytic_continuation"),
993 univ_params: vec![],
994 ty: analytic_continuation_ty(),
995 });
996 let _ = env.add(Declaration::Axiom {
997 name: Name::str("ComplexAnalysis.picard_little"),
998 univ_params: vec![],
999 ty: picard_little_theorem_ty(),
1000 });
1001 let _ = env.add(Declaration::Axiom {
1002 name: Name::str("ComplexAnalysis.picard_great"),
1003 univ_params: vec![],
1004 ty: picard_great_theorem_ty(),
1005 });
1006 let _ = env.add(Declaration::Axiom {
1007 name: Name::str("ComplexAnalysis.weierstrass_factorization"),
1008 univ_params: vec![],
1009 ty: weierstrass_factorization_ty(),
1010 });
1011 let _ = env.add(Declaration::Axiom {
1012 name: Name::str("ComplexAnalysis.meromorphic_riemann_sphere"),
1013 univ_params: vec![],
1014 ty: meromorphic_riemann_sphere_ty(),
1015 });
1016 let _ = env.add(Declaration::Axiom {
1017 name: Name::str("ComplexAnalysis.riemann_mapping"),
1018 univ_params: vec![],
1019 ty: riemann_mapping_theorem_ty(),
1020 });
1021 let _ = env.add(Declaration::Axiom {
1022 name: Name::str("ComplexAnalysis.mobius_group"),
1023 univ_params: vec![],
1024 ty: mobius_group_ty(),
1025 });
1026 let _ = env.add(Declaration::Axiom {
1027 name: Name::str("ComplexAnalysis.mobius_conformal"),
1028 univ_params: vec![],
1029 ty: mobius_conformal_ty(),
1030 });
1031 let _ = env.add(Declaration::Axiom {
1032 name: Name::str("ComplexAnalysis.laurent_series"),
1033 univ_params: vec![],
1034 ty: laurent_series_ty(),
1035 });
1036 let _ = env.add(Declaration::Axiom {
1037 name: Name::str("ComplexAnalysis.argument_principle"),
1038 univ_params: vec![],
1039 ty: argument_principle_ty(),
1040 });
1041 let _ = env.add(Declaration::Axiom {
1042 name: Name::str("ComplexAnalysis.rouche"),
1043 univ_params: vec![],
1044 ty: rouche_theorem_ty(),
1045 });
1046 let _ = env.add(Declaration::Axiom {
1047 name: Name::str("ComplexAnalysis.mittag_leffler"),
1048 univ_params: vec![],
1049 ty: mittag_leffler_theorem_ty(),
1050 });
1051 let _ = env.add(Declaration::Axiom {
1052 name: Name::str("ComplexAnalysis.runge"),
1053 univ_params: vec![],
1054 ty: runge_theorem_ty(),
1055 });
1056 let _ = env.add(Declaration::Axiom {
1057 name: Name::str("ComplexAnalysis.hardy_banach"),
1058 univ_params: vec![],
1059 ty: hardy_banach_ty(),
1060 });
1061 let _ = env.add(Declaration::Axiom {
1062 name: Name::str("ComplexAnalysis.nevanlinna_first"),
1063 univ_params: vec![],
1064 ty: nevanlinna_first_theorem_ty(),
1065 });
1066 let _ = env.add(Declaration::Axiom {
1067 name: Name::str("ComplexAnalysis.nevanlinna_second"),
1068 univ_params: vec![],
1069 ty: nevanlinna_second_theorem_ty(),
1070 });
1071 let _ = env.add(Declaration::Axiom {
1072 name: Name::str("ComplexAnalysis.bloch"),
1073 univ_params: vec![],
1074 ty: bloch_theorem_ty(),
1075 });
1076 let _ = env.add(Declaration::Axiom {
1077 name: Name::str("ComplexAnalysis.weierstrass_p_elliptic"),
1078 univ_params: vec![],
1079 ty: weierstrass_p_ty(),
1080 });
1081 let _ = env.add(Declaration::Axiom {
1082 name: Name::str("ComplexAnalysis.elliptic_liouville"),
1083 univ_params: vec![],
1084 ty: elliptic_liouville_ty(),
1085 });
1086 let _ = env.add(Declaration::Axiom {
1087 name: Name::str("ComplexAnalysis.modular_form_finite_dim"),
1088 univ_params: vec![],
1089 ty: modular_form_finite_dim_ty(),
1090 });
1091 let _ = env.add(Declaration::Axiom {
1092 name: Name::str("ComplexAnalysis.hartogs"),
1093 univ_params: vec![],
1094 ty: hartogs_theorem_ty(),
1095 });
1096 let _ = env.add(Declaration::Axiom {
1097 name: Name::str("ComplexAnalysis.oka"),
1098 univ_params: vec![],
1099 ty: oka_theorem_ty(),
1100 });
1101 let _ = env.add(Declaration::Axiom {
1102 name: Name::str("ComplexAnalysis.bohr"),
1103 univ_params: vec![],
1104 ty: bohr_theorem_ty(),
1105 });
1106 let _ = env.add(Declaration::Axiom {
1107 name: Name::str("ComplexAnalysis.paley_wiener"),
1108 univ_params: vec![],
1109 ty: paley_wiener_theorem_ty(),
1110 });
1111 let _ = env.add(Declaration::Axiom {
1112 name: Name::str("ComplexAnalysis.hadamard_factorization"),
1113 univ_params: vec![],
1114 ty: hadamard_factorization_ty(),
1115 });
1116 let _ = env.add(Declaration::Axiom {
1117 name: Name::str("ComplexAnalysis.schwarz_pick"),
1118 univ_params: vec![],
1119 ty: schwarz_pick_lemma_ty(),
1120 });
1121 let _ = env.add(Declaration::Axiom {
1122 name: Name::str("ComplexAnalysis.jensen_formula"),
1123 univ_params: vec![],
1124 ty: jensen_formula_ty(),
1125 });
1126 let _ = env.add(Declaration::Axiom {
1127 name: Name::str("ComplexAnalysis.phragmen_lindelof"),
1128 univ_params: vec![],
1129 ty: phragmen_lindelof_ty(),
1130 });
1131 let _ = env.add(Declaration::Axiom {
1132 name: Name::str("ComplexAnalysis.riemann_zeta_meromorphic"),
1133 univ_params: vec![],
1134 ty: riemann_zeta_meromorphic_ty(),
1135 });
1136 let _ = env.add(Declaration::Axiom {
1137 name: Name::str("ComplexAnalysis.riemann_hypothesis"),
1138 univ_params: vec![],
1139 ty: riemann_hypothesis_ty(),
1140 });
1141 Ok(())
1142}
1143#[allow(dead_code)]
1147pub fn contour_integrate_circular<F>(f: F, center: Complex, radius: f64, n_points: usize) -> Complex
1148where
1149 F: Fn(Complex) -> Complex,
1150{
1151 if n_points == 0 {
1152 return Complex::zero();
1153 }
1154 let mut sum = Complex::zero();
1155 for k in 0..n_points {
1156 let theta = 2.0 * PI * k as f64 / n_points as f64;
1157 let z = center.add(Complex::from_polar(radius, theta));
1158 let dz = Complex::from_polar(radius, theta + PI / 2.0).scale(2.0 * PI / n_points as f64);
1159 sum = sum.add(f(z).mul(dz));
1160 }
1161 sum
1162}
1163#[allow(dead_code)]
1165pub fn dft(signal: &[Complex]) -> Vec<Complex> {
1166 let n = signal.len();
1167 if n == 0 {
1168 return vec![];
1169 }
1170 (0..n)
1171 .map(|k| {
1172 (0..n)
1173 .map(|j| {
1174 let angle = -2.0 * PI * k as f64 * j as f64 / n as f64;
1175 signal[j].mul(Complex::from_polar(1.0, angle))
1176 })
1177 .fold(Complex::zero(), |acc, x| acc.add(x))
1178 })
1179 .collect()
1180}
1181#[allow(dead_code)]
1183pub fn idft(spectrum: &[Complex]) -> Vec<Complex> {
1184 let n = spectrum.len();
1185 if n == 0 {
1186 return vec![];
1187 }
1188 let scale = 1.0 / n as f64;
1189 (0..n)
1190 .map(|j| {
1191 (0..n)
1192 .map(|k| {
1193 let angle = 2.0 * PI * k as f64 * j as f64 / n as f64;
1194 spectrum[k].mul(Complex::from_polar(1.0, angle))
1195 })
1196 .fold(Complex::zero(), |acc, x| acc.add(x))
1197 .scale(scale)
1198 })
1199 .collect()
1200}
1201#[allow(dead_code)]
1203pub fn fft(signal: &[Complex]) -> Vec<Complex> {
1204 let n = signal.len();
1205 if n <= 1 {
1206 return signal.to_vec();
1207 }
1208 if n & (n - 1) != 0 {
1209 return dft(signal);
1210 }
1211 let evens: Vec<Complex> = signal.iter().step_by(2).cloned().collect();
1212 let odds: Vec<Complex> = signal.iter().skip(1).step_by(2).cloned().collect();
1213 let mut e = fft(&evens);
1214 let mut o = fft(&odds);
1215 e.resize(n, Complex::zero());
1216 o.resize(n, Complex::zero());
1217 let mut result = vec![Complex::zero(); n];
1218 let half = n / 2;
1219 for k in 0..half {
1220 let twiddle = Complex::from_polar(1.0, -2.0 * PI * k as f64 / n as f64);
1221 let t = twiddle.mul(o[k]);
1222 result[k] = e[k].add(t);
1223 result[k + half] = e[k].sub(t);
1224 }
1225 result
1226}
1227#[allow(dead_code)]
1230pub fn newton_method<F, Df>(f: F, df: Df, z0: Complex, max_iter: usize, tol: f64) -> Option<Complex>
1231where
1232 F: Fn(Complex) -> Complex,
1233 Df: Fn(Complex) -> Complex,
1234{
1235 let mut z = z0;
1236 for _ in 0..max_iter {
1237 let fz = f(z);
1238 if fz.abs() < tol {
1239 return Some(z);
1240 }
1241 let dfz = df(z);
1242 z = z.sub(fz.div(dfz)?);
1243 }
1244 if f(z).abs() < tol {
1245 Some(z)
1246 } else {
1247 None
1248 }
1249}
1250#[allow(dead_code)]
1253pub fn mandelbrot_iter(c: Complex, max_iter: usize) -> Option<usize> {
1254 let mut z = Complex::zero();
1255 for i in 0..max_iter {
1256 if z.norm_sq() > 4.0 {
1257 return Some(i);
1258 }
1259 z = z.mul(z).add(c);
1260 }
1261 None
1262}
1263#[allow(dead_code)]
1266pub fn mandelbrot_ascii(
1267 re_min: f64,
1268 re_max: f64,
1269 im_min: f64,
1270 im_max: f64,
1271 width: usize,
1272 height: usize,
1273 max_iter: usize,
1274) -> Vec<String> {
1275 let chars: Vec<char> = " .:-=+*#%@".chars().collect();
1276 let n_chars = chars.len();
1277 (0..height)
1278 .map(|row| {
1279 let im = im_max - (im_max - im_min) * row as f64 / height as f64;
1280 (0..width)
1281 .map(|col| {
1282 let re = re_min + (re_max - re_min) * col as f64 / width as f64;
1283 let c = Complex::new(re, im);
1284 let idx = match mandelbrot_iter(c, max_iter) {
1285 None => n_chars - 1,
1286 Some(i) => (i * (n_chars - 1) / max_iter).min(n_chars - 2),
1287 };
1288 chars[idx]
1289 })
1290 .collect()
1291 })
1292 .collect()
1293}
1294#[allow(dead_code)]
1296pub fn sieve_of_eratosthenes(count: usize) -> Vec<u64> {
1297 if count == 0 {
1298 return vec![];
1299 }
1300 let limit = ((count as f64 * (count as f64).max(2.0).ln() * 1.3) as usize).max(20);
1301 let mut is_prime = vec![true; limit + 1];
1302 is_prime[0] = false;
1303 if limit >= 1 {
1304 is_prime[1] = false;
1305 }
1306 let mut i = 2usize;
1307 while i * i <= limit {
1308 if is_prime[i] {
1309 let mut j = i * i;
1310 while j <= limit {
1311 is_prime[j] = false;
1312 j += i;
1313 }
1314 }
1315 i += 1;
1316 }
1317 is_prime
1318 .iter()
1319 .enumerate()
1320 .filter(|(_, &p)| p)
1321 .map(|(i, _)| i as u64)
1322 .take(count)
1323 .collect()
1324}
1325#[allow(dead_code)]
1328pub fn riemann_zeta_approx(s: Complex, n_terms: usize) -> Complex {
1329 (1..=n_terms)
1330 .map(|n| {
1331 let log_n = Complex::new((n as f64).ln(), 0.0);
1332 s.neg().mul(log_n).exp()
1333 })
1334 .fold(Complex::zero(), |acc, x| acc.add(x))
1335}
1336#[allow(dead_code)]
1338pub fn riemann_zeta_euler_product(s: Complex, n_primes: usize) -> Complex {
1339 let primes = sieve_of_eratosthenes(n_primes);
1340 primes.iter().fold(Complex::one(), |acc, &p| {
1341 let log_p = Complex::new((p as f64).ln(), 0.0);
1342 let p_neg_s = s.neg().mul(log_p).exp();
1343 let denom = Complex::one().sub(p_neg_s);
1344 match Complex::one().div(denom) {
1345 Some(factor) => acc.mul(factor),
1346 None => acc,
1347 }
1348 })
1349}
1350#[cfg(test)]
1351mod tests {
1352 use super::*;
1353 use std::f64::consts::E;
1354 const EPS: f64 = 1e-10;
1355 #[test]
1356 fn test_complex_add() {
1357 let z = Complex::new(1.0, 2.0);
1358 let w = Complex::new(3.0, -1.0);
1359 let sum = z + w;
1360 assert!((sum.re - 4.0).abs() < EPS);
1361 assert!((sum.im - 1.0).abs() < EPS);
1362 }
1363 #[test]
1364 fn test_complex_mul() {
1365 let z = Complex::new(1.0, 2.0);
1366 let w = Complex::new(3.0, 4.0);
1367 let prod = z * w;
1368 assert!((prod.re - (-5.0)).abs() < EPS);
1369 assert!((prod.im - 10.0).abs() < EPS);
1370 }
1371 #[test]
1372 fn test_complex_conj() {
1373 let z = Complex::new(3.0, 4.0);
1374 let c = z.conj();
1375 assert!((c.re - 3.0).abs() < EPS);
1376 assert!((c.im - (-4.0)).abs() < EPS);
1377 }
1378 #[test]
1379 fn test_complex_abs() {
1380 let z = Complex::new(3.0, 4.0);
1381 assert!((z.abs() - 5.0).abs() < EPS);
1382 }
1383 #[test]
1384 fn test_complex_div() {
1385 let z = Complex::new(1.0, 0.0);
1386 let w = Complex::new(0.0, 1.0);
1387 let q = z.div(w).expect("div operation should succeed");
1388 assert!((q.re - 0.0).abs() < EPS);
1389 assert!((q.im - (-1.0)).abs() < EPS);
1390 }
1391 #[test]
1392 fn test_euler_formula() {
1393 let theta = PI;
1394 let z = Complex::new(0.0, theta).exp();
1395 assert!((z.re - (-1.0)).abs() < 1e-10);
1396 assert!(z.im.abs() < 1e-10);
1397 }
1398 #[test]
1399 fn test_euler_e_to_half_pi_i() {
1400 let z = Complex::new(0.0, PI / 2.0).exp();
1401 assert!(z.re.abs() < 1e-10);
1402 assert!((z.im - 1.0).abs() < 1e-10);
1403 }
1404 #[test]
1405 fn test_complex_exp_real() {
1406 let z = Complex::new(1.0, 0.0).exp();
1407 assert!((z.re - E).abs() < EPS);
1408 assert!(z.im.abs() < EPS);
1409 }
1410 #[test]
1411 fn test_complex_log_inverse() {
1412 let z = Complex::new(1.0, 1.0);
1413 let log_z = z.log().expect("log should succeed");
1414 let exp_log_z = log_z.exp();
1415 assert!((exp_log_z.re - z.re).abs() < EPS);
1416 assert!((exp_log_z.im - z.im).abs() < EPS);
1417 }
1418 #[test]
1419 fn test_complex_sqrt() {
1420 let z = Complex::new(-1.0, 0.0);
1421 let s = z.sqrt();
1422 assert!(s.re.abs() < EPS);
1423 assert!((s.im - 1.0).abs() < EPS);
1424 }
1425 #[test]
1426 fn test_complex_powi() {
1427 let z = Complex::i();
1428 let z2 = z.powi(2);
1429 assert!((z2.re - (-1.0)).abs() < EPS);
1430 assert!(z2.im.abs() < EPS);
1431 let z4 = z.powi(4);
1432 assert!((z4.re - 1.0).abs() < EPS);
1433 assert!(z4.im.abs() < EPS);
1434 }
1435 #[test]
1436 fn test_roots_of_unity() {
1437 let roots = Complex::roots_of_unity(4);
1438 assert_eq!(roots.len(), 4);
1439 for r in &roots {
1440 assert!((r.abs() - 1.0).abs() < EPS);
1441 }
1442 for r in &roots {
1443 let r4 = r.powi(4);
1444 assert!((r4.re - 1.0).abs() < EPS);
1445 assert!(r4.im.abs() < EPS);
1446 }
1447 }
1448 #[test]
1449 fn test_nth_roots() {
1450 let one = Complex::one();
1451 let roots = one.nth_roots(3);
1452 assert_eq!(roots.len(), 3);
1453 for r in &roots {
1454 let r3 = r.powi(3);
1455 assert!((r3.re - 1.0).abs() < EPS, "r^3 ≠ 1: {:?}", r3);
1456 assert!(r3.im.abs() < EPS, "r^3.im ≠ 0: {:?}", r3.im);
1457 }
1458 }
1459 #[test]
1460 fn test_complex_cos_sin() {
1461 let z = Complex::zero();
1462 assert!((z.cos().re - 1.0).abs() < EPS);
1463 assert!(z.sin().re.abs() < EPS);
1464 let pi_z = Complex::new(PI, 0.0);
1465 assert!((pi_z.cos().re - (-1.0)).abs() < EPS);
1466 }
1467 #[test]
1468 fn test_polar_roundtrip() {
1469 let z = Complex::new(3.0, 4.0);
1470 let (r, theta) = z.to_polar();
1471 let z2 = Complex::from_polar(r, theta);
1472 assert!((z2.re - z.re).abs() < EPS);
1473 assert!((z2.im - z.im).abs() < EPS);
1474 }
1475 #[test]
1476 fn test_sinh_cosh() {
1477 let z = Complex::new(1.0, 0.0);
1478 let c2 = z.cosh().mul(z.cosh());
1479 let s2 = z.sinh().mul(z.sinh());
1480 let diff = c2.sub(s2);
1481 assert!((diff.re - 1.0).abs() < EPS);
1482 assert!(diff.im.abs() < EPS);
1483 }
1484 #[test]
1485 fn test_asin_sin_roundtrip() {
1486 let z = Complex::new(0.5, 0.3);
1487 let sin_z = z.sin();
1488 let asin_sin_z = sin_z.asin().expect("asin should succeed");
1489 assert!((asin_sin_z.re - z.re).abs() < 1e-9);
1490 assert!((asin_sin_z.im - z.im).abs() < 1e-9);
1491 }
1492 #[test]
1493 fn test_acos_cos_roundtrip() {
1494 let z = Complex::new(0.7, 0.0);
1495 let cos_z = z.cos();
1496 let acos_cos_z = cos_z.acos().expect("acos should succeed");
1497 assert!((acos_cos_z.re - z.re).abs() < 1e-9);
1498 assert!(acos_cos_z.im.abs() < 1e-9);
1499 }
1500 #[test]
1501 fn test_atan_roundtrip() {
1502 let z = Complex::new(0.3, 0.2);
1503 let atan_z = z.atan().expect("atan should succeed");
1504 let tan_atan_z = atan_z.tan().expect("tan should succeed");
1505 assert!((tan_atan_z.re - z.re).abs() < 1e-9);
1506 assert!((tan_atan_z.im - z.im).abs() < 1e-9);
1507 }
1508 #[test]
1509 fn test_dft_idft_roundtrip() {
1510 let signal = vec![
1511 Complex::new(1.0, 0.0),
1512 Complex::new(0.0, 1.0),
1513 Complex::new(-1.0, 0.0),
1514 Complex::new(0.0, -1.0),
1515 ];
1516 let spectrum = dft(&signal);
1517 let recovered = idft(&spectrum);
1518 assert_eq!(recovered.len(), signal.len());
1519 for (a, b) in signal.iter().zip(recovered.iter()) {
1520 assert!(
1521 a.approx_eq(*b, 1e-10),
1522 "DFT/IDFT roundtrip failed: {:?} vs {:?}",
1523 a,
1524 b
1525 );
1526 }
1527 }
1528 #[test]
1529 fn test_fft_matches_dft() {
1530 let signal: Vec<Complex> = (0u32..8)
1531 .map(|k| Complex::from_polar(1.0, 2.0 * PI * k as f64 / 8.0))
1532 .collect();
1533 let dft_result = dft(&signal);
1534 let fft_result = fft(&signal);
1535 assert_eq!(dft_result.len(), fft_result.len());
1536 for (a, b) in dft_result.iter().zip(fft_result.iter()) {
1537 assert!(
1538 a.approx_eq(*b, 1e-9),
1539 "FFT/DFT mismatch: {:?} vs {:?}",
1540 a,
1541 b
1542 );
1543 }
1544 }
1545 #[test]
1546 fn test_newton_method_sqrt2() {
1547 let root = newton_method(
1548 |z| z.mul(z).sub(Complex::new(2.0, 0.0)),
1549 |z| z.scale(2.0),
1550 Complex::new(1.5, 0.0),
1551 50,
1552 1e-12,
1553 );
1554 let r = root.expect("Newton should converge");
1555 assert!((r.re - 2.0_f64.sqrt()).abs() < 1e-10);
1556 assert!(r.im.abs() < 1e-10);
1557 }
1558 #[test]
1559 fn test_newton_method_complex_root() {
1560 let root = newton_method(
1561 |z| z.mul(z).add(Complex::one()),
1562 |z| z.scale(2.0),
1563 Complex::new(0.1, 1.0),
1564 50,
1565 1e-12,
1566 );
1567 let r = root.expect("Newton should converge to i");
1568 assert!(r.re.abs() < 1e-10);
1569 assert!((r.im - 1.0).abs() < 1e-10);
1570 }
1571 #[test]
1572 fn test_mandelbrot_zero_in_set() {
1573 assert_eq!(mandelbrot_iter(Complex::zero(), 100), None);
1574 }
1575 #[test]
1576 fn test_mandelbrot_large_escape() {
1577 let result = mandelbrot_iter(Complex::new(2.5, 0.0), 100);
1578 assert!(result.is_some());
1579 }
1580 #[test]
1581 fn test_riemann_zeta_s2() {
1582 let s = Complex::new(2.0, 0.0);
1583 let zeta = riemann_zeta_approx(s, 10_000);
1584 let expected = PI * PI / 6.0;
1585 assert!((zeta.re - expected).abs() < 0.01, "ζ(2) ≈ {}", zeta.re);
1586 assert!(zeta.im.abs() < 0.01);
1587 }
1588 #[test]
1589 fn test_sieve_first_primes() {
1590 let primes = sieve_of_eratosthenes(5);
1591 assert_eq!(primes, vec![2, 3, 5, 7, 11]);
1592 }
1593 #[test]
1594 fn test_mobius_identity() {
1595 let id = MobiusTransform::identity();
1596 let z = Complex::new(2.0, 3.0);
1597 let result = id.apply(z).expect("apply should succeed");
1598 assert!(result.approx_eq(z, EPS));
1599 }
1600 #[test]
1601 fn test_mobius_compose_invert() {
1602 let f = MobiusTransform::new(
1603 Complex::one(),
1604 Complex::one(),
1605 Complex::one(),
1606 Complex::new(2.0, 0.0),
1607 )
1608 .expect("operation should succeed");
1609 let f_inv = f.invert().expect("invert should succeed");
1610 let z = Complex::new(1.0, 1.0);
1611 let round = f
1612 .apply(z)
1613 .and_then(|w| f_inv.apply(w))
1614 .expect("Complex::new should succeed");
1615 assert!(round.approx_eq(z, 1e-10));
1616 }
1617 #[test]
1618 fn test_mobius_fixed_points() {
1619 let f = MobiusTransform::new(
1620 Complex::zero(),
1621 Complex::one(),
1622 Complex::one(),
1623 Complex::zero(),
1624 )
1625 .expect("operation should succeed");
1626 let fps = f.fixed_points();
1627 assert_eq!(fps.len(), 2);
1628 for fp in &fps {
1629 let fz = f.apply(*fp).expect("apply should succeed");
1630 assert!(fz.approx_eq(*fp, 1e-10), "fixed point check: {:?}", fp);
1631 }
1632 }
1633 #[test]
1634 fn test_contour_integral_constant() {
1635 let integral = contour_integrate_circular(|_| Complex::one(), Complex::zero(), 1.0, 1024);
1636 assert!(integral.abs() < 1e-10, "∮ 1 dz ≠ 0: {:?}", integral);
1637 }
1638 #[test]
1639 fn test_build_complex_env() {
1640 let mut env = Environment::new();
1641 let _ = env.add(Declaration::Axiom {
1642 name: Name::str("Real"),
1643 univ_params: vec![],
1644 ty: type0(),
1645 });
1646 let _ = env.add(Declaration::Axiom {
1647 name: Name::str("Nat"),
1648 univ_params: vec![],
1649 ty: type0(),
1650 });
1651 let _ = env.add(Declaration::Axiom {
1652 name: Name::str("Polynomial"),
1653 univ_params: vec![],
1654 ty: arrow(type0(), type0()),
1655 });
1656 let _ = env.add(Declaration::Axiom {
1657 name: Name::str("IsEntire"),
1658 univ_params: vec![],
1659 ty: impl_pi(
1660 "alpha",
1661 type0(),
1662 arrow(arrow(complex_ty(), complex_ty()), prop()),
1663 ),
1664 });
1665 let _ = env.add(Declaration::Axiom {
1666 name: Name::str("IsBounded"),
1667 univ_params: vec![],
1668 ty: impl_pi(
1669 "alpha",
1670 type0(),
1671 arrow(arrow(complex_ty(), complex_ty()), prop()),
1672 ),
1673 });
1674 let _ = env.add(Declaration::Axiom {
1675 name: Name::str("IsConstant"),
1676 univ_params: vec![],
1677 ty: impl_pi(
1678 "alpha",
1679 type0(),
1680 arrow(arrow(complex_ty(), complex_ty()), prop()),
1681 ),
1682 });
1683 let _ = env.add(Declaration::Axiom {
1684 name: Name::str("IsHolomorphic"),
1685 univ_params: vec![],
1686 ty: arrow(arrow(complex_ty(), complex_ty()), prop()),
1687 });
1688 let _ = env.add(Declaration::Axiom {
1689 name: Name::str("ClosedCurve"),
1690 univ_params: vec![],
1691 ty: arrow(type0(), type0()),
1692 });
1693 let _ = env.add(Declaration::Axiom {
1694 name: Name::str("ContourIntegral"),
1695 univ_params: vec![],
1696 ty: arrow(
1697 arrow(complex_ty(), complex_ty()),
1698 arrow(app(cst("ClosedCurve"), complex_ty()), complex_ty()),
1699 ),
1700 });
1701 let _ = env.add(Declaration::Axiom {
1702 name: Name::str("rootsOfUnity"),
1703 univ_params: vec![],
1704 ty: arrow(nat_ty(), type0()),
1705 });
1706 let _ = env.add(Declaration::Axiom {
1707 name: Name::str("Fintype.card"),
1708 univ_params: vec![],
1709 ty: arrow(type0(), nat_ty()),
1710 });
1711 let _ = env.add(Declaration::Axiom {
1712 name: Name::str("Polynomial.degree_pos"),
1713 univ_params: vec![],
1714 ty: impl_pi(
1715 "alpha",
1716 type0(),
1717 arrow(app(cst("Polynomial"), bvar(0)), prop()),
1718 ),
1719 });
1720 let _ = env.add(Declaration::Axiom {
1721 name: Name::str("Polynomial.eval"),
1722 univ_params: vec![],
1723 ty: impl_pi(
1724 "alpha",
1725 type0(),
1726 arrow(app(cst("Polynomial"), bvar(0)), arrow(bvar(0), bvar(0))),
1727 ),
1728 });
1729 let _ = env.add(Declaration::Axiom {
1730 name: Name::str("Real.ofNat"),
1731 univ_params: vec![],
1732 ty: arrow(nat_ty(), real_ty()),
1733 });
1734 let result = build_complex_env(&mut env);
1735 assert!(result.is_ok());
1736 }
1737}
1738#[allow(dead_code)]
1740pub fn cauchy_integral_approx<F>(f: F, center: C64, radius: f64, n_points: usize) -> C64
1741where
1742 F: Fn(C64) -> C64,
1743{
1744 let mut sum = C64::zero();
1745 let dt = 2.0 * std::f64::consts::PI / n_points as f64;
1746 for k in 0..n_points {
1747 let t = k as f64 * dt;
1748 let z = center.add(&C64::from_polar(radius, t));
1749 let fz = f(z);
1750 let dz = C64::new(-radius * t.sin(), radius * t.cos());
1751 sum = sum.add(&fz.mul(&dz));
1752 }
1753 let factor = C64::new(0.0, -1.0 / (2.0 * std::f64::consts::PI));
1754 let result = sum.mul(&factor);
1755 C64::new(result.re * dt, result.im * dt)
1756}