1#![deny(rustdoc::broken_intra_doc_links)]
2
3use crate::{
9 FpScalar, RealScalar,
10 core::traits::{raw::RawScalarValidate, validation::sealed::NativeReal},
11 functions::FunctionErrors,
12 kernels::{PrecisionBits, RawComplexTrait, RawScalarTrait},
13};
14use num::Complex;
15use std::backtrace::Backtrace;
16use thiserror::Error;
17use try_create::IntoInner;
18
19#[cfg(debug_assertions)]
20use crate::core::errors::capture_backtrace;
21
22#[cfg(debug_assertions)]
23use num::Zero;
24
25pub trait ComplexScalarConstructors: FpScalar<InnerType = Self::RawComplex> {
46 type RawComplex: RawComplexTrait<RawReal = <Self::RealType as RealScalar>::RawReal>;
48
49 #[must_use = "this `Result` may contain an error that should be handled"]
53 fn try_new_complex(
54 real: <Self::RawComplex as RawComplexTrait>::RawReal,
55 imag: <Self::RawComplex as RawComplexTrait>::RawReal,
56 ) -> Result<Self, <Self::RawComplex as RawScalarValidate>::ValidationError>;
57
58 fn new_complex(real: Self::RealType, imag: Self::RealType) -> Self {
60 Self::try_new_complex(real.into_inner(), imag.into_inner()).unwrap()
61 }
62
63 #[must_use = "this `Result` may contain an error that should be handled"]
65 fn try_new_pure_real(
66 real_part: <Self::RawComplex as RawComplexTrait>::RawReal,
67 ) -> Result<Self, <Self::RawComplex as RawScalarValidate>::ValidationError> {
68 let zero =
69 <Self::RawComplex as RawComplexTrait>::RawReal::raw_zero(real_part.precision_bits());
70 Self::try_new_complex(real_part, zero)
71 }
72
73 #[must_use = "this `Result` may contain an error that should be handled"]
75 fn try_new_pure_imaginary(
76 imag_part: <Self::RawComplex as RawComplexTrait>::RawReal,
77 ) -> Result<Self, <Self::RawComplex as RawScalarValidate>::ValidationError> {
78 let zero =
79 <Self::RawComplex as RawComplexTrait>::RawReal::raw_zero(imag_part.precision_bits());
80 Self::try_new_complex(zero, imag_part)
81 }
82
83 fn new_pure_real(real_part: Self::RealType) -> Self {
90 Self::try_new_pure_real(real_part.into_inner()).unwrap()
91 }
92
93 fn new_pure_imaginary(imag_part: Self::RealType) -> Self {
100 Self::try_new_pure_imaginary(imag_part.into_inner()).unwrap()
101 }
102}
103
104pub trait ComplexScalarGetParts: ComplexScalarConstructors {
128 fn real_part(&self) -> Self::RealType;
130
131 fn imag_part(&self) -> Self::RealType;
133
134 fn raw_real_part(&self) -> &<Self::RealType as RealScalar>::RawReal;
136
137 fn raw_imag_part(&self) -> &<Self::RealType as RealScalar>::RawReal;
139
140 fn is_pure_real(&self) -> bool {
144 self.raw_imag_part().is_zero()
145 }
146
147 fn is_pure_imaginary(&self) -> bool {
151 self.raw_real_part().is_zero() && !self.raw_imag_part().is_zero()
152 }
153}
154
155pub trait ComplexScalarSetParts: ComplexScalarGetParts {
176 fn set_real_part(&mut self, real_part: Self::RealType);
178
179 fn set_imaginary_part(&mut self, imag_part: Self::RealType);
181
182 fn with_real_part(mut self, real_part: Self::RealType) -> Self {
184 self.set_real_part(real_part);
185 self
186 }
187
188 fn with_imaginary_part(mut self, imag_part: Self::RealType) -> Self {
190 self.set_imaginary_part(imag_part);
191 self
192 }
193}
194
195pub trait ComplexScalarMutateParts: ComplexScalarSetParts {
226 fn add_to_real_part(&mut self, c: &Self::RealType);
228
229 fn add_to_imaginary_part(&mut self, c: &Self::RealType);
231
232 fn multiply_real_part(&mut self, c: &Self::RealType);
234
235 fn multiply_imaginary_part(&mut self, c: &Self::RealType);
237}
238
239pub trait Conjugate: Sized {
281 fn conjugate(self) -> Self;
283}
284
285impl<T: NativeReal> Conjugate for Complex<T> {
286 #[inline(always)]
287 fn conjugate(self) -> Self {
288 self.conj()
289 }
290}
291
292#[derive(Debug, Error)]
307pub enum ArgInputErrors<RawComplex: RawComplexTrait> {
308 #[error("the input complex number is invalid according to validation policy")]
315 ValidationError {
316 #[source]
321 #[backtrace]
322 source: <RawComplex as RawScalarValidate>::ValidationError,
323 },
324
325 #[error("the input value is zero!")]
330 Zero {
331 backtrace: Backtrace,
333 },
334}
335
336pub type ArgErrors<RawComplex> = FunctionErrors<
364 ArgInputErrors<RawComplex>,
365 <<RawComplex as RawComplexTrait>::RawReal as RawScalarValidate>::ValidationError,
366>;
367
368pub trait Arg: Sized {
377 type Output: Sized;
380
381 type Error: std::error::Error;
385
386 #[must_use = "this `Result` may contain an error that should be handled"]
388 fn try_arg(self) -> Result<Self::Output, Self::Error>;
389
390 fn arg(self) -> Self::Output;
392}
393
394impl<T> Arg for Complex<T>
395where
396 Self: RawComplexTrait<RawReal = T>,
397 T: NativeReal,
398{
399 type Output = T;
400
401 type Error = ArgErrors<Complex<T>>;
402
403 #[inline(always)]
439 fn try_arg(self) -> Result<Self::Output, Self::Error> {
440 #[cfg(debug_assertions)]
441 {
442 self.validate_raw_scalar()
443 .map_err(|e| Self::Error::Input(ArgInputErrors::ValidationError { source: e }))
444 .and_then(|v: Complex<T>| {
445 if <Complex<T> as Zero>::is_zero(&v) {
446 Err(Self::Error::Input(ArgInputErrors::Zero {
447 backtrace: capture_backtrace(),
448 }))
449 } else {
450 Complex::<T>::arg(v)
451 .validate_raw_scalar()
452 .map_err(|e| Self::Error::Output { source: e })
453 }
454 })
455 }
456 #[cfg(not(debug_assertions))]
457 {
458 Ok(Complex::<T>::arg(self))
459 }
460 }
461
462 #[inline(always)]
492 fn arg(self) -> T {
493 #[cfg(debug_assertions)]
494 {
495 self.try_arg()
496 .expect("Error calling Arg::try_arg() inside Arg::arg() debug mode.")
497 }
498 #[cfg(not(debug_assertions))]
499 {
500 Complex::<T>::arg(self)
501 }
502 }
503}
504
505#[cfg(test)]
509mod tests {
510 use super::*;
511 use crate::{ComplexScalar, core::errors::ErrorsValidationRawComplex};
512 use num::Complex;
513 use try_create::TryNew;
514
515 mod native_f64 {
516 use super::*;
517 use crate::backends::native::validated::{
518 ComplexNative64StrictFinite, RealNative64StrictFinite,
519 };
520 use std::f64::consts::*;
521
522 #[test]
523 fn conjugate() {
524 let z = Complex::new(1.0, -2.0);
525 let expected_conjugate = Complex::new(1.0, 2.0);
526 assert_eq!(z.conjugate(), expected_conjugate);
527
528 let z = Complex::new(-3.0, 4.0);
529 let expected_conjugate = Complex::new(-3.0, -4.0);
530 assert_eq!(z.conjugate(), expected_conjugate);
531
532 let z_zero = Complex::new(0.0, 0.0);
535 assert_eq!(z_zero.conjugate(), Complex::new(0.0, 0.0));
536 let z_real = Complex::new(5.0, 0.0);
538 assert_eq!(z_real.conjugate(), Complex::new(5.0, 0.0));
539 let z_imag = Complex::new(0.0, 5.0);
541 assert_eq!(z_imag.conjugate(), Complex::new(0.0, -5.0));
542 let z_neg_imag = Complex::new(0.0, -5.0);
543 assert_eq!(z_neg_imag.conjugate(), Complex::new(0.0, 5.0));
544 }
545
546 #[test]
547 fn arg() {
548 let z = Complex::new(1.0, 1.0);
549 let expected_arg = std::f64::consts::FRAC_PI_4; assert_eq!(z.arg(), expected_arg);
551
552 let z_pos_real = Complex::new(1.0, 0.0);
554 assert_eq!(z_pos_real.arg(), 0.0);
555 let z_neg_real = Complex::new(-1.0, 0.0);
556 assert_eq!(z_neg_real.arg(), PI);
557 let z_pos_imag = Complex::new(0.0, 1.0);
558 assert_eq!(z_pos_imag.arg(), FRAC_PI_2);
559 let z_neg_imag = Complex::new(0.0, -1.0);
560 assert_eq!(z_neg_imag.arg(), -FRAC_PI_2);
561
562 let z2 = Complex::new(-1.0, 1.0); assert_eq!(z2.arg(), 3.0 * FRAC_PI_4);
565 let z3 = Complex::new(-1.0, -1.0); assert_eq!(z3.arg(), -3.0 * FRAC_PI_4);
567 let z4 = Complex::new(1.0, -1.0); assert_eq!(z4.arg(), -FRAC_PI_4);
569 }
570
571 #[test]
572 #[cfg(debug_assertions)]
573 fn try_arg_invalid() {
574 let zero = Complex::new(0.0, 0.0);
575 assert!(matches!(
576 zero.try_arg(),
577 Err(ArgErrors::<Complex<f64>>::Input(
578 ArgInputErrors::Zero { .. }
579 ))
580 ));
581
582 let z_nan_re = Complex::new(f64::NAN, 1.0);
584 assert!(matches!(
585 z_nan_re.try_arg(),
586 Err(ArgErrors::<Complex<f64>>::Input(
587 ArgInputErrors::ValidationError {
588 source: ErrorsValidationRawComplex::InvalidRealPart { .. }
589 }
590 ))
591 ));
592 let z_nan_im = Complex::new(1.0, f64::NAN);
593 assert!(matches!(
594 z_nan_im.try_arg(),
595 Err(ArgErrors::<Complex<f64>>::Input(
596 ArgInputErrors::ValidationError {
597 source: ErrorsValidationRawComplex::InvalidImaginaryPart { .. }
598 }
599 ))
600 ));
601
602 let z_inf_re = Complex::new(f64::INFINITY, 1.0);
604 assert!(matches!(
605 z_inf_re.try_arg(),
606 Err(ArgErrors::<Complex<f64>>::Input(
607 ArgInputErrors::ValidationError {
608 source: ErrorsValidationRawComplex::InvalidRealPart { .. }
609 }
610 ))
611 ));
612 let z_inf_im = Complex::new(1.0, f64::INFINITY);
613 assert!(matches!(
614 z_inf_im.try_arg(),
615 Err(ArgErrors::<Complex<f64>>::Input(
616 ArgInputErrors::ValidationError {
617 source: ErrorsValidationRawComplex::InvalidImaginaryPart { .. }
618 }
619 ))
620 ));
621
622 }
636
637 #[test]
638 #[cfg(debug_assertions)]
639 #[should_panic]
640 fn arg_panics_on_zero_debug() {
641 let zero = Complex::new(0.0, 0.0);
642 let _ = Arg::arg(zero);
643 }
644
645 #[test]
646 #[cfg(debug_assertions)]
647 #[should_panic]
648 fn arg_panics_on_nan_debug() {
649 let nan = Complex::new(f64::NAN, 1.0);
650 let _ = Arg::arg(nan);
651 }
652
653 #[test]
654 #[cfg(debug_assertions)]
655 #[should_panic]
656 fn arg_panics_on_inf_debug() {
657 let inf = Complex::new(f64::INFINITY, 1.0);
658 let _ = Arg::arg(inf);
659 }
660
661 #[test]
662 #[cfg(not(debug_assertions))]
663 fn arg_behavior_release() {
664 let zero = Complex::new(0.0, 0.0);
666 assert_eq!(Arg::arg(zero), 0.0);
667
668 let nan_re = Complex::new(f64::NAN, 1.0);
670 assert!(Arg::arg(nan_re).is_nan());
671 let inf_re = Complex::new(f64::INFINITY, 0.0); assert_eq!(Arg::arg(inf_re), 0.0);
673 let inf_im = Complex::new(0.0, f64::INFINITY); assert_eq!(Arg::arg(inf_im), FRAC_PI_2);
675 let inf_both = Complex::new(f64::INFINITY, f64::INFINITY); assert_eq!(Arg::arg(inf_both), FRAC_PI_4);
677 }
678
679 #[test]
680 fn test_is_pure_real() {
681 let z_real = ComplexNative64StrictFinite::try_new_complex(5.0, 0.0).unwrap();
683 assert!(z_real.is_pure_real());
684 assert!(!z_real.is_pure_imaginary());
685
686 let z_zero = ComplexNative64StrictFinite::try_new_complex(0.0, 0.0).unwrap();
688 assert!(z_zero.is_pure_real());
689 assert!(!z_zero.is_pure_imaginary());
690
691 let z_complex = ComplexNative64StrictFinite::try_new_complex(3.0, 4.0).unwrap();
693 assert!(!z_complex.is_pure_real());
694 assert!(!z_complex.is_pure_imaginary());
695
696 let z_imag = ComplexNative64StrictFinite::try_new_complex(0.0, 5.0).unwrap();
698 assert!(!z_imag.is_pure_real());
699 assert!(z_imag.is_pure_imaginary());
700 }
701
702 #[test]
703 fn test_is_pure_imaginary() {
704 let z_imag = ComplexNative64StrictFinite::try_new_complex(0.0, 7.0).unwrap();
706 assert!(z_imag.is_pure_imaginary());
707 assert!(!z_imag.is_pure_real());
708
709 let z_neg_imag = ComplexNative64StrictFinite::try_new_complex(0.0, -3.0).unwrap();
711 assert!(z_neg_imag.is_pure_imaginary());
712
713 let z_zero = ComplexNative64StrictFinite::try_new_complex(0.0, 0.0).unwrap();
715 assert!(!z_zero.is_pure_imaginary());
716 assert!(z_zero.is_pure_real());
717 }
718
719 #[test]
720 fn test_with_real_part() {
721 let z = ComplexNative64StrictFinite::try_new_complex(3.0, 4.0).unwrap();
722 let new_real = RealNative64StrictFinite::try_new(10.0).unwrap();
723
724 let z_modified = z.with_real_part(new_real);
725 assert_eq!(*z_modified.raw_real_part(), 10.0);
726 assert_eq!(*z_modified.raw_imag_part(), 4.0);
727 }
728
729 #[test]
730 fn test_with_imaginary_part() {
731 let z = ComplexNative64StrictFinite::try_new_complex(3.0, 4.0).unwrap();
732 let new_imag = RealNative64StrictFinite::try_new(20.0).unwrap();
733
734 let z_modified = z.with_imaginary_part(new_imag);
735 assert_eq!(*z_modified.raw_real_part(), 3.0);
736 assert_eq!(*z_modified.raw_imag_part(), 20.0);
737 }
738
739 #[test]
740 fn test_new_pure_real() {
741 let real_part = RealNative64StrictFinite::try_new(7.0).unwrap();
742 let z = ComplexNative64StrictFinite::new_pure_real(real_part);
743
744 assert_eq!(*z.raw_real_part(), 7.0);
745 assert_eq!(*z.raw_imag_part(), 0.0);
746 assert!(z.is_pure_real());
747 }
748
749 #[test]
750 fn test_new_pure_imaginary() {
751 let imag_part = RealNative64StrictFinite::try_new(9.0).unwrap();
752 let z = ComplexNative64StrictFinite::new_pure_imaginary(imag_part);
753
754 assert_eq!(*z.raw_real_part(), 0.0);
755 assert_eq!(*z.raw_imag_part(), 9.0);
756 assert!(z.is_pure_imaginary());
757 }
758
759 #[test]
760 fn test_try_new_pure_real_valid() {
761 let z = ComplexNative64StrictFinite::try_new_pure_real(5.0).unwrap();
762 assert_eq!(*z.raw_real_part(), 5.0);
763 assert_eq!(*z.raw_imag_part(), 0.0);
764 }
765
766 #[test]
767 fn test_try_new_pure_real_invalid() {
768 let result = ComplexNative64StrictFinite::try_new_pure_real(f64::NAN);
770 assert!(result.is_err());
771
772 let result = ComplexNative64StrictFinite::try_new_pure_real(f64::INFINITY);
774 assert!(result.is_err());
775 }
776
777 #[test]
778 fn test_try_new_pure_imaginary_valid() {
779 let z = ComplexNative64StrictFinite::try_new_pure_imaginary(8.0).unwrap();
780 assert_eq!(*z.raw_real_part(), 0.0);
781 assert_eq!(*z.raw_imag_part(), 8.0);
782 }
783
784 #[test]
785 fn test_try_new_pure_imaginary_invalid() {
786 let result = ComplexNative64StrictFinite::try_new_pure_imaginary(f64::NAN);
788 assert!(result.is_err());
789
790 let result = ComplexNative64StrictFinite::try_new_pure_imaginary(f64::NEG_INFINITY);
792 assert!(result.is_err());
793 }
794
795 #[test]
796 fn test_into_parts_basic() {
797 let z = ComplexNative64StrictFinite::try_new_complex(3.0, 4.0).unwrap();
798
799 let (real, imag) = z.into_parts();
801
802 assert_eq!(*real.as_ref(), 3.0);
803 assert_eq!(*imag.as_ref(), 4.0);
804 }
805
806 #[test]
807 fn test_into_parts_zero() {
808 let z = ComplexNative64StrictFinite::try_new_complex(0.0, 0.0).unwrap();
809 let (real, imag) = z.into_parts();
810
811 assert_eq!(*real.as_ref(), 0.0);
812 assert_eq!(*imag.as_ref(), 0.0);
813 }
814
815 #[test]
816 fn test_into_parts_pure_real() {
817 let z = ComplexNative64StrictFinite::try_new_complex(7.5, 0.0).unwrap();
818 let (real, imag) = z.into_parts();
819
820 assert_eq!(*real.as_ref(), 7.5);
821 assert_eq!(*imag.as_ref(), 0.0);
822 }
823
824 #[test]
825 fn test_into_parts_pure_imaginary() {
826 let z = ComplexNative64StrictFinite::try_new_complex(0.0, -9.2).unwrap();
827 let (real, imag) = z.into_parts();
828
829 assert_eq!(*real.as_ref(), 0.0);
830 assert_eq!(*imag.as_ref(), -9.2);
831 }
832
833 #[test]
834 fn test_into_parts_negative() {
835 let z = ComplexNative64StrictFinite::try_new_complex(-5.5, -3.3).unwrap();
836 let (real, imag) = z.into_parts();
837
838 assert_eq!(*real.as_ref(), -5.5);
839 assert_eq!(*imag.as_ref(), -3.3);
840 }
841
842 #[test]
843 fn test_into_parts_parts_are_independent() {
844 let z = ComplexNative64StrictFinite::try_new_complex(10.0, 20.0).unwrap();
845 let (real, imag) = z.into_parts();
846
847 let two = RealNative64StrictFinite::try_new(2.0).unwrap();
849 let real_doubled = real * two;
850 let imag_halved = imag / two;
851
852 assert_eq!(*real_doubled.as_ref(), 20.0);
853 assert_eq!(*imag_halved.as_ref(), 10.0);
854 }
855 }
856
857 mod native_f32 {
858 use super::*;
859 use crate::backends::native::validated::{
860 ComplexNative32StrictFinite, RealNative32StrictFinite,
861 };
862 use std::f32::consts::*;
863
864 #[test]
865 fn conjugate() {
866 let z = Complex::new(1.0_f32, -2.0_f32);
867 let expected_conjugate = Complex::new(1.0_f32, 2.0_f32);
868 assert_eq!(z.conjugate(), expected_conjugate);
869
870 let z = Complex::new(-3.0_f32, 4.0_f32);
871 let expected_conjugate = Complex::new(-3.0_f32, -4.0_f32);
872 assert_eq!(z.conjugate(), expected_conjugate);
873
874 let z_zero = Complex::new(0.0_f32, 0.0_f32);
877 assert_eq!(z_zero.conjugate(), Complex::new(0.0_f32, 0.0_f32));
878 let z_real = Complex::new(5.0_f32, 0.0_f32);
880 assert_eq!(z_real.conjugate(), Complex::new(5.0_f32, 0.0_f32));
881 let z_imag = Complex::new(0.0_f32, 5.0_f32);
883 assert_eq!(z_imag.conjugate(), Complex::new(0.0_f32, -5.0_f32));
884 let z_neg_imag = Complex::new(0.0_f32, -5.0_f32);
885 assert_eq!(z_neg_imag.conjugate(), Complex::new(0.0_f32, 5.0_f32));
886 }
887
888 #[test]
889 fn arg() {
890 let z = Complex::new(1.0_f32, 1.0_f32);
891 let expected_arg = std::f32::consts::FRAC_PI_4; assert_eq!(z.arg(), expected_arg);
893
894 let z_pos_real = Complex::new(1.0_f32, 0.0_f32);
896 assert_eq!(z_pos_real.arg(), 0.0_f32);
897 let z_neg_real = Complex::new(-1.0_f32, 0.0_f32);
898 assert_eq!(z_neg_real.arg(), PI);
899 let z_pos_imag = Complex::new(0.0_f32, 1.0_f32);
900 assert_eq!(z_pos_imag.arg(), FRAC_PI_2);
901 let z_neg_imag = Complex::new(0.0_f32, -1.0_f32);
902 assert_eq!(z_neg_imag.arg(), -FRAC_PI_2);
903
904 let z2 = Complex::new(-1.0_f32, 1.0_f32); assert_eq!(z2.arg(), 3.0 * FRAC_PI_4);
907 let z3 = Complex::new(-1.0_f32, -1.0_f32); assert_eq!(z3.arg(), -3.0 * FRAC_PI_4);
909 let z4 = Complex::new(1.0_f32, -1.0_f32); assert_eq!(z4.arg(), -FRAC_PI_4);
911 }
912
913 #[test]
914 #[cfg(debug_assertions)]
915 fn try_arg_invalid() {
916 let zero = Complex::new(0.0_f32, 0.0_f32);
917 assert!(matches!(
918 zero.try_arg(),
919 Err(ArgErrors::<Complex<f32>>::Input(
920 ArgInputErrors::Zero { .. }
921 ))
922 ));
923
924 let z_nan_re = Complex::new(f32::NAN, 1.0_f32);
926 assert!(matches!(
927 z_nan_re.try_arg(),
928 Err(ArgErrors::<Complex<f32>>::Input(
929 ArgInputErrors::ValidationError {
930 source: ErrorsValidationRawComplex::InvalidRealPart { .. }
931 }
932 ))
933 ));
934 let z_nan_im = Complex::new(1.0_f32, f32::NAN);
935 assert!(matches!(
936 z_nan_im.try_arg(),
937 Err(ArgErrors::<Complex<f32>>::Input(
938 ArgInputErrors::ValidationError {
939 source: ErrorsValidationRawComplex::InvalidImaginaryPart { .. }
940 }
941 ))
942 ));
943
944 let z_inf_re = Complex::new(f32::INFINITY, 1.0_f32);
946 assert!(matches!(
947 z_inf_re.try_arg(),
948 Err(ArgErrors::<Complex<f32>>::Input(
949 ArgInputErrors::ValidationError {
950 source: ErrorsValidationRawComplex::InvalidRealPart { .. }
951 }
952 ))
953 ));
954 let z_inf_im = Complex::new(1.0_f32, f32::INFINITY);
955 assert!(matches!(
956 z_inf_im.try_arg(),
957 Err(ArgErrors::<Complex<f32>>::Input(
958 ArgInputErrors::ValidationError {
959 source: ErrorsValidationRawComplex::InvalidImaginaryPart { .. }
960 }
961 ))
962 ));
963
964 }
978
979 #[test]
980 #[cfg(debug_assertions)]
981 #[should_panic]
982 fn arg_panics_on_zero_debug() {
983 let zero = Complex::new(0.0, 0.0);
984 let _ = Arg::arg(zero);
985 }
986
987 #[test]
988 #[cfg(debug_assertions)]
989 #[should_panic]
990 fn arg_panics_on_nan_debug() {
991 let nan = Complex::new(f32::NAN, 1.0_f32);
992 let _ = Arg::arg(nan);
993 }
994
995 #[test]
996 #[cfg(debug_assertions)]
997 #[should_panic]
998 fn arg_panics_on_inf_debug() {
999 let inf = Complex::new(f32::INFINITY, 1.0_f32);
1000 let _ = Arg::arg(inf);
1001 }
1002
1003 #[test]
1004 #[cfg(not(debug_assertions))]
1005 fn arg_behavior_release() {
1006 let zero = Complex::new(0.0, 0.0);
1008 assert_eq!(Arg::arg(zero), 0.0);
1009
1010 let nan_re = Complex::new(f32::NAN, 1.0_f32);
1012 assert!(Arg::arg(nan_re).is_nan());
1013 let inf_re = Complex::new(f32::INFINITY, 0.0_f32); assert_eq!(Arg::arg(inf_re), 0.0_f32);
1015 let inf_im = Complex::new(0.0_f32, f32::INFINITY); assert_eq!(Arg::arg(inf_im), FRAC_PI_2);
1017 let inf_both = Complex::new(f32::INFINITY, f32::INFINITY); assert_eq!(Arg::arg(inf_both), FRAC_PI_4);
1019 }
1020
1021 #[test]
1022 fn test_is_pure_real() {
1023 let z_real = ComplexNative32StrictFinite::try_new_complex(5.0, 0.0).unwrap();
1025 assert!(z_real.is_pure_real());
1026 assert!(!z_real.is_pure_imaginary());
1027
1028 let z_zero = ComplexNative32StrictFinite::try_new_complex(0.0, 0.0).unwrap();
1030 assert!(z_zero.is_pure_real());
1031 assert!(!z_zero.is_pure_imaginary());
1032
1033 let z_complex = ComplexNative32StrictFinite::try_new_complex(3.0, 4.0).unwrap();
1035 assert!(!z_complex.is_pure_real());
1036 assert!(!z_complex.is_pure_imaginary());
1037
1038 let z_imag = ComplexNative32StrictFinite::try_new_complex(0.0, 5.0).unwrap();
1040 assert!(!z_imag.is_pure_real());
1041 assert!(z_imag.is_pure_imaginary());
1042 }
1043
1044 #[test]
1045 fn test_is_pure_imaginary() {
1046 let z_imag = ComplexNative32StrictFinite::try_new_complex(0.0, 7.0).unwrap();
1048 assert!(z_imag.is_pure_imaginary());
1049 assert!(!z_imag.is_pure_real());
1050
1051 let z_neg_imag = ComplexNative32StrictFinite::try_new_complex(0.0, -3.0).unwrap();
1053 assert!(z_neg_imag.is_pure_imaginary());
1054
1055 let z_zero = ComplexNative32StrictFinite::try_new_complex(0.0, 0.0).unwrap();
1057 assert!(!z_zero.is_pure_imaginary());
1058 assert!(z_zero.is_pure_real());
1059 }
1060
1061 #[test]
1062 fn test_with_real_part() {
1063 let z = ComplexNative32StrictFinite::try_new_complex(3.0, 4.0).unwrap();
1064 let new_real = RealNative32StrictFinite::try_new(10.0).unwrap();
1065
1066 let z_modified = z.with_real_part(new_real);
1067 assert_eq!(*z_modified.raw_real_part(), 10.0);
1068 assert_eq!(*z_modified.raw_imag_part(), 4.0);
1069 }
1070
1071 #[test]
1072 fn test_with_imaginary_part() {
1073 let z = ComplexNative32StrictFinite::try_new_complex(3.0, 4.0).unwrap();
1074 let new_imag = RealNative32StrictFinite::try_new(20.0).unwrap();
1075
1076 let z_modified = z.with_imaginary_part(new_imag);
1077 assert_eq!(*z_modified.raw_real_part(), 3.0);
1078 assert_eq!(*z_modified.raw_imag_part(), 20.0);
1079 }
1080
1081 #[test]
1082 fn test_new_pure_real() {
1083 let real_part = RealNative32StrictFinite::try_new(7.0).unwrap();
1084 let z = ComplexNative32StrictFinite::new_pure_real(real_part);
1085
1086 assert_eq!(*z.raw_real_part(), 7.0);
1087 assert_eq!(*z.raw_imag_part(), 0.0);
1088 assert!(z.is_pure_real());
1089 }
1090
1091 #[test]
1092 fn test_new_pure_imaginary() {
1093 let imag_part = RealNative32StrictFinite::try_new(9.0).unwrap();
1094 let z = ComplexNative32StrictFinite::new_pure_imaginary(imag_part);
1095
1096 assert_eq!(*z.raw_real_part(), 0.0);
1097 assert_eq!(*z.raw_imag_part(), 9.0);
1098 assert!(z.is_pure_imaginary());
1099 }
1100
1101 #[test]
1102 fn test_try_new_pure_real_valid() {
1103 let z = ComplexNative32StrictFinite::try_new_pure_real(5.0).unwrap();
1104 assert_eq!(*z.raw_real_part(), 5.0);
1105 assert_eq!(*z.raw_imag_part(), 0.0);
1106 }
1107
1108 #[test]
1109 fn test_try_new_pure_real_invalid() {
1110 let result = ComplexNative32StrictFinite::try_new_pure_real(f32::NAN);
1112 assert!(result.is_err());
1113
1114 let result = ComplexNative32StrictFinite::try_new_pure_real(f32::INFINITY);
1116 assert!(result.is_err());
1117 }
1118
1119 #[test]
1120 fn test_try_new_pure_imaginary_valid() {
1121 let z = ComplexNative32StrictFinite::try_new_pure_imaginary(8.0).unwrap();
1122 assert_eq!(*z.raw_real_part(), 0.0);
1123 assert_eq!(*z.raw_imag_part(), 8.0);
1124 }
1125
1126 #[test]
1127 fn test_try_new_pure_imaginary_invalid() {
1128 let result = ComplexNative32StrictFinite::try_new_pure_imaginary(f32::NAN);
1130 assert!(result.is_err());
1131
1132 let result = ComplexNative32StrictFinite::try_new_pure_imaginary(f32::NEG_INFINITY);
1134 assert!(result.is_err());
1135 }
1136
1137 #[test]
1138 fn test_into_parts_basic() {
1139 let z = ComplexNative32StrictFinite::try_new_complex(3.0, 4.0).unwrap();
1140
1141 let (real, imag) = z.into_parts();
1143
1144 assert_eq!(*real.as_ref(), 3.0);
1145 assert_eq!(*imag.as_ref(), 4.0);
1146 }
1147
1148 #[test]
1149 fn test_into_parts_zero() {
1150 let z = ComplexNative32StrictFinite::try_new_complex(0.0, 0.0).unwrap();
1151 let (real, imag) = z.into_parts();
1152
1153 assert_eq!(*real.as_ref(), 0.0);
1154 assert_eq!(*imag.as_ref(), 0.0);
1155 }
1156
1157 #[test]
1158 fn test_into_parts_pure_real() {
1159 let z = ComplexNative32StrictFinite::try_new_complex(7.5, 0.0).unwrap();
1160 let (real, imag) = z.into_parts();
1161
1162 assert_eq!(*real.as_ref(), 7.5);
1163 assert_eq!(*imag.as_ref(), 0.0);
1164 }
1165
1166 #[test]
1167 fn test_into_parts_pure_imaginary() {
1168 let z = ComplexNative32StrictFinite::try_new_complex(0.0, -9.2).unwrap();
1169 let (real, imag) = z.into_parts();
1170
1171 assert_eq!(*real.as_ref(), 0.0);
1172 assert_eq!(*imag.as_ref(), -9.2);
1173 }
1174
1175 #[test]
1176 fn test_into_parts_negative() {
1177 let z = ComplexNative32StrictFinite::try_new_complex(-5.5, -3.3).unwrap();
1178 let (real, imag) = z.into_parts();
1179
1180 assert_eq!(*real.as_ref(), -5.5);
1181 assert_eq!(*imag.as_ref(), -3.3);
1182 }
1183
1184 #[test]
1185 fn test_into_parts_parts_are_independent() {
1186 let z = ComplexNative32StrictFinite::try_new_complex(10.0, 20.0).unwrap();
1187 let (real, imag) = z.into_parts();
1188
1189 let two = RealNative32StrictFinite::try_new(2.0).unwrap();
1191 let real_doubled = real * two;
1192 let imag_halved = imag / two;
1193
1194 assert_eq!(*real_doubled.as_ref(), 20.0);
1195 assert_eq!(*imag_halved.as_ref(), 10.0);
1196 }
1197 }
1198
1199 #[cfg(feature = "rug")]
1200 mod rug53 {
1201 use super::*;
1202 use crate::backends::rug::validated::{ComplexRugStrictFinite, RealRugStrictFinite};
1203 use rug::Float;
1204 use std::f64::consts::*;
1205 use try_create::TryNew;
1206
1207 const PRECISION: u32 = 53;
1208
1209 fn rug_complex(re: f64, im: f64) -> rug::Complex {
1210 rug::Complex::with_val(
1211 PRECISION,
1212 (
1213 Float::with_val(PRECISION, re),
1214 Float::with_val(PRECISION, im),
1215 ),
1216 )
1217 }
1218
1219 fn new_complex_rug(re: f64, im: f64) -> ComplexRugStrictFinite<PRECISION> {
1220 ComplexRugStrictFinite::<PRECISION>::try_new(rug_complex(re, im))
1221 .expect("valid test value for complex rug")
1222 }
1223
1224 #[allow(clippy::result_large_err)]
1225 fn try_new_complex_rug(
1226 re: f64,
1227 im: f64,
1228 ) -> Result<
1229 ComplexRugStrictFinite<PRECISION>,
1230 <rug::Complex as RawScalarValidate>::ValidationError,
1231 > {
1232 ComplexRugStrictFinite::<PRECISION>::try_new(rug_complex(re, im))
1233 }
1234
1235 fn real_rug(val: f64) -> RealRugStrictFinite<PRECISION> {
1236 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, val))
1237 .expect("valid test value for real rug")
1238 }
1239
1240 #[test]
1241 fn conjugate() {
1242 let z = new_complex_rug(1.0, -2.0);
1243 let expected_conjugate = new_complex_rug(1.0, 2.0);
1244 assert_eq!(z.conjugate(), expected_conjugate);
1245
1246 let z = new_complex_rug(-3.0, 4.0);
1247 let expected_conjugate = new_complex_rug(-3.0, -4.0);
1248 assert_eq!(z.conjugate(), expected_conjugate);
1249
1250 let z_zero = new_complex_rug(0.0, 0.0);
1253 assert_eq!(z_zero.conjugate(), new_complex_rug(0.0, 0.0));
1254 let z_real = new_complex_rug(5.0, 0.0);
1256 assert_eq!(z_real.conjugate(), new_complex_rug(5.0, 0.0));
1257 let z_imag = new_complex_rug(0.0, 5.0);
1259 assert_eq!(z_imag.conjugate(), new_complex_rug(0.0, -5.0));
1260 let z_neg_imag = new_complex_rug(0.0, -5.0);
1261 assert_eq!(z_neg_imag.conjugate(), new_complex_rug(0.0, 5.0));
1262 }
1263
1264 #[test]
1265 fn arg() {
1266 let z1 = new_complex_rug(1.0, 1.0);
1268 assert_eq!(z1.arg(), real_rug(FRAC_PI_4));
1269
1270 let z_pos_real = new_complex_rug(1.0, 0.0);
1272 assert_eq!(z_pos_real.arg(), real_rug(0.0));
1273 let z_neg_real = new_complex_rug(-1.0, 0.0);
1274 assert_eq!(z_neg_real.arg(), real_rug(PI));
1275 let z_pos_imag = new_complex_rug(0.0, 1.0);
1276 assert_eq!(z_pos_imag.arg(), real_rug(FRAC_PI_2));
1277 let z_neg_imag = new_complex_rug(0.0, -1.0);
1278 assert_eq!(z_neg_imag.arg(), real_rug(-FRAC_PI_2));
1279
1280 let z2 = new_complex_rug(-1.0, 1.0); assert_eq!(z2.arg(), real_rug(3.0 * FRAC_PI_4));
1283 let z3 = new_complex_rug(-1.0, -1.0); assert_eq!(z3.arg(), real_rug(-3.0 * FRAC_PI_4));
1285 let z4 = new_complex_rug(1.0, -1.0); assert_eq!(z4.arg(), real_rug(-FRAC_PI_4));
1287
1288 let zero = new_complex_rug(0.0, 0.0);
1290 assert!(matches!(
1291 zero.try_arg(),
1292 Err(ArgErrors::Input(ArgInputErrors::Zero { .. }))
1293 ));
1294 }
1295
1296 #[test]
1297 #[cfg(not(debug_assertions))]
1298 fn try_arg_zero_invalid() {
1299 let z_zero = new_complex_rug(0.0, 0.0);
1301 assert!(matches!(
1302 z_zero.try_arg(),
1303 Err(ArgErrors::Input(ArgInputErrors::Zero { .. }))
1304 ));
1305 }
1306
1307 #[test]
1308 #[should_panic(
1309 expected = "Error calling ComplexValidated::try_arg() inside ComplexValidated::arg()"
1310 )]
1311 fn arg_panics_on_zero() {
1312 let zero = new_complex_rug(0.0, 0.0);
1313 let _ = zero.arg();
1314 }
1315
1316 #[test]
1317 fn err_on_try_new_real_part_infinity_debug() {
1318 let err = try_new_complex_rug(f64::INFINITY, 1.0);
1319 assert!(matches!(
1320 err,
1321 Err(ErrorsValidationRawComplex::InvalidRealPart { .. })
1322 ));
1323 }
1324
1325 #[test]
1326 fn err_on_try_new_real_part_nan_debug() {
1327 let err = try_new_complex_rug(f64::NAN, 1.0);
1328 assert!(matches!(
1329 err,
1330 Err(ErrorsValidationRawComplex::InvalidRealPart { .. })
1331 ));
1332 }
1333
1334 #[test]
1335 fn err_on_try_new_imaginary_part_infinity_debug() {
1336 let err = try_new_complex_rug(1.0, f64::INFINITY);
1337 assert!(matches!(
1338 err,
1339 Err(ErrorsValidationRawComplex::InvalidImaginaryPart { .. })
1340 ));
1341 }
1342
1343 #[test]
1344 fn err_on_try_new_imaginary_part_nan_debug() {
1345 let err = try_new_complex_rug(1.0, f64::NAN);
1346 assert!(matches!(
1347 err,
1348 Err(ErrorsValidationRawComplex::InvalidImaginaryPart { .. })
1349 ));
1350 }
1351
1352 #[test]
1353 #[cfg(debug_assertions)]
1354 #[should_panic(expected = "valid test value for complex rug")]
1355 fn panics_on_new_real_part_nan_debug() {
1356 let _nan = new_complex_rug(f64::NAN, 1.0);
1357 }
1358
1359 #[test]
1360 #[cfg(debug_assertions)]
1361 #[should_panic(expected = "valid test value for complex rug")]
1362 fn panics_on_new_real_part_infinity_debug() {
1363 let _inf = new_complex_rug(f64::INFINITY, 1.0);
1364 }
1365
1366 #[test]
1367 #[cfg(debug_assertions)]
1368 #[should_panic(expected = "valid test value for complex rug")]
1369 fn panics_on_new_imaginary_part_nan_debug() {
1370 let _nan = new_complex_rug(1.0, f64::NAN);
1371 }
1372
1373 #[test]
1374 #[cfg(debug_assertions)]
1375 #[should_panic(expected = "valid test value for complex rug")]
1376 fn panics_on_new_imaginary_part_infinity_debug() {
1377 let _inf = new_complex_rug(1.0, f64::INFINITY);
1378 }
1379
1380 #[test]
1385 fn test_into_parts_basic() {
1386 use crate::ComplexScalar;
1387
1388 let z = new_complex_rug(3.0, 4.0);
1389 let (real, imag) = z.into_parts();
1390
1391 assert_eq!(*real.as_ref(), 3.0);
1392 assert_eq!(*imag.as_ref(), 4.0);
1393 }
1394
1395 #[test]
1396 fn test_into_parts_zero() {
1397 use crate::ComplexScalar;
1398
1399 let z = new_complex_rug(0.0, 0.0);
1400 let (real, imag) = z.into_parts();
1401
1402 assert_eq!(*real.as_ref(), 0.0);
1403 assert_eq!(*imag.as_ref(), 0.0);
1404 }
1405
1406 #[test]
1407 fn test_into_parts_pure_real() {
1408 use crate::ComplexScalar;
1409
1410 let z = new_complex_rug(7.5, 0.0);
1411 let (real, imag) = z.into_parts();
1412
1413 assert_eq!(*real.as_ref(), 7.5);
1414 assert_eq!(*imag.as_ref(), 0.0);
1415 }
1416
1417 #[test]
1418 fn test_into_parts_pure_imaginary() {
1419 use crate::ComplexScalar;
1420
1421 let z = new_complex_rug(0.0, -9.2);
1422 let (real, imag) = z.into_parts();
1423
1424 assert_eq!(*real.as_ref(), 0.0);
1425 assert_eq!(*imag.as_ref(), -9.2);
1426 }
1427
1428 #[test]
1429 fn test_into_parts_negative() {
1430 use crate::ComplexScalar;
1431
1432 let z = new_complex_rug(-5.5, -3.3);
1433 let (real, imag) = z.into_parts();
1434
1435 assert_eq!(*real.as_ref(), -5.5);
1436 assert_eq!(*imag.as_ref(), -3.3);
1437 }
1438
1439 #[test]
1440 fn test_into_parts_parts_are_independent() {
1441 use crate::ComplexScalar;
1442
1443 let z = new_complex_rug(10.0, 20.0);
1444 let (real, imag) = z.into_parts();
1445
1446 let two = real_rug(2.0);
1448 let real_doubled = real * two;
1449 let imag_halved = imag / real_rug(2.0);
1450
1451 assert_eq!(*real_doubled.as_ref(), 20.0);
1452 assert_eq!(*imag_halved.as_ref(), 10.0);
1453 }
1454 }
1455}
1456