1use std::marker::PhantomData;
8
9use num_complex::Complex as NumComplex;
10
11use crate::domain::Domain;
12
13#[derive(Debug, Clone, PartialEq, Eq, Hash)]
15pub struct Complex<D: Domain> {
16 inner: NumComplex<D::Element>,
17}
18
19impl<D: Domain> Complex<D> {
20 pub fn new(real: D::Element, imag: D::Element) -> Self {
22 Self {
23 inner: NumComplex::new(real, imag),
24 }
25 }
26
27 pub fn re(&self) -> &D::Element {
29 &self.inner.re
30 }
31
32 pub fn im(&self) -> &D::Element {
34 &self.inner.im
35 }
36
37 pub fn inner(&self) -> &NumComplex<D::Element> {
39 &self.inner
40 }
41}
42
43#[derive(Debug, Clone, Copy, PartialEq, Eq)]
45pub struct ComplexDomain<D: Domain> {
46 base: D,
47 _marker: PhantomData<D>,
48}
49
50impl<D: Domain> ComplexDomain<D> {
51 pub fn new(base: D) -> Self {
53 Self {
54 base,
55 _marker: PhantomData,
56 }
57 }
58
59 pub fn base(&self) -> &D {
61 &self.base
62 }
63
64 pub fn real_element(&self, re: D::Element) -> Complex<D> {
66 Complex::new(re, self.base.zero())
67 }
68
69 pub fn imag_element(&self, im: D::Element) -> Complex<D> {
71 Complex::new(self.base.zero(), im)
72 }
73}
74
75impl<D: Domain> Domain for ComplexDomain<D> {
76 type Element = Complex<D>;
77
78 fn zero(&self) -> Self::Element {
79 Complex::new(self.base.zero(), self.base.zero())
80 }
81
82 fn one(&self) -> Self::Element {
83 Complex::new(self.base.one(), self.base.zero())
84 }
85
86 fn add(&self, a: &Self::Element, b: &Self::Element) -> Self::Element {
87 Complex::new(self.base.add(a.re(), b.re()), self.base.add(a.im(), b.im()))
88 }
89
90 fn sub(&self, a: &Self::Element, b: &Self::Element) -> Self::Element {
91 Complex::new(self.base.sub(a.re(), b.re()), self.base.sub(a.im(), b.im()))
92 }
93
94 fn neg(&self, a: &Self::Element) -> Self::Element {
95 Complex::new(self.base.neg(a.re()), self.base.neg(a.im()))
96 }
97
98 fn mul(&self, a: &Self::Element, b: &Self::Element) -> Self::Element {
99 let ac = self.base.mul(a.re(), b.re());
101 let bd = self.base.mul(a.im(), b.im());
102 let ad = self.base.mul(a.re(), b.im());
103 let bc = self.base.mul(a.im(), b.re());
104 Complex::new(self.base.sub(&ac, &bd), self.base.add(&ad, &bc))
105 }
106
107 fn div(&self, a: &Self::Element, b: &Self::Element) -> Option<Self::Element> {
108 let c2 = self.base.mul(b.re(), b.re());
110 let d2 = self.base.mul(b.im(), b.im());
111 let denom = self.base.add(&c2, &d2);
112 let ac = self.base.mul(a.re(), b.re());
113 let bd = self.base.mul(a.im(), b.im());
114 let bc = self.base.mul(a.im(), b.re());
115 let ad = self.base.mul(a.re(), b.im());
116 let real_num = self.base.add(&ac, &bd);
117 let imag_num = self.base.sub(&bc, &ad);
118 let real = self.base.div(&real_num, &denom)?;
119 let imag = self.base.div(&imag_num, &denom)?;
120 Some(Complex::new(real, imag))
121 }
122
123 fn inv(&self, a: &Self::Element) -> Option<Self::Element> {
124 self.div(&self.one(), a)
125 }
126}
127
128#[cfg(test)]
129mod tests {
130 use super::*;
131 use crate::{IntegerDomain, Rational, RationalDomain};
132
133 #[test]
134 fn complex_addition() {
135 let base = IntegerDomain;
136 let domain = ComplexDomain::new(base);
137 let a = Complex::new(1.into(), 2.into());
138 let b = Complex::new(3.into(), 4.into());
139 let sum = domain.add(&a, &b);
140 assert_eq!(sum.re(), &4.into());
141 assert_eq!(sum.im(), &6.into());
142 }
143
144 #[test]
145 fn complex_multiplication() {
146 let base = IntegerDomain;
147 let domain = ComplexDomain::new(base);
148 let a = Complex::new(1.into(), 2.into());
149 let b = Complex::new(3.into(), 4.into());
150 let prod = domain.mul(&a, &b);
151 assert_eq!(prod.re(), &(-5).into());
153 assert_eq!(prod.im(), &10.into());
154 }
155
156 #[test]
157 fn complex_i_squared_is_minus_one() {
158 let base = IntegerDomain;
159 let domain = ComplexDomain::new(base);
160 let i = domain.imag_element(1.into());
161 let i2 = domain.mul(&i, &i);
162 assert_eq!(i2.re(), &(-1).into());
163 assert_eq!(i2.im(), &0.into());
164 }
165
166 #[test]
167 fn complex_inverse_over_rationals() {
168 let base = RationalDomain;
169 let domain = ComplexDomain::new(base);
170 let z = Complex::new(Rational::new(1, 1), Rational::new(1, 1));
171 let inv = domain.inv(&z).expect("non-zero complex is invertible");
172 let prod = domain.mul(&z, &inv);
173 assert_eq!(prod, domain.one());
174 }
175}