1use crate::CalculatorError;
19use crate::CalculatorFloat;
20use num_complex::Complex;
21use serde::de::Deserialize;
22use serde::de::Error;
23use serde::de::{SeqAccess, Visitor};
24use serde::ser::SerializeTuple;
25use serde::Serialize;
26use std::convert::TryFrom;
27use std::fmt;
28use std::ops;
29#[derive(Debug, Clone, PartialEq)]
33pub struct CalculatorComplex {
34 pub re: CalculatorFloat,
36 pub im: CalculatorFloat,
38}
39
40#[cfg(feature = "json_schema")]
41impl schemars::JsonSchema for CalculatorComplex {
42 fn schema_name() -> std::borrow::Cow<'static, str> {
43 "CalculatorComplex".into()
44 }
45
46 fn json_schema(generator: &mut schemars::SchemaGenerator) -> schemars::Schema {
47 <(CalculatorFloat, CalculatorFloat)>::json_schema(generator)
48 }
49}
50
51impl Serialize for CalculatorComplex {
52 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
53 where
54 S: serde::Serializer,
55 {
56 let mut tuple = serializer.serialize_tuple(2)?;
57 tuple.serialize_element(&self.re)?;
58 tuple.serialize_element(&self.im)?;
59 tuple.end()
60 }
61}
62
63impl<'de> Deserialize<'de> for CalculatorComplex {
64 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
65 where
66 D: serde::Deserializer<'de>,
67 {
68 struct ComplexVisitor;
69 impl<'de> Visitor<'de> for ComplexVisitor {
70 type Value = CalculatorComplex;
71 fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
72 std::fmt::Formatter::write_str(
73 formatter,
74 "Tuple of two CalculatorFloat values (float or string)",
75 )
76 }
77 fn visit_seq<M>(self, mut access: M) -> Result<Self::Value, M::Error>
79 where
80 M: SeqAccess<'de>,
81 {
82 let real: CalculatorFloat = match access.next_element()? {
84 Some(x) => x,
85 None => {
86 return Err(M::Error::custom("Missing real part".to_string()));
87 }
88 };
89 let imaginary: CalculatorFloat = match access.next_element()? {
90 Some(x) => x,
91 None => {
92 return Err(M::Error::custom("Missing imaginary part".to_string()));
93 }
94 };
95
96 Ok(CalculatorComplex::new(real, imaginary))
97 }
98 }
99 let pp_visitor = ComplexVisitor;
100
101 deserializer.deserialize_tuple(2, pp_visitor)
102 }
103}
104
105impl Default for CalculatorComplex {
107 fn default() -> Self {
108 CalculatorComplex {
109 re: CalculatorFloat::Float(0.0),
110 im: CalculatorFloat::Float(0.0),
111 }
112 }
113}
114
115impl<'a> From<&'a CalculatorComplex> for CalculatorComplex {
122 fn from(item: &'a CalculatorComplex) -> Self {
123 (*item).clone()
124 }
125}
126
127impl<T1, T2> From<(T1, T2)> for CalculatorComplex
129where
130 T1: Into<CalculatorFloat>,
131 T2: Into<CalculatorFloat>,
132{
133 fn from(input: (T1, T2)) -> Self {
134 CalculatorComplex {
135 re: input.0.into(),
136 im: input.1.into(),
137 }
138 }
139}
140
141impl<T> From<T> for CalculatorComplex
148where
149 CalculatorFloat: From<T>,
150{
151 fn from(item: T) -> Self {
152 Self {
153 re: CalculatorFloat::from(item),
154 im: CalculatorFloat::Float(0.0),
155 }
156 }
157}
158
159impl From<Complex<f64>> for CalculatorComplex {
166 fn from(item: Complex<f64>) -> Self {
167 Self {
168 re: CalculatorFloat::from(item.re),
169 im: CalculatorFloat::from(item.im),
170 }
171 }
172}
173
174impl TryFrom<CalculatorComplex> for f64 {
185 type Error = CalculatorError;
186
187 fn try_from(value: CalculatorComplex) -> Result<Self, Self::Error> {
188 match value.im {
189 CalculatorFloat::Float(x) => {
190 if x != 0.0 {
191 return Err(CalculatorError::ComplexCanNotBeConvertedToFloat { val: value });
192 }
193 }
194 _ => return Err(CalculatorError::ComplexSymbolicNotConvertable { val: value }),
195 }
196 match value.re {
197 CalculatorFloat::Float(x) => Ok(x),
198 CalculatorFloat::Str(_) => {
199 Err(CalculatorError::ComplexSymbolicNotConvertable { val: value })
200 }
201 }
202 }
203}
204
205impl TryFrom<CalculatorComplex> for Complex<f64> {
216 type Error = CalculatorError;
217
218 fn try_from(value: CalculatorComplex) -> Result<Self, CalculatorError> {
219 let im = match value.im {
220 CalculatorFloat::Float(x) => x,
221 _ => return Err(CalculatorError::ComplexSymbolicNotConvertable { val: value }),
222 };
223 let re = match value.re {
224 CalculatorFloat::Float(x) => x,
225 CalculatorFloat::Str(_) => {
226 return Err(CalculatorError::ComplexSymbolicNotConvertable { val: value })
227 }
228 };
229 Ok(Complex::new(re, im))
230 }
231}
232
233impl fmt::Display for CalculatorComplex {
238 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
239 write!(f, "({} + i * {})", self.re, self.im)
240 }
241}
242
243impl CalculatorComplex {
244 pub const ZERO: CalculatorComplex = CalculatorComplex {
246 re: CalculatorFloat::Float(0.0),
247 im: CalculatorFloat::Float(0.0),
248 };
249
250 pub const ONE: CalculatorComplex = CalculatorComplex {
252 re: CalculatorFloat::Float(1.0),
253 im: CalculatorFloat::Float(0.0),
254 };
255
256 pub const I: CalculatorComplex = CalculatorComplex {
258 re: CalculatorFloat::Float(0.0),
259 im: CalculatorFloat::Float(1.0),
260 };
261
262 pub fn new<T1, T2>(re: T1, im: T2) -> Self
270 where
271 T1: Into<CalculatorFloat>,
272 T2: Into<CalculatorFloat>,
273 {
274 Self {
275 re: re.into(),
276 im: im.into(),
277 }
278 }
279
280 pub fn arg(&self) -> CalculatorFloat {
282 self.im.atan2(&self.re)
283 }
284 pub fn norm_sqr(&self) -> CalculatorFloat {
286 (self.re.clone() * &self.re) + (self.im.clone() * &self.im)
287 }
288 pub fn norm(&self) -> CalculatorFloat {
290 ((self.re.clone() * &self.re) + (self.im.clone() * &self.im)).sqrt()
291 }
292
293 pub fn abs(&self) -> CalculatorFloat {
295 self.norm()
296 }
297
298 pub fn conj(&self) -> CalculatorComplex {
300 Self {
301 re: self.re.clone(),
302 im: -self.im.clone(),
303 }
304 }
305 pub fn isclose<T>(&self, other: T) -> bool
307 where
308 T: Into<CalculatorComplex>,
309 {
310 let other_from: CalculatorComplex = other.into();
311 self.re.isclose(other_from.re) && self.im.isclose(other_from.im)
312 }
313}
314
315impl<T> ops::Add<T> for CalculatorComplex
322where
323 T: Into<CalculatorComplex>,
324{
325 type Output = Self;
326 fn add(self, other: T) -> Self {
327 let other_from = other.into();
328 CalculatorComplex {
329 re: self.re + other_from.re,
330 im: self.im + other_from.im,
331 }
332 }
333}
334
335impl std::iter::Sum for CalculatorComplex {
342 fn sum<I: Iterator<Item = CalculatorComplex>>(iter: I) -> Self {
343 let mut sum = CalculatorComplex::new(0, 0);
344 for i in iter {
345 sum += i;
346 }
347 sum
348 }
349}
350
351impl<T> ops::AddAssign<T> for CalculatorComplex
358where
359 T: Into<CalculatorComplex>,
360{
361 fn add_assign(&mut self, other: T) {
362 let other_from: CalculatorComplex = other.into();
363 *self = CalculatorComplex {
364 re: &self.re + other_from.re,
365 im: &self.im + other_from.im,
366 }
367 }
368}
369
370impl<T> ops::Sub<T> for CalculatorComplex
377where
378 T: Into<CalculatorComplex>,
379{
380 type Output = Self;
381 fn sub(self, other: T) -> Self {
382 let other_from: CalculatorComplex = other.into();
383 CalculatorComplex {
384 re: self.re - other_from.re,
385 im: self.im - other_from.im,
386 }
387 }
388}
389impl<T> ops::SubAssign<T> for CalculatorComplex
396where
397 T: Into<CalculatorComplex>,
398{
399 fn sub_assign(&mut self, other: T) {
400 let other_from: CalculatorComplex = other.into();
401 *self = CalculatorComplex {
402 re: self.re.clone() - other_from.re,
403 im: self.im.clone() - other_from.im,
404 }
405 }
406}
407
408impl ops::Neg for CalculatorComplex {
410 type Output = CalculatorComplex;
411
412 fn neg(self) -> Self {
413 CalculatorComplex {
414 re: -self.re,
415 im: -self.im,
416 }
417 }
418}
419
420impl<T> ops::Mul<T> for CalculatorComplex
427where
428 T: Into<CalculatorComplex>,
429{
430 type Output = Self;
431 fn mul(self, other: T) -> Self {
432 let other_from: CalculatorComplex = other.into();
433 CalculatorComplex {
434 re: self.re.clone() * &other_from.re - (self.im.clone() * &other_from.im),
435 im: self.re * &other_from.im + (self.im * &other_from.re),
436 }
437 }
438}
439impl<T> ops::MulAssign<T> for CalculatorComplex
446where
447 T: Into<CalculatorComplex>,
448{
449 fn mul_assign(&mut self, other: T) {
450 let other_from: CalculatorComplex = other.into();
451 *self = CalculatorComplex {
452 re: self.re.clone() * &other_from.re - (self.im.clone() * &other_from.im),
453 im: self.re.clone() * &other_from.im + (self.im.clone() * &other_from.re),
454 }
455 }
456}
457
458impl<T> ops::Div<T> for CalculatorComplex
465where
466 T: Into<CalculatorComplex>,
467{
468 type Output = Self;
469 fn div(self, other: T) -> Self {
470 let other_from: CalculatorComplex = other.into();
471 let norm = other_from.norm_sqr();
472 CalculatorComplex {
473 re: (self.re.clone() * &other_from.re + (self.im.clone() * &other_from.im)) / &norm,
474 im: (-self.re * &other_from.im + (self.im * &other_from.re)) / &norm,
475 }
476 }
477}
478impl<T> ops::DivAssign<T> for CalculatorComplex
485where
486 T: Into<CalculatorComplex>,
487{
488 fn div_assign(&mut self, other: T) {
489 let other_from: CalculatorComplex = other.into();
490 let norm = other_from.norm_sqr();
491 *self = CalculatorComplex {
492 re: (self.re.clone() * &other_from.re + (self.im.clone() * &other_from.im)) / &norm,
493 im: (-self.re.clone() * &other_from.im + (self.im.clone() * &other_from.re)) / &norm,
494 }
495 }
496}
497
498impl CalculatorComplex {
500 pub fn recip(&self) -> CalculatorComplex {
502 let norm = self.norm_sqr();
503 CalculatorComplex {
504 re: self.re.clone() / &norm,
505 im: -self.im.clone() / &norm,
506 }
507 }
508}
509
510#[cfg(test)]
511mod tests {
512 use crate::CalculatorComplex;
513 use crate::CalculatorFloat;
514 use num_complex::Complex;
515 #[cfg(feature = "json_schema")]
516 use schemars::schema_for;
517 use serde_test::assert_tokens;
518 use serde_test::Configure;
519 use serde_test::Token;
520 use std::convert::TryFrom;
521 use std::ops::Neg;
522
523 #[test]
525 fn from_int() {
526 let x = CalculatorComplex::from(3);
527 assert_eq!(x.re, CalculatorFloat::from(3));
528 assert_eq!(x.im, CalculatorFloat::from(0));
529 assert_eq!(
530 x,
531 CalculatorComplex {
532 re: CalculatorFloat::from(3),
533 im: CalculatorFloat::from(0)
534 }
535 );
536 assert_eq!(f64::try_from(x).unwrap(), 3.0)
537 }
538
539 #[test]
541 fn serde_readable() {
542 let complex_float = CalculatorComplex::new(0.1, 0.3);
543
544 assert_tokens(
545 &complex_float.readable(),
546 &[
547 Token::Tuple { len: 2 },
548 Token::F64(0.1),
549 Token::F64(0.3),
550 Token::TupleEnd,
551 ],
552 );
553 let complex_str = CalculatorComplex::new("a", "b");
554
555 assert_tokens(
556 &complex_str.readable(),
557 &[
558 Token::Tuple { len: 2 },
559 Token::Str("a"),
560 Token::Str("b"),
561 Token::TupleEnd,
562 ],
563 );
564 let complex_mixed = CalculatorComplex::new("a", -0.3);
565
566 assert_tokens(
567 &complex_mixed.readable(),
568 &[
569 Token::Tuple { len: 2 },
570 Token::Str("a"),
571 Token::F64(-0.3),
572 Token::TupleEnd,
573 ],
574 );
575
576 let complex_num_complex = Complex::<f64>::new(0.0, -3.0);
578 assert_tokens(
579 &complex_num_complex.readable(),
580 &[
581 Token::Tuple { len: 2 },
582 Token::F64(0.0),
583 Token::F64(-3.0),
584 Token::TupleEnd,
585 ],
586 );
587 }
588
589 #[cfg(feature = "json_schema")]
590 #[test]
591 fn test_json_schema_support() {
592 let schema = schema_for!(CalculatorComplex);
593 let serialized = serde_json::to_string(&schema).unwrap();
594 assert_eq!(serialized.as_str(), "{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"title\":\"CalculatorComplex\",\"type\":\"array\",\"maxItems\":2,\"minItems\":2,\"prefixItems\":[{\"$ref\":\"#/$defs/CalculatorFloat\"},{\"$ref\":\"#/$defs/CalculatorFloat\"}],\"$defs\":{\"CalculatorFloat\":{\"oneOf\":[{\"type\":\"number\",\"format\":\"double\"},{\"type\":\"string\"}]}}}");
595 }
596
597 #[test]
599 fn from_float() {
600 let x = CalculatorComplex::from(3.1);
601 assert_eq!(x.re, CalculatorFloat::from(3.1));
602 assert_eq!(x.im, CalculatorFloat::from(0));
603 assert_eq!(
604 x,
605 CalculatorComplex {
606 re: CalculatorFloat::from(3.1),
607 im: CalculatorFloat::from(0)
608 }
609 );
610 }
611
612 #[test]
614 fn from_str() {
615 let x = CalculatorComplex::from("3.1");
616 assert_eq!(x.re, CalculatorFloat::from("3.1"));
617 assert_eq!(x.im, CalculatorFloat::from(0));
618 assert_eq!(
619 x,
620 CalculatorComplex {
621 re: CalculatorFloat::from("3.1"),
622 im: CalculatorFloat::from(0)
623 }
624 );
625 }
626
627 #[test]
629 fn from_complex() {
630 let x = CalculatorComplex::from(Complex::new(1.0, 2.0));
631 assert_eq!(x.re, CalculatorFloat::from(1.0));
632 assert_eq!(x.im, CalculatorFloat::from(2.00));
633 assert_eq!(
634 x,
635 CalculatorComplex {
636 re: CalculatorFloat::from(1.0),
637 im: CalculatorFloat::from(2.0)
638 }
639 );
640 }
641
642 #[test]
644 fn from_calculator_complex() {
645 let x = CalculatorComplex::new(1, 1);
646 assert_eq!(CalculatorComplex::from(&x), x);
647 }
648
649 #[test]
651 fn default() {
652 let x = CalculatorComplex::default();
653 assert_eq!(x.re, CalculatorFloat::from(0.0));
654 assert_eq!(x.im, CalculatorFloat::from(0.0));
655 assert_eq!(x, CalculatorComplex::new(0, 0));
656 }
657
658 #[test]
660 fn try_from_float() {
661 let x = CalculatorComplex::new(1.0, 0.0);
662 assert_eq!(<f64>::try_from(x).unwrap(), 1.0);
663
664 let x = CalculatorComplex::new(0.0, 1.0);
665 assert!(f64::try_from(x).is_err());
666
667 let x = CalculatorComplex::new("x", 0.0);
668 assert!(f64::try_from(x).is_err());
669
670 let x = CalculatorComplex::new(1.0, "x");
671 assert!(f64::try_from(x).is_err());
672 }
673
674 #[test]
676 fn try_from_complex() {
677 let x = CalculatorComplex::new(1, 1);
678 assert_eq!(Complex::<f64>::try_from(x).unwrap(), Complex::new(1.0, 1.0));
679
680 let x = CalculatorComplex::new(0.0, "x");
681 assert!(Complex::<f64>::try_from(x).is_err());
682
683 let x = CalculatorComplex::new("x", 0.0);
684 assert!(Complex::<f64>::try_from(x).is_err());
685 }
686
687 #[test]
689 fn display() {
690 let x = CalculatorComplex::new(-3, 2);
691 let x_formatted = format!("{x}");
692 assert_eq!(x_formatted, "(-3e0 + i * 2e0)");
693 }
694
695 #[test]
697 fn try_add() {
698 let x = CalculatorComplex::new(1, 1);
699 let y = CalculatorComplex::new(2, "test");
700 assert_eq!(x + y, CalculatorComplex::new(3.0, "(1e0 + test)"));
701 }
702
703 #[test]
705 fn try_iadd() {
706 let mut x = CalculatorComplex::new(1, 1);
707 let y = CalculatorComplex::new(2, "test");
708 x += y;
709 assert_eq!(x, CalculatorComplex::new(3.0, "(1e0 + test)"));
710 }
711
712 #[test]
714 fn try_sub() {
715 let x = CalculatorComplex::new(1, 1);
716 let y = CalculatorComplex::new(2, "test");
717 assert_eq!(x - y, CalculatorComplex::new(-1.0, "(1e0 - test)"));
718 }
719
720 #[test]
722 fn try_isub() {
723 let mut x = CalculatorComplex::new(1, 1);
724 let y = CalculatorComplex::new(2, "test");
725 x -= y;
726 assert_eq!(x, CalculatorComplex::new(-1.0, "(1e0 - test)"));
727 }
728
729 #[test]
731 fn try_mul() {
732 let x = CalculatorComplex::new(1, 1);
733 let y = CalculatorComplex::new(2, 2);
734 assert_eq!(x * y, CalculatorComplex::new(0.0, 4.0));
735 }
736
737 #[test]
739 fn try_imul() {
740 let mut x = CalculatorComplex::new(1, 1);
741 let y = CalculatorComplex::new(2, 2);
742 x *= y;
743 assert_eq!(x, CalculatorComplex::new(0.0, 4.0));
744 }
745
746 #[test]
748 fn try_div() {
749 let x = CalculatorComplex::new(1, 1);
750 let y = CalculatorComplex::new(3, 4);
751 assert_eq!(x / y, CalculatorComplex::new(7.0 / 25.0, -1.0 / 25.0));
752 }
753
754 #[test]
756 fn try_idiv() {
757 let mut x = CalculatorComplex::new(1, 1);
758 let y = CalculatorComplex::new(3, 4);
759 x /= y;
760 assert_eq!(x, CalculatorComplex::new(7.0 / 25.0, -1.0 / 25.0));
761 }
762
763 #[test]
765 fn arg() {
766 let x = CalculatorComplex::new(1, 2);
767 let y = Complex::new(1.0, 2.0);
768 assert_eq!(x.arg(), CalculatorFloat::from(y.arg()));
769
770 let x = CalculatorComplex::new("x", 2);
771 assert_eq!(x.arg(), CalculatorFloat::from("atan2(2e0, x)"));
772
773 let x = CalculatorComplex::new(1, "2x");
774 assert_eq!(x.arg(), CalculatorFloat::from("atan2(2x, 1e0)"));
775
776 let x = CalculatorComplex::new("x", "2t");
777 assert_eq!(x.arg(), CalculatorFloat::from("atan2(2t, x)"));
778 }
779
780 #[test]
782 fn norm_sqr() {
783 let x = CalculatorComplex::new(1, 2);
784 let y = Complex::new(1.0, 2.0);
785 assert_eq!(x.norm_sqr(), CalculatorFloat::from(y.norm_sqr()));
786 }
787
788 #[test]
790 fn norm() {
791 let x = CalculatorComplex::new(1, 2);
792 let y = Complex::new(1.0, 2.0);
793 assert_eq!(x.norm(), CalculatorFloat::from(y.norm()));
794 }
795
796 #[test]
797 fn abs() {
798 let x = CalculatorComplex::new(1, 2);
799 let y = Complex::new(1.0, 2.0);
800 assert_eq!(x.abs(), CalculatorFloat::from(y.norm()));
801 }
802
803 #[test]
805 fn conj() {
806 let x = CalculatorComplex::new(1, 2);
807 let y = Complex::new(1.0, 2.0);
808 assert_eq!(x.conj(), CalculatorComplex::new(y.conj().re, y.conj().im));
809 }
810
811 #[test]
813 fn is_close() {
814 let x = CalculatorComplex::new(1, 2);
815 let y = Complex::new(1.0, 2.0);
816 assert!(x.isclose(y));
817
818 let y = 1.0;
819 assert!(!x.isclose(y));
820 }
821
822 #[test]
824 fn neg() {
825 let x = CalculatorComplex::new(1, 2);
826 assert_eq!(x.neg(), CalculatorComplex::new(-1, -2));
827 }
828
829 #[test]
831 fn inv() {
832 let x = CalculatorComplex::new(3, 4);
833 assert_eq!(x.recip(), CalculatorComplex::new(0.12, -0.16));
834 }
835
836 #[test]
838 fn debug() {
839 let x = CalculatorComplex::from(3.0);
840 assert_eq!(
841 format!("{x:?}"),
842 "CalculatorComplex { re: Float(3.0), im: Float(0.0) }"
843 );
844
845 let xs = CalculatorComplex::from("3x");
846 assert_eq!(
847 format!("{xs:?}"),
848 "CalculatorComplex { re: Str(\"3x\"), im: Float(0.0) }"
849 );
850 }
851
852 #[test]
854 fn clone_trait() {
855 let x = CalculatorComplex::from(3.0);
856 assert_eq!(x.clone(), x);
857
858 let xs = CalculatorComplex::from("3x");
859 assert_eq!(xs.clone(), xs);
860 }
861
862 #[test]
864 fn partial_eq() {
865 let x1 = CalculatorComplex::from(3.0);
866 let x2 = CalculatorComplex::from(3.0);
867 assert!(x1 == x2);
868 assert!(x2 == x1);
869
870 let x1s = CalculatorComplex::from("3x");
871 let x2s = CalculatorComplex::from("3x");
872 assert!(x1s == x2s);
873 assert!(x2s == x1s);
874 }
875}
876