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:
46 FpScalar<InnerType = Self::RawComplex, RawScalarType = Self::RawComplex>
47{
48 type RawComplex: RawComplexTrait<RawReal = <Self::RealType as RealScalar>::RawReal>;
50
51 #[must_use = "this `Result` may contain an error that should be handled"]
55 fn try_new_complex(
56 real: <Self::RawComplex as RawComplexTrait>::RawReal,
57 imag: <Self::RawComplex as RawComplexTrait>::RawReal,
58 ) -> Result<Self, <Self::RawComplex as RawScalarValidate>::ValidationError>;
59
60 fn new_complex(real: Self::RealType, imag: Self::RealType) -> Self {
62 Self::try_new_complex(real.into_inner(), imag.into_inner()).unwrap()
63 }
64
65 #[must_use = "this `Result` may contain an error that should be handled"]
67 fn try_new_pure_real(
68 real_part: <Self::RawComplex as RawComplexTrait>::RawReal,
69 ) -> Result<Self, <Self::RawComplex as RawScalarValidate>::ValidationError> {
70 let zero =
71 <Self::RawComplex as RawComplexTrait>::RawReal::raw_zero(real_part.precision_bits());
72 Self::try_new_complex(real_part, zero)
73 }
74
75 #[must_use = "this `Result` may contain an error that should be handled"]
77 fn try_new_pure_imaginary(
78 imag_part: <Self::RawComplex as RawComplexTrait>::RawReal,
79 ) -> Result<Self, <Self::RawComplex as RawScalarValidate>::ValidationError> {
80 let zero =
81 <Self::RawComplex as RawComplexTrait>::RawReal::raw_zero(imag_part.precision_bits());
82 Self::try_new_complex(zero, imag_part)
83 }
84
85 fn new_pure_real(real_part: Self::RealType) -> Self {
92 Self::try_new_pure_real(real_part.into_inner()).unwrap()
93 }
94
95 fn new_pure_imaginary(imag_part: Self::RealType) -> Self {
102 Self::try_new_pure_imaginary(imag_part.into_inner()).unwrap()
103 }
104}
105
106pub trait ComplexScalarGetParts: ComplexScalarConstructors {
130 fn real_part(&self) -> Self::RealType;
132
133 fn imag_part(&self) -> Self::RealType;
135
136 fn raw_real_part(&self) -> &<Self::RealType as RealScalar>::RawReal;
138
139 fn raw_imag_part(&self) -> &<Self::RealType as RealScalar>::RawReal;
141
142 fn is_pure_real(&self) -> bool {
146 self.raw_imag_part().is_zero()
147 }
148
149 fn is_pure_imaginary(&self) -> bool {
153 self.raw_real_part().is_zero() && !self.raw_imag_part().is_zero()
154 }
155}
156
157pub trait ComplexScalarSetParts: ComplexScalarGetParts {
178 fn set_real_part(&mut self, real_part: Self::RealType);
180
181 fn set_imaginary_part(&mut self, imag_part: Self::RealType);
183
184 fn with_real_part(mut self, real_part: Self::RealType) -> Self {
186 self.set_real_part(real_part);
187 self
188 }
189
190 fn with_imaginary_part(mut self, imag_part: Self::RealType) -> Self {
192 self.set_imaginary_part(imag_part);
193 self
194 }
195}
196
197pub trait ComplexScalarMutateParts: ComplexScalarSetParts {
225 fn add_to_real_part(&mut self, c: &Self::RealType);
227
228 fn add_to_imaginary_part(&mut self, c: &Self::RealType);
230
231 fn multiply_real_part(&mut self, c: &Self::RealType);
233
234 fn multiply_imaginary_part(&mut self, c: &Self::RealType);
236}
237
238pub trait Conjugate: Sized {
280 fn conjugate(self) -> Self;
282}
283
284impl<T: NativeReal> Conjugate for Complex<T> {
285 #[inline(always)]
286 fn conjugate(self) -> Self {
287 self.conj()
288 }
289}
290
291#[derive(Debug, Error)]
306pub enum ArgInputErrors<RawComplex: RawComplexTrait> {
307 #[error("the input complex number is invalid according to validation policy")]
314 ValidationError {
315 #[source]
320 #[backtrace]
321 source: <RawComplex as RawScalarValidate>::ValidationError,
322 },
323
324 #[error("the input value is zero!")]
329 Zero {
330 backtrace: Backtrace,
332 },
333}
334
335pub type ArgErrors<RawComplex> = FunctionErrors<
363 ArgInputErrors<RawComplex>,
364 <<RawComplex as RawComplexTrait>::RawReal as RawScalarValidate>::ValidationError,
365>;
366
367pub trait Arg: Sized {
376 type Output: Sized;
379
380 type Error: std::error::Error;
384
385 #[must_use = "this `Result` may contain an error that should be handled"]
387 fn try_arg(self) -> Result<Self::Output, Self::Error>;
388
389 fn arg(self) -> Self::Output;
391}
392
393impl<T> Arg for Complex<T>
394where
395 Self: RawComplexTrait<RawReal = T>,
396 T: NativeReal,
397{
398 type Output = T;
399
400 type Error = ArgErrors<Complex<T>>;
401
402 #[inline(always)]
438 fn try_arg(self) -> Result<Self::Output, Self::Error> {
439 #[cfg(debug_assertions)]
440 {
441 self.validate_raw_scalar()
442 .map_err(|e| Self::Error::Input(ArgInputErrors::ValidationError { source: e }))
443 .and_then(|v: Complex<T>| {
444 if <Complex<T> as Zero>::is_zero(&v) {
445 Err(Self::Error::Input(ArgInputErrors::Zero {
446 backtrace: capture_backtrace(),
447 }))
448 } else {
449 Complex::<T>::arg(v)
450 .validate_raw_scalar()
451 .map_err(|e| Self::Error::Output { source: e })
452 }
453 })
454 }
455 #[cfg(not(debug_assertions))]
456 {
457 Ok(Complex::<T>::arg(self))
458 }
459 }
460
461 #[inline(always)]
491 fn arg(self) -> T {
492 #[cfg(debug_assertions)]
493 {
494 self.try_arg()
495 .expect("Error calling Arg::try_arg() inside Arg::arg() debug mode.")
496 }
497 #[cfg(not(debug_assertions))]
498 {
499 Complex::<T>::arg(self)
500 }
501 }
502}
503
504#[cfg(test)]
508mod tests {
509 use super::*;
510 use crate::{ComplexScalar, ScalarCore};
511 use num::Complex;
512 use try_create::TryNew;
513
514 #[cfg(debug_assertions)]
515 use crate::core::errors::ErrorsValidationRawComplex;
516
517 mod native_f64 {
518 use super::*;
519 use crate::backends::native::validated::{
520 ComplexNative64StrictFinite, RealNative64StrictFinite,
521 };
522 use std::f64::consts::*;
523
524 #[test]
525 fn conjugate() {
526 let z = Complex::new(1.0, -2.0);
527 let expected_conjugate = Complex::new(1.0, 2.0);
528 assert_eq!(z.conjugate(), expected_conjugate);
529
530 let z = Complex::new(-3.0, 4.0);
531 let expected_conjugate = Complex::new(-3.0, -4.0);
532 assert_eq!(z.conjugate(), expected_conjugate);
533
534 let z_zero = Complex::new(0.0, 0.0);
537 assert_eq!(z_zero.conjugate(), Complex::new(0.0, 0.0));
538 let z_real = Complex::new(5.0, 0.0);
540 assert_eq!(z_real.conjugate(), Complex::new(5.0, 0.0));
541 let z_imag = Complex::new(0.0, 5.0);
543 assert_eq!(z_imag.conjugate(), Complex::new(0.0, -5.0));
544 let z_neg_imag = Complex::new(0.0, -5.0);
545 assert_eq!(z_neg_imag.conjugate(), Complex::new(0.0, 5.0));
546 }
547
548 #[test]
549 fn arg() {
550 let z = Complex::new(1.0, 1.0);
551 let expected_arg = std::f64::consts::FRAC_PI_4; assert_eq!(z.arg(), expected_arg);
553
554 let z_pos_real = Complex::new(1.0, 0.0);
556 assert_eq!(z_pos_real.arg(), 0.0);
557 let z_neg_real = Complex::new(-1.0, 0.0);
558 assert_eq!(z_neg_real.arg(), PI);
559 let z_pos_imag = Complex::new(0.0, 1.0);
560 assert_eq!(z_pos_imag.arg(), FRAC_PI_2);
561 let z_neg_imag = Complex::new(0.0, -1.0);
562 assert_eq!(z_neg_imag.arg(), -FRAC_PI_2);
563
564 let z2 = Complex::new(-1.0, 1.0); assert_eq!(z2.arg(), 3.0 * FRAC_PI_4);
567 let z3 = Complex::new(-1.0, -1.0); assert_eq!(z3.arg(), -3.0 * FRAC_PI_4);
569 let z4 = Complex::new(1.0, -1.0); assert_eq!(z4.arg(), -FRAC_PI_4);
571 }
572
573 #[test]
574 #[cfg(debug_assertions)]
575 fn try_arg_invalid() {
576 let zero = Complex::new(0.0, 0.0);
577 assert!(matches!(
578 zero.try_arg(),
579 Err(ArgErrors::<Complex<f64>>::Input(
580 ArgInputErrors::Zero { .. }
581 ))
582 ));
583
584 let z_nan_re = Complex::new(f64::NAN, 1.0);
586 assert!(matches!(
587 z_nan_re.try_arg(),
588 Err(ArgErrors::<Complex<f64>>::Input(
589 ArgInputErrors::ValidationError {
590 source: ErrorsValidationRawComplex::InvalidRealPart { .. }
591 }
592 ))
593 ));
594 let z_nan_im = Complex::new(1.0, f64::NAN);
595 assert!(matches!(
596 z_nan_im.try_arg(),
597 Err(ArgErrors::<Complex<f64>>::Input(
598 ArgInputErrors::ValidationError {
599 source: ErrorsValidationRawComplex::InvalidImaginaryPart { .. }
600 }
601 ))
602 ));
603
604 let z_inf_re = Complex::new(f64::INFINITY, 1.0);
606 assert!(matches!(
607 z_inf_re.try_arg(),
608 Err(ArgErrors::<Complex<f64>>::Input(
609 ArgInputErrors::ValidationError {
610 source: ErrorsValidationRawComplex::InvalidRealPart { .. }
611 }
612 ))
613 ));
614 let z_inf_im = Complex::new(1.0, f64::INFINITY);
615 assert!(matches!(
616 z_inf_im.try_arg(),
617 Err(ArgErrors::<Complex<f64>>::Input(
618 ArgInputErrors::ValidationError {
619 source: ErrorsValidationRawComplex::InvalidImaginaryPart { .. }
620 }
621 ))
622 ));
623
624 }
638
639 #[test]
640 #[cfg(debug_assertions)]
641 #[should_panic]
642 fn arg_panics_on_zero_debug() {
643 let zero = Complex::new(0.0, 0.0);
644 let _ = Arg::arg(zero);
645 }
646
647 #[test]
648 #[cfg(debug_assertions)]
649 #[should_panic]
650 fn arg_panics_on_nan_debug() {
651 let nan = Complex::new(f64::NAN, 1.0);
652 let _ = Arg::arg(nan);
653 }
654
655 #[test]
656 #[cfg(debug_assertions)]
657 #[should_panic]
658 fn arg_panics_on_inf_debug() {
659 let inf = Complex::new(f64::INFINITY, 1.0);
660 let _ = Arg::arg(inf);
661 }
662
663 #[test]
664 #[cfg(not(debug_assertions))]
665 fn arg_behavior_release() {
666 let zero = Complex::new(0.0, 0.0);
668 assert_eq!(Arg::arg(zero), 0.0);
669
670 let nan_re = Complex::new(f64::NAN, 1.0);
672 assert!(Arg::arg(nan_re).is_nan());
673 let inf_re = Complex::new(f64::INFINITY, 0.0); assert_eq!(Arg::arg(inf_re), 0.0);
675 let inf_im = Complex::new(0.0, f64::INFINITY); assert_eq!(Arg::arg(inf_im), FRAC_PI_2);
677 let inf_both = Complex::new(f64::INFINITY, f64::INFINITY); assert_eq!(Arg::arg(inf_both), FRAC_PI_4);
679 }
680
681 #[test]
682 fn test_is_pure_real() {
683 let z_real = ComplexNative64StrictFinite::try_new_complex(5.0, 0.0).unwrap();
685 assert!(z_real.is_pure_real());
686 assert!(!z_real.is_pure_imaginary());
687
688 let z_zero = ComplexNative64StrictFinite::try_new_complex(0.0, 0.0).unwrap();
690 assert!(z_zero.is_pure_real());
691 assert!(!z_zero.is_pure_imaginary());
692
693 let z_complex = ComplexNative64StrictFinite::try_new_complex(3.0, 4.0).unwrap();
695 assert!(!z_complex.is_pure_real());
696 assert!(!z_complex.is_pure_imaginary());
697
698 let z_imag = ComplexNative64StrictFinite::try_new_complex(0.0, 5.0).unwrap();
700 assert!(!z_imag.is_pure_real());
701 assert!(z_imag.is_pure_imaginary());
702 }
703
704 #[test]
705 fn test_is_pure_imaginary() {
706 let z_imag = ComplexNative64StrictFinite::try_new_complex(0.0, 7.0).unwrap();
708 assert!(z_imag.is_pure_imaginary());
709 assert!(!z_imag.is_pure_real());
710
711 let z_neg_imag = ComplexNative64StrictFinite::try_new_complex(0.0, -3.0).unwrap();
713 assert!(z_neg_imag.is_pure_imaginary());
714
715 let z_zero = ComplexNative64StrictFinite::try_new_complex(0.0, 0.0).unwrap();
717 assert!(!z_zero.is_pure_imaginary());
718 assert!(z_zero.is_pure_real());
719 }
720
721 #[test]
722 fn test_with_real_part() {
723 let z = ComplexNative64StrictFinite::try_new_complex(3.0, 4.0).unwrap();
724 let new_real = RealNative64StrictFinite::try_new(10.0).unwrap();
725
726 let z_modified = z.with_real_part(new_real);
727 assert_eq!(*z_modified.raw_real_part(), 10.0);
728 assert_eq!(*z_modified.raw_imag_part(), 4.0);
729 }
730
731 #[test]
732 fn test_with_imaginary_part() {
733 let z = ComplexNative64StrictFinite::try_new_complex(3.0, 4.0).unwrap();
734 let new_imag = RealNative64StrictFinite::try_new(20.0).unwrap();
735
736 let z_modified = z.with_imaginary_part(new_imag);
737 assert_eq!(*z_modified.raw_real_part(), 3.0);
738 assert_eq!(*z_modified.raw_imag_part(), 20.0);
739 }
740
741 #[test]
742 fn test_new_pure_real() {
743 let real_part = RealNative64StrictFinite::try_new(7.0).unwrap();
744 let z = ComplexNative64StrictFinite::new_pure_real(real_part);
745
746 assert_eq!(*z.raw_real_part(), 7.0);
747 assert_eq!(*z.raw_imag_part(), 0.0);
748 assert!(z.is_pure_real());
749 }
750
751 #[test]
752 fn test_new_pure_imaginary() {
753 let imag_part = RealNative64StrictFinite::try_new(9.0).unwrap();
754 let z = ComplexNative64StrictFinite::new_pure_imaginary(imag_part);
755
756 assert_eq!(*z.raw_real_part(), 0.0);
757 assert_eq!(*z.raw_imag_part(), 9.0);
758 assert!(z.is_pure_imaginary());
759 }
760
761 #[test]
762 fn test_try_new_pure_real_valid() {
763 let z = ComplexNative64StrictFinite::try_new_pure_real(5.0).unwrap();
764 assert_eq!(*z.raw_real_part(), 5.0);
765 assert_eq!(*z.raw_imag_part(), 0.0);
766 }
767
768 #[test]
769 fn test_try_new_pure_real_invalid() {
770 let result = ComplexNative64StrictFinite::try_new_pure_real(f64::NAN);
772 assert!(result.is_err());
773
774 let result = ComplexNative64StrictFinite::try_new_pure_real(f64::INFINITY);
776 assert!(result.is_err());
777 }
778
779 #[test]
780 fn test_try_new_pure_imaginary_valid() {
781 let z = ComplexNative64StrictFinite::try_new_pure_imaginary(8.0).unwrap();
782 assert_eq!(*z.raw_real_part(), 0.0);
783 assert_eq!(*z.raw_imag_part(), 8.0);
784 }
785
786 #[test]
787 fn test_try_new_pure_imaginary_invalid() {
788 let result = ComplexNative64StrictFinite::try_new_pure_imaginary(f64::NAN);
790 assert!(result.is_err());
791
792 let result = ComplexNative64StrictFinite::try_new_pure_imaginary(f64::NEG_INFINITY);
794 assert!(result.is_err());
795 }
796
797 #[test]
798 fn test_into_parts_basic() {
799 let z = ComplexNative64StrictFinite::try_new_complex(3.0, 4.0).unwrap();
800
801 let (real, imag) = z.into_parts();
803
804 assert_eq!(*real.as_raw_scalar_ref(), 3.0);
805 assert_eq!(*imag.as_raw_scalar_ref(), 4.0);
806 }
807
808 #[test]
809 fn test_into_parts_zero() {
810 let z = ComplexNative64StrictFinite::try_new_complex(0.0, 0.0).unwrap();
811 let (real, imag) = z.into_parts();
812
813 assert_eq!(*real.as_raw_scalar_ref(), 0.0);
814 assert_eq!(*imag.as_raw_scalar_ref(), 0.0);
815 }
816
817 #[test]
818 fn test_into_parts_pure_real() {
819 let z = ComplexNative64StrictFinite::try_new_complex(7.5, 0.0).unwrap();
820 let (real, imag) = z.into_parts();
821
822 assert_eq!(*real.as_raw_scalar_ref(), 7.5);
823 assert_eq!(*imag.as_raw_scalar_ref(), 0.0);
824 }
825
826 #[test]
827 fn test_into_parts_pure_imaginary() {
828 let z = ComplexNative64StrictFinite::try_new_complex(0.0, -9.2).unwrap();
829 let (real, imag) = z.into_parts();
830
831 assert_eq!(*real.as_raw_scalar_ref(), 0.0);
832 assert_eq!(*imag.as_raw_scalar_ref(), -9.2);
833 }
834
835 #[test]
836 fn test_into_parts_negative() {
837 let z = ComplexNative64StrictFinite::try_new_complex(-5.5, -3.3).unwrap();
838 let (real, imag) = z.into_parts();
839
840 assert_eq!(*real.as_raw_scalar_ref(), -5.5);
841 assert_eq!(*imag.as_raw_scalar_ref(), -3.3);
842 }
843
844 #[test]
845 fn test_into_parts_parts_are_independent() {
846 let z = ComplexNative64StrictFinite::try_new_complex(10.0, 20.0).unwrap();
847 let (real, imag) = z.into_parts();
848
849 let two = RealNative64StrictFinite::try_new(2.0).unwrap();
851 let real_doubled = real * two;
852 let imag_halved = imag / two;
853
854 assert_eq!(*real_doubled.as_raw_scalar_ref(), 20.0);
855 assert_eq!(*imag_halved.as_raw_scalar_ref(), 10.0);
856 }
857 }
858
859 mod native_f32 {
860 use super::*;
861 use crate::backends::native::validated::{
862 ComplexNative32StrictFinite, RealNative32StrictFinite,
863 };
864 use std::f32::consts::*;
865
866 #[test]
867 fn conjugate() {
868 let z = Complex::new(1.0_f32, -2.0_f32);
869 let expected_conjugate = Complex::new(1.0_f32, 2.0_f32);
870 assert_eq!(z.conjugate(), expected_conjugate);
871
872 let z = Complex::new(-3.0_f32, 4.0_f32);
873 let expected_conjugate = Complex::new(-3.0_f32, -4.0_f32);
874 assert_eq!(z.conjugate(), expected_conjugate);
875
876 let z_zero = Complex::new(0.0_f32, 0.0_f32);
879 assert_eq!(z_zero.conjugate(), Complex::new(0.0_f32, 0.0_f32));
880 let z_real = Complex::new(5.0_f32, 0.0_f32);
882 assert_eq!(z_real.conjugate(), Complex::new(5.0_f32, 0.0_f32));
883 let z_imag = Complex::new(0.0_f32, 5.0_f32);
885 assert_eq!(z_imag.conjugate(), Complex::new(0.0_f32, -5.0_f32));
886 let z_neg_imag = Complex::new(0.0_f32, -5.0_f32);
887 assert_eq!(z_neg_imag.conjugate(), Complex::new(0.0_f32, 5.0_f32));
888 }
889
890 #[test]
891 fn arg() {
892 let z = Complex::new(1.0_f32, 1.0_f32);
893 let expected_arg = std::f32::consts::FRAC_PI_4; assert_eq!(z.arg(), expected_arg);
895
896 let z_pos_real = Complex::new(1.0_f32, 0.0_f32);
898 assert_eq!(z_pos_real.arg(), 0.0_f32);
899 let z_neg_real = Complex::new(-1.0_f32, 0.0_f32);
900 if cfg!(target_arch = "aarch64") {
901 assert_eq!(z_neg_real.arg(), 3.1415925);
902 } else {
903 assert_eq!(z_neg_real.arg(), std::f32::consts::PI);
904 }
905 let z_pos_imag = Complex::new(0.0_f32, 1.0_f32);
906 assert_eq!(z_pos_imag.arg(), FRAC_PI_2);
907 let z_neg_imag = Complex::new(0.0_f32, -1.0_f32);
908 assert_eq!(z_neg_imag.arg(), -FRAC_PI_2);
909
910 let z2 = Complex::new(-1.0_f32, 1.0_f32); assert_eq!(z2.arg(), 3.0 * FRAC_PI_4);
913 let z3 = Complex::new(-1.0_f32, -1.0_f32); assert_eq!(z3.arg(), -3.0 * FRAC_PI_4);
915 let z4 = Complex::new(1.0_f32, -1.0_f32); assert_eq!(z4.arg(), -FRAC_PI_4);
917 }
918
919 #[test]
920 #[cfg(debug_assertions)]
921 fn try_arg_invalid() {
922 let zero = Complex::new(0.0_f32, 0.0_f32);
923 assert!(matches!(
924 zero.try_arg(),
925 Err(ArgErrors::<Complex<f32>>::Input(
926 ArgInputErrors::Zero { .. }
927 ))
928 ));
929
930 let z_nan_re = Complex::new(f32::NAN, 1.0_f32);
932 assert!(matches!(
933 z_nan_re.try_arg(),
934 Err(ArgErrors::<Complex<f32>>::Input(
935 ArgInputErrors::ValidationError {
936 source: ErrorsValidationRawComplex::InvalidRealPart { .. }
937 }
938 ))
939 ));
940 let z_nan_im = Complex::new(1.0_f32, f32::NAN);
941 assert!(matches!(
942 z_nan_im.try_arg(),
943 Err(ArgErrors::<Complex<f32>>::Input(
944 ArgInputErrors::ValidationError {
945 source: ErrorsValidationRawComplex::InvalidImaginaryPart { .. }
946 }
947 ))
948 ));
949
950 let z_inf_re = Complex::new(f32::INFINITY, 1.0_f32);
952 assert!(matches!(
953 z_inf_re.try_arg(),
954 Err(ArgErrors::<Complex<f32>>::Input(
955 ArgInputErrors::ValidationError {
956 source: ErrorsValidationRawComplex::InvalidRealPart { .. }
957 }
958 ))
959 ));
960 let z_inf_im = Complex::new(1.0_f32, f32::INFINITY);
961 assert!(matches!(
962 z_inf_im.try_arg(),
963 Err(ArgErrors::<Complex<f32>>::Input(
964 ArgInputErrors::ValidationError {
965 source: ErrorsValidationRawComplex::InvalidImaginaryPart { .. }
966 }
967 ))
968 ));
969
970 }
984
985 #[test]
986 #[cfg(debug_assertions)]
987 #[should_panic]
988 fn arg_panics_on_zero_debug() {
989 let zero = Complex::new(0.0, 0.0);
990 let _ = Arg::arg(zero);
991 }
992
993 #[test]
994 #[cfg(debug_assertions)]
995 #[should_panic]
996 fn arg_panics_on_nan_debug() {
997 let nan = Complex::new(f32::NAN, 1.0_f32);
998 let _ = Arg::arg(nan);
999 }
1000
1001 #[test]
1002 #[cfg(debug_assertions)]
1003 #[should_panic]
1004 fn arg_panics_on_inf_debug() {
1005 let inf = Complex::new(f32::INFINITY, 1.0_f32);
1006 let _ = Arg::arg(inf);
1007 }
1008
1009 #[test]
1010 #[cfg(not(debug_assertions))]
1011 fn arg_behavior_release() {
1012 let zero = Complex::new(0.0, 0.0);
1014 assert_eq!(Arg::arg(zero), 0.0);
1015
1016 let nan_re = Complex::new(f32::NAN, 1.0_f32);
1018 assert!(Arg::arg(nan_re).is_nan());
1019 let inf_re = Complex::new(f32::INFINITY, 0.0_f32); assert_eq!(Arg::arg(inf_re), 0.0_f32);
1021 let inf_im = Complex::new(0.0_f32, f32::INFINITY); assert_eq!(Arg::arg(inf_im), FRAC_PI_2);
1023 let inf_both = Complex::new(f32::INFINITY, f32::INFINITY); assert_eq!(Arg::arg(inf_both), FRAC_PI_4);
1025 }
1026
1027 #[test]
1028 fn test_is_pure_real() {
1029 let z_real = ComplexNative32StrictFinite::try_new_complex(5.0, 0.0).unwrap();
1031 assert!(z_real.is_pure_real());
1032 assert!(!z_real.is_pure_imaginary());
1033
1034 let z_zero = ComplexNative32StrictFinite::try_new_complex(0.0, 0.0).unwrap();
1036 assert!(z_zero.is_pure_real());
1037 assert!(!z_zero.is_pure_imaginary());
1038
1039 let z_complex = ComplexNative32StrictFinite::try_new_complex(3.0, 4.0).unwrap();
1041 assert!(!z_complex.is_pure_real());
1042 assert!(!z_complex.is_pure_imaginary());
1043
1044 let z_imag = ComplexNative32StrictFinite::try_new_complex(0.0, 5.0).unwrap();
1046 assert!(!z_imag.is_pure_real());
1047 assert!(z_imag.is_pure_imaginary());
1048 }
1049
1050 #[test]
1051 fn test_is_pure_imaginary() {
1052 let z_imag = ComplexNative32StrictFinite::try_new_complex(0.0, 7.0).unwrap();
1054 assert!(z_imag.is_pure_imaginary());
1055 assert!(!z_imag.is_pure_real());
1056
1057 let z_neg_imag = ComplexNative32StrictFinite::try_new_complex(0.0, -3.0).unwrap();
1059 assert!(z_neg_imag.is_pure_imaginary());
1060
1061 let z_zero = ComplexNative32StrictFinite::try_new_complex(0.0, 0.0).unwrap();
1063 assert!(!z_zero.is_pure_imaginary());
1064 assert!(z_zero.is_pure_real());
1065 }
1066
1067 #[test]
1068 fn test_with_real_part() {
1069 let z = ComplexNative32StrictFinite::try_new_complex(3.0, 4.0).unwrap();
1070 let new_real = RealNative32StrictFinite::try_new(10.0).unwrap();
1071
1072 let z_modified = z.with_real_part(new_real);
1073 assert_eq!(*z_modified.raw_real_part(), 10.0);
1074 assert_eq!(*z_modified.raw_imag_part(), 4.0);
1075 }
1076
1077 #[test]
1078 fn test_with_imaginary_part() {
1079 let z = ComplexNative32StrictFinite::try_new_complex(3.0, 4.0).unwrap();
1080 let new_imag = RealNative32StrictFinite::try_new(20.0).unwrap();
1081
1082 let z_modified = z.with_imaginary_part(new_imag);
1083 assert_eq!(*z_modified.raw_real_part(), 3.0);
1084 assert_eq!(*z_modified.raw_imag_part(), 20.0);
1085 }
1086
1087 #[test]
1088 fn test_new_pure_real() {
1089 let real_part = RealNative32StrictFinite::try_new(7.0).unwrap();
1090 let z = ComplexNative32StrictFinite::new_pure_real(real_part);
1091
1092 assert_eq!(*z.raw_real_part(), 7.0);
1093 assert_eq!(*z.raw_imag_part(), 0.0);
1094 assert!(z.is_pure_real());
1095 }
1096
1097 #[test]
1098 fn test_new_pure_imaginary() {
1099 let imag_part = RealNative32StrictFinite::try_new(9.0).unwrap();
1100 let z = ComplexNative32StrictFinite::new_pure_imaginary(imag_part);
1101
1102 assert_eq!(*z.raw_real_part(), 0.0);
1103 assert_eq!(*z.raw_imag_part(), 9.0);
1104 assert!(z.is_pure_imaginary());
1105 }
1106
1107 #[test]
1108 fn test_try_new_pure_real_valid() {
1109 let z = ComplexNative32StrictFinite::try_new_pure_real(5.0).unwrap();
1110 assert_eq!(*z.raw_real_part(), 5.0);
1111 assert_eq!(*z.raw_imag_part(), 0.0);
1112 }
1113
1114 #[test]
1115 fn test_try_new_pure_real_invalid() {
1116 let result = ComplexNative32StrictFinite::try_new_pure_real(f32::NAN);
1118 assert!(result.is_err());
1119
1120 let result = ComplexNative32StrictFinite::try_new_pure_real(f32::INFINITY);
1122 assert!(result.is_err());
1123 }
1124
1125 #[test]
1126 fn test_try_new_pure_imaginary_valid() {
1127 let z = ComplexNative32StrictFinite::try_new_pure_imaginary(8.0).unwrap();
1128 assert_eq!(*z.raw_real_part(), 0.0);
1129 assert_eq!(*z.raw_imag_part(), 8.0);
1130 }
1131
1132 #[test]
1133 fn test_try_new_pure_imaginary_invalid() {
1134 let result = ComplexNative32StrictFinite::try_new_pure_imaginary(f32::NAN);
1136 assert!(result.is_err());
1137
1138 let result = ComplexNative32StrictFinite::try_new_pure_imaginary(f32::NEG_INFINITY);
1140 assert!(result.is_err());
1141 }
1142
1143 #[test]
1144 fn test_into_parts_basic() {
1145 let z = ComplexNative32StrictFinite::try_new_complex(3.0, 4.0).unwrap();
1146
1147 let (real, imag) = z.into_parts();
1149
1150 assert_eq!(*real.as_raw_scalar_ref(), 3.0);
1151 assert_eq!(*imag.as_raw_scalar_ref(), 4.0);
1152 }
1153
1154 #[test]
1155 fn test_into_parts_zero() {
1156 let z = ComplexNative32StrictFinite::try_new_complex(0.0, 0.0).unwrap();
1157 let (real, imag) = z.into_parts();
1158
1159 assert_eq!(*real.as_raw_scalar_ref(), 0.0);
1160 assert_eq!(*imag.as_raw_scalar_ref(), 0.0);
1161 }
1162
1163 #[test]
1164 fn test_into_parts_pure_real() {
1165 let z = ComplexNative32StrictFinite::try_new_complex(7.5, 0.0).unwrap();
1166 let (real, imag) = z.into_parts();
1167
1168 assert_eq!(*real.as_raw_scalar_ref(), 7.5);
1169 assert_eq!(*imag.as_raw_scalar_ref(), 0.0);
1170 }
1171
1172 #[test]
1173 fn test_into_parts_pure_imaginary() {
1174 let z = ComplexNative32StrictFinite::try_new_complex(0.0, -9.2).unwrap();
1175 let (real, imag) = z.into_parts();
1176
1177 assert_eq!(*real.as_raw_scalar_ref(), 0.0);
1178 assert_eq!(*imag.as_raw_scalar_ref(), -9.2);
1179 }
1180
1181 #[test]
1182 fn test_into_parts_negative() {
1183 let z = ComplexNative32StrictFinite::try_new_complex(-5.5, -3.3).unwrap();
1184 let (real, imag) = z.into_parts();
1185
1186 assert_eq!(*real.as_raw_scalar_ref(), -5.5);
1187 assert_eq!(*imag.as_raw_scalar_ref(), -3.3);
1188 }
1189
1190 #[test]
1191 fn test_into_parts_parts_are_independent() {
1192 let z = ComplexNative32StrictFinite::try_new_complex(10.0, 20.0).unwrap();
1193 let (real, imag) = z.into_parts();
1194
1195 let two = RealNative32StrictFinite::try_new(2.0).unwrap();
1197 let real_doubled = real * two;
1198 let imag_halved = imag / two;
1199
1200 assert_eq!(*real_doubled.as_raw_scalar_ref(), 20.0);
1201 assert_eq!(*imag_halved.as_raw_scalar_ref(), 10.0);
1202 }
1203 }
1204
1205 #[cfg(feature = "rug")]
1206 mod rug53 {
1207 use super::*;
1208 use crate::ErrorsValidationRawComplex;
1209 use crate::backends::rug::validated::{ComplexRugStrictFinite, RealRugStrictFinite};
1210 use rug::Float;
1211 use std::f64::consts::*;
1212 use try_create::TryNew;
1213
1214 const PRECISION: u32 = 53;
1215
1216 fn rug_complex(re: f64, im: f64) -> rug::Complex {
1217 rug::Complex::with_val(
1218 PRECISION,
1219 (
1220 Float::with_val(PRECISION, re),
1221 Float::with_val(PRECISION, im),
1222 ),
1223 )
1224 }
1225
1226 fn new_complex_rug(re: f64, im: f64) -> ComplexRugStrictFinite<PRECISION> {
1227 ComplexRugStrictFinite::<PRECISION>::try_new(rug_complex(re, im))
1228 .expect("valid test value for complex rug")
1229 }
1230
1231 #[allow(clippy::result_large_err)]
1232 fn try_new_complex_rug(
1233 re: f64,
1234 im: f64,
1235 ) -> Result<
1236 ComplexRugStrictFinite<PRECISION>,
1237 <rug::Complex as RawScalarValidate>::ValidationError,
1238 > {
1239 ComplexRugStrictFinite::<PRECISION>::try_new(rug_complex(re, im))
1240 }
1241
1242 fn real_rug(val: f64) -> RealRugStrictFinite<PRECISION> {
1243 RealRugStrictFinite::<PRECISION>::try_new(Float::with_val(PRECISION, val))
1244 .expect("valid test value for real rug")
1245 }
1246
1247 #[test]
1248 fn conjugate() {
1249 let z = new_complex_rug(1.0, -2.0);
1250 let expected_conjugate = new_complex_rug(1.0, 2.0);
1251 assert_eq!(z.conjugate(), expected_conjugate);
1252
1253 let z = new_complex_rug(-3.0, 4.0);
1254 let expected_conjugate = new_complex_rug(-3.0, -4.0);
1255 assert_eq!(z.conjugate(), expected_conjugate);
1256
1257 let z_zero = new_complex_rug(0.0, 0.0);
1260 assert_eq!(z_zero.conjugate(), new_complex_rug(0.0, 0.0));
1261 let z_real = new_complex_rug(5.0, 0.0);
1263 assert_eq!(z_real.conjugate(), new_complex_rug(5.0, 0.0));
1264 let z_imag = new_complex_rug(0.0, 5.0);
1266 assert_eq!(z_imag.conjugate(), new_complex_rug(0.0, -5.0));
1267 let z_neg_imag = new_complex_rug(0.0, -5.0);
1268 assert_eq!(z_neg_imag.conjugate(), new_complex_rug(0.0, 5.0));
1269 }
1270
1271 #[test]
1272 fn arg() {
1273 let z1 = new_complex_rug(1.0, 1.0);
1275 assert_eq!(z1.arg(), real_rug(FRAC_PI_4));
1276
1277 let z_pos_real = new_complex_rug(1.0, 0.0);
1279 assert_eq!(z_pos_real.arg(), real_rug(0.0));
1280 let z_neg_real = new_complex_rug(-1.0, 0.0);
1281 assert_eq!(z_neg_real.arg(), real_rug(PI));
1282 let z_pos_imag = new_complex_rug(0.0, 1.0);
1283 assert_eq!(z_pos_imag.arg(), real_rug(FRAC_PI_2));
1284 let z_neg_imag = new_complex_rug(0.0, -1.0);
1285 assert_eq!(z_neg_imag.arg(), real_rug(-FRAC_PI_2));
1286
1287 let z2 = new_complex_rug(-1.0, 1.0); assert_eq!(z2.arg(), real_rug(3.0 * FRAC_PI_4));
1290 let z3 = new_complex_rug(-1.0, -1.0); assert_eq!(z3.arg(), real_rug(-3.0 * FRAC_PI_4));
1292 let z4 = new_complex_rug(1.0, -1.0); assert_eq!(z4.arg(), real_rug(-FRAC_PI_4));
1294
1295 let zero = new_complex_rug(0.0, 0.0);
1297 assert!(matches!(
1298 zero.try_arg(),
1299 Err(ArgErrors::Input(ArgInputErrors::Zero { .. }))
1300 ));
1301 }
1302
1303 #[test]
1304 #[cfg(not(debug_assertions))]
1305 fn try_arg_zero_invalid() {
1306 let z_zero = new_complex_rug(0.0, 0.0);
1308 assert!(matches!(
1309 z_zero.try_arg(),
1310 Err(ArgErrors::Input(ArgInputErrors::Zero { .. }))
1311 ));
1312 }
1313
1314 #[test]
1315 #[should_panic(
1316 expected = "Error calling ComplexValidated::try_arg() inside ComplexValidated::arg()"
1317 )]
1318 fn arg_panics_on_zero() {
1319 let zero = new_complex_rug(0.0, 0.0);
1320 let _ = zero.arg();
1321 }
1322
1323 #[test]
1324 fn err_on_try_new_real_part_infinity_debug() {
1325 let err = try_new_complex_rug(f64::INFINITY, 1.0);
1326 assert!(matches!(
1327 err,
1328 Err(ErrorsValidationRawComplex::InvalidRealPart { .. })
1329 ));
1330 }
1331
1332 #[test]
1333 fn err_on_try_new_real_part_nan_debug() {
1334 let err = try_new_complex_rug(f64::NAN, 1.0);
1335 assert!(matches!(
1336 err,
1337 Err(ErrorsValidationRawComplex::InvalidRealPart { .. })
1338 ));
1339 }
1340
1341 #[test]
1342 fn err_on_try_new_imaginary_part_infinity_debug() {
1343 let err = try_new_complex_rug(1.0, f64::INFINITY);
1344 assert!(matches!(
1345 err,
1346 Err(ErrorsValidationRawComplex::InvalidImaginaryPart { .. })
1347 ));
1348 }
1349
1350 #[test]
1351 fn err_on_try_new_imaginary_part_nan_debug() {
1352 let err = try_new_complex_rug(1.0, f64::NAN);
1353 assert!(matches!(
1354 err,
1355 Err(ErrorsValidationRawComplex::InvalidImaginaryPart { .. })
1356 ));
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_nan_debug() {
1363 let _nan = new_complex_rug(f64::NAN, 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_real_part_infinity_debug() {
1370 let _inf = new_complex_rug(f64::INFINITY, 1.0);
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_nan_debug() {
1377 let _nan = new_complex_rug(1.0, f64::NAN);
1378 }
1379
1380 #[test]
1381 #[cfg(debug_assertions)]
1382 #[should_panic(expected = "valid test value for complex rug")]
1383 fn panics_on_new_imaginary_part_infinity_debug() {
1384 let _inf = new_complex_rug(1.0, f64::INFINITY);
1385 }
1386
1387 #[test]
1392 fn test_into_parts_basic() {
1393 use crate::ComplexScalar;
1394
1395 let z = new_complex_rug(3.0, 4.0);
1396 let (real, imag) = z.into_parts();
1397
1398 assert_eq!(*real.as_raw_scalar_ref(), 3.0);
1399 assert_eq!(*imag.as_raw_scalar_ref(), 4.0);
1400 }
1401
1402 #[test]
1403 fn test_into_parts_zero() {
1404 use crate::ComplexScalar;
1405
1406 let z = new_complex_rug(0.0, 0.0);
1407 let (real, imag) = z.into_parts();
1408
1409 assert_eq!(*real.as_raw_scalar_ref(), 0.0);
1410 assert_eq!(*imag.as_raw_scalar_ref(), 0.0);
1411 }
1412
1413 #[test]
1414 fn test_into_parts_pure_real() {
1415 use crate::ComplexScalar;
1416
1417 let z = new_complex_rug(7.5, 0.0);
1418 let (real, imag) = z.into_parts();
1419
1420 assert_eq!(*real.as_raw_scalar_ref(), 7.5);
1421 assert_eq!(*imag.as_raw_scalar_ref(), 0.0);
1422 }
1423
1424 #[test]
1425 fn test_into_parts_pure_imaginary() {
1426 use crate::ComplexScalar;
1427
1428 let z = new_complex_rug(0.0, -9.2);
1429 let (real, imag) = z.into_parts();
1430
1431 assert_eq!(*real.as_raw_scalar_ref(), 0.0);
1432 assert_eq!(*imag.as_raw_scalar_ref(), -9.2);
1433 }
1434
1435 #[test]
1436 fn test_into_parts_negative() {
1437 use crate::ComplexScalar;
1438
1439 let z = new_complex_rug(-5.5, -3.3);
1440 let (real, imag) = z.into_parts();
1441
1442 assert_eq!(*real.as_raw_scalar_ref(), -5.5);
1443 assert_eq!(*imag.as_raw_scalar_ref(), -3.3);
1444 }
1445
1446 #[test]
1447 fn test_into_parts_parts_are_independent() {
1448 use crate::ComplexScalar;
1449
1450 let z = new_complex_rug(10.0, 20.0);
1451 let (real, imag) = z.into_parts();
1452
1453 let two = real_rug(2.0);
1455 let real_doubled = real * two;
1456 let imag_halved = imag / real_rug(2.0);
1457
1458 assert_eq!(*real_doubled.as_raw_scalar_ref(), 20.0);
1459 assert_eq!(*imag_halved.as_raw_scalar_ref(), 10.0);
1460 }
1461 }
1462}
1463