qoqo_calculator/
calculator_complex.rs

1// Copyright © 2020-2025 HQS Quantum Simulations GmbH. All Rights Reserved.
2//
3// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
4// in compliance with the License. You may obtain a copy of the License at
5//
6//     http://www.apache.org/licenses/LICENSE-2.0
7//
8// Unless required by applicable law or agreed to in writing, software distributed under the
9// License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
10// express or implied. See the License for the specific language governing permissions and
11// limitations underthe License.
12
13//! calculator_complex module
14//!
15//! Provides CalculatorComplex struct and methods for parsing and evaluating
16//! mathematical expressions in string form to complex.
17
18use 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/// Struct CalculatorComplex.
30///
31///
32#[derive(Debug, Clone, PartialEq)]
33pub struct CalculatorComplex {
34    /// CalculatorFloat value of real part of CalculatorComplex
35    pub re: CalculatorFloat,
36    /// CalculatorFloat value of imaginary part of CalculatorComplex
37    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            // when variants are marked by String values
78            fn visit_seq<M>(self, mut access: M) -> Result<Self::Value, M::Error>
79            where
80                M: SeqAccess<'de>,
81            {
82                // let visitor = TupleVisitor;
83                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
105/// Implement Default value 0 for CalculatorComplex.
106impl 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
115/// Initialize CalculatorComplex from CalculatorComplex reference &CalculatorComplex.
116///
117/// # Returns
118///
119/// * `CalculatorFloat`
120///
121impl<'a> From<&'a CalculatorComplex> for CalculatorComplex {
122    fn from(item: &'a CalculatorComplex) -> Self {
123        (*item).clone()
124    }
125}
126
127/// I
128impl<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
141/// Initialize CalculatorComplex from type that can be cast to CalculatorFloat.
142///
143/// # Returns
144///
145/// * `CalculatorComplex`
146///
147impl<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
159/// Initialize CalculatorComplex from Complex.
160///
161/// # Returns
162///
163/// * `CalculatorComplex`
164///
165impl 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
174/// Try turning CalculatorComplex into f64 float.
175///
176/// # Returns
177///
178/// * `f64`
179///
180/// # Panics
181///
182/// Panics when CalculatorFloat contains symbolic string value
183///
184impl 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
205/// Try turning CalculatorComplex into Complex<f64> float.
206///
207/// # Returns
208///
209/// * `f64`
210///
211/// # Panics
212///
213/// Panics when CalculatorFloat contains symbolic string value
214///
215impl 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
233/// Implement Display trait for CalculatorComplex.
234///
235/// Allows use of simple text formating
236///
237impl 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    /// Constant zero for CalculatorComplex
245    pub const ZERO: CalculatorComplex = CalculatorComplex {
246        re: CalculatorFloat::Float(0.0),
247        im: CalculatorFloat::Float(0.0),
248    };
249
250    /// Constant one for CalculatorFloat
251    pub const ONE: CalculatorComplex = CalculatorComplex {
252        re: CalculatorFloat::Float(1.0),
253        im: CalculatorFloat::Float(0.0),
254    };
255
256    /// Constant imaginary number for CalculatorFloat
257    pub const I: CalculatorComplex = CalculatorComplex {
258        re: CalculatorFloat::Float(0.0),
259        im: CalculatorFloat::Float(1.0),
260    };
261
262    /// Return CalculatorComplex constructed form pair of real values.
263    ///
264    /// # Arguments
265    ///
266    /// * `re` - Real part given as type that can be converted to CalculatorFloat
267    /// * `im` - Imaginary part given as type that can be converted to CalculatorFloat
268    ///
269    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    /// Return phase of complex number x: arg(x).
281    pub fn arg(&self) -> CalculatorFloat {
282        self.im.atan2(&self.re)
283    }
284    /// Return square norm of complex number x: |x|^2=x.re^2+x.im^2.
285    pub fn norm_sqr(&self) -> CalculatorFloat {
286        (self.re.clone() * &self.re) + (self.im.clone() * &self.im)
287    }
288    /// Return norm of complex number x: |x|=(x.re^2+x.im^2)^1/2.
289    pub fn norm(&self) -> CalculatorFloat {
290        ((self.re.clone() * &self.re) + (self.im.clone() * &self.im)).sqrt()
291    }
292
293    /// Return absolute value of complex number x: |x|=(x.re^2+x.im^2)^1/2.
294    pub fn abs(&self) -> CalculatorFloat {
295        self.norm()
296    }
297
298    /// Return complex conjugate of x: x*=x.re-i*x.im.
299    pub fn conj(&self) -> CalculatorComplex {
300        Self {
301            re: self.re.clone(),
302            im: -self.im.clone(),
303        }
304    }
305    /// Return true when x is close to y.
306    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
315/// Implement `+` for CalculatorComplex and generic type `T`.
316///
317/// # Arguments
318///
319/// * `other` - Any type T for which CalculatorComplex::From<T> trait is implemented
320///
321impl<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
335/// Implements summing over an iterator of CalculatorComplex
336///
337/// # Arguments
338///
339/// * `iter` - Any iterator over CalculatorComplex items
340///
341impl 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
351/// Implement `+=` for CalculatorComplex and generic type `T`.
352///
353/// # Arguments
354///
355/// * `other` - Any type T for which CalculatorComplex::From<T> trait is implemented
356///
357impl<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
370/// Implement `-` for CalculatorComplex and generic type `T`.
371///
372/// # Arguments
373///
374/// * `other` - Any type T for which CalculatorComplex::From<T> trait is implemented
375///
376impl<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}
389/// Implement `-=` for CalculatorComplex and generic type `T`.
390///
391/// # Arguments
392///
393/// * `other` - Any type T for which CalculatorComplex::From<T> trait is implemented
394///
395impl<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
408/// Implement minus sign for CalculatorComplex.
409impl 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
420/// Implement `*` for CalculatorComplex and generic type `T`.
421///
422/// # Arguments
423///
424/// * `other` - Any type T for which CalculatorComplex::From<T> trait is implemented
425///
426impl<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}
439/// Implement `*=` for CalculatorComplex and generic type `T`.
440///
441/// # Arguments
442///
443/// * `other` - Any type T for which CalculatorComplex::From<T> trait is implemented
444///
445impl<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
458/// Implement `*` for CalculatorComplex and generic type `T`.
459///
460/// # Arguments
461///
462/// * `other` - Any type T for which CalculatorComplex::From<T> trait is implemented
463///
464impl<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}
478/// Implement `*=` for CalculatorComplex and generic type `T`.
479///
480/// # Arguments
481///
482/// * `other` - Any type T for which CalculatorComplex::From<T> trait is implemented
483///
484impl<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
498/// Implement Inverse `1/x` for CalculatorFloat.
499impl CalculatorComplex {
500    /// Returns Inverse `1/x` for CalculatorFloat.
501    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 the initialisation of CalculatorComplex from integer input
524    #[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 serde serialisation
540    #[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        // Checking that num_complex serialisation is still using tuple serialisation
577        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 the initialisation of CalculatorComplex from float input
598    #[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 the initialisation of CalculatorComplex from string input
613    #[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 the initialisation of CalculatorComplex from complex input
628    #[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 the initialisation of CalculatorComplex from Calculatorcomplex reference input
643    #[test]
644    fn from_calculator_complex() {
645        let x = CalculatorComplex::new(1, 1);
646        assert_eq!(CalculatorComplex::from(&x), x);
647    }
648
649    // Test the default function of CalculatorComplex
650    #[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 the conversion of CalculatorComplex to Float
659    #[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 the conversion of CalculatorComplex to Complex
675    #[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 the Display trait of CalculatorComplex
688    #[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 the addition functionality of CalculatorComplex
696    #[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 the add_assign functionality of CalculatorComplex
704    #[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 the subtract functionality of CalculatorComplex
713    #[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 the sub_assign functionality of CalculatorComplex
721    #[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 the multiply functionality of CalculatorComplex
730    #[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 the mul_assign functionality of CalculatorComplex
738    #[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 the division functionality of CalculatorComplex
747    #[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 the div_assign functionality of CalculatorComplex
755    #[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 the arg(x) functionality of CalculatorComplex with all possible input types
764    #[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 the square norm functionality of CalculatorComplex
781    #[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 the norm functionality of CalculatorComplex
789    #[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 the conjugate functionality of CalculatorComplex
804    #[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 the isclose functionality of CalculatorComplex
812    #[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 the negative sign (*-1) functionality of CalculatorComplex
823    #[test]
824    fn neg() {
825        let x = CalculatorComplex::new(1, 2);
826        assert_eq!(x.neg(), CalculatorComplex::new(-1, -2));
827    }
828
829    // Test the inverse functionality of CalculatorComplex
830    #[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 the Debug trait for CalculatorComplex
837    #[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 the Clone trait for CalculatorComplex
853    #[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 the PartialEq trait for CalculatorComplex
863    #[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// End of tests