Skip to main content

tenflowers_core/
complex.rs

1//! Complex number types and operations for TenfloweRS
2//!
3//! This module provides Complex32 and Complex64 types to support FFT operations
4//! and other complex number computations.
5
6use scirs2_core::numeric::{One, Zero};
7use std::fmt;
8use std::ops::{Add, Div, Mul, Neg, Sub};
9
10/// 32-bit complex number (f32 real and imaginary parts)
11#[derive(Debug, Clone, Copy, PartialEq)]
12pub struct Complex32 {
13    pub real: f32,
14    pub imag: f32,
15}
16
17/// 64-bit complex number (f64 real and imaginary parts)
18#[derive(Debug, Clone, Copy, PartialEq)]
19pub struct Complex64 {
20    pub real: f64,
21    pub imag: f64,
22}
23
24impl Complex32 {
25    /// Create a new complex number
26    pub fn new(real: f32, imag: f32) -> Self {
27        Self { real, imag }
28    }
29
30    /// Create a complex number from a real number
31    pub fn from_real(real: f32) -> Self {
32        Self { real, imag: 0.0 }
33    }
34
35    /// Create a complex number from an imaginary number
36    pub fn from_imag(imag: f32) -> Self {
37        Self { real: 0.0, imag }
38    }
39
40    /// Get the magnitude (absolute value) of the complex number
41    pub fn magnitude(&self) -> f32 {
42        (self.real * self.real + self.imag * self.imag).sqrt()
43    }
44
45    /// Get the phase (argument) of the complex number
46    pub fn phase(&self) -> f32 {
47        self.imag.atan2(self.real)
48    }
49
50    /// Get the complex conjugate
51    pub fn conjugate(&self) -> Self {
52        Self {
53            real: self.real,
54            imag: -self.imag,
55        }
56    }
57
58    /// Convert to polar form (magnitude, phase)
59    pub fn to_polar(&self) -> (f32, f32) {
60        (self.magnitude(), self.phase())
61    }
62
63    /// Create from polar form (magnitude, phase)
64    pub fn from_polar(magnitude: f32, phase: f32) -> Self {
65        Self {
66            real: magnitude * phase.cos(),
67            imag: magnitude * phase.sin(),
68        }
69    }
70}
71
72impl Complex64 {
73    /// Create a new complex number
74    pub fn new(real: f64, imag: f64) -> Self {
75        Self { real, imag }
76    }
77
78    /// Create a complex number from a real number
79    pub fn from_real(real: f64) -> Self {
80        Self { real, imag: 0.0 }
81    }
82
83    /// Create a complex number from an imaginary number
84    pub fn from_imag(imag: f64) -> Self {
85        Self { real: 0.0, imag }
86    }
87
88    /// Get the magnitude (absolute value) of the complex number
89    pub fn magnitude(&self) -> f64 {
90        (self.real * self.real + self.imag * self.imag).sqrt()
91    }
92
93    /// Get the phase (argument) of the complex number
94    pub fn phase(&self) -> f64 {
95        self.imag.atan2(self.real)
96    }
97
98    /// Get the complex conjugate
99    pub fn conjugate(&self) -> Self {
100        Self {
101            real: self.real,
102            imag: -self.imag,
103        }
104    }
105
106    /// Convert to polar form (magnitude, phase)
107    pub fn to_polar(&self) -> (f64, f64) {
108        (self.magnitude(), self.phase())
109    }
110
111    /// Create from polar form (magnitude, phase)
112    pub fn from_polar(magnitude: f64, phase: f64) -> Self {
113        Self {
114            real: magnitude * phase.cos(),
115            imag: magnitude * phase.sin(),
116        }
117    }
118}
119
120// Arithmetic operations for Complex32
121impl Add for Complex32 {
122    type Output = Self;
123
124    fn add(self, other: Self) -> Self {
125        Self {
126            real: self.real + other.real,
127            imag: self.imag + other.imag,
128        }
129    }
130}
131
132impl Sub for Complex32 {
133    type Output = Self;
134
135    fn sub(self, other: Self) -> Self {
136        Self {
137            real: self.real - other.real,
138            imag: self.imag - other.imag,
139        }
140    }
141}
142
143impl Mul for Complex32 {
144    type Output = Self;
145
146    fn mul(self, other: Self) -> Self {
147        Self {
148            real: self.real * other.real - self.imag * other.imag,
149            imag: self.real * other.imag + self.imag * other.real,
150        }
151    }
152}
153
154impl Div for Complex32 {
155    type Output = Self;
156
157    fn div(self, other: Self) -> Self {
158        let denom = other.real * other.real + other.imag * other.imag;
159        Self {
160            real: (self.real * other.real + self.imag * other.imag) / denom,
161            imag: (self.imag * other.real - self.real * other.imag) / denom,
162        }
163    }
164}
165
166impl Neg for Complex32 {
167    type Output = Self;
168
169    fn neg(self) -> Self {
170        Self {
171            real: -self.real,
172            imag: -self.imag,
173        }
174    }
175}
176
177// Arithmetic operations for Complex64
178impl Add for Complex64 {
179    type Output = Self;
180
181    fn add(self, other: Self) -> Self {
182        Self {
183            real: self.real + other.real,
184            imag: self.imag + other.imag,
185        }
186    }
187}
188
189impl Sub for Complex64 {
190    type Output = Self;
191
192    fn sub(self, other: Self) -> Self {
193        Self {
194            real: self.real - other.real,
195            imag: self.imag - other.imag,
196        }
197    }
198}
199
200impl Mul for Complex64 {
201    type Output = Self;
202
203    fn mul(self, other: Self) -> Self {
204        Self {
205            real: self.real * other.real - self.imag * other.imag,
206            imag: self.real * other.imag + self.imag * other.real,
207        }
208    }
209}
210
211impl Div for Complex64 {
212    type Output = Self;
213
214    fn div(self, other: Self) -> Self {
215        let denom = other.real * other.real + other.imag * other.imag;
216        Self {
217            real: (self.real * other.real + self.imag * other.imag) / denom,
218            imag: (self.imag * other.real - self.real * other.imag) / denom,
219        }
220    }
221}
222
223impl Neg for Complex64 {
224    type Output = Self;
225
226    fn neg(self) -> Self {
227        Self {
228            real: -self.real,
229            imag: -self.imag,
230        }
231    }
232}
233
234// Zero and One traits for Complex32
235impl Zero for Complex32 {
236    fn zero() -> Self {
237        Self {
238            real: 0.0,
239            imag: 0.0,
240        }
241    }
242
243    fn is_zero(&self) -> bool {
244        self.real == 0.0 && self.imag == 0.0
245    }
246}
247
248impl One for Complex32 {
249    fn one() -> Self {
250        Self {
251            real: 1.0,
252            imag: 0.0,
253        }
254    }
255}
256
257// Zero and One traits for Complex64
258impl Zero for Complex64 {
259    fn zero() -> Self {
260        Self {
261            real: 0.0,
262            imag: 0.0,
263        }
264    }
265
266    fn is_zero(&self) -> bool {
267        self.real == 0.0 && self.imag == 0.0
268    }
269}
270
271impl One for Complex64 {
272    fn one() -> Self {
273        Self {
274            real: 1.0,
275            imag: 0.0,
276        }
277    }
278}
279
280// Default implementations
281impl Default for Complex32 {
282    fn default() -> Self {
283        Self::zero()
284    }
285}
286
287impl Default for Complex64 {
288    fn default() -> Self {
289        Self::zero()
290    }
291}
292
293// Display implementations
294impl fmt::Display for Complex32 {
295    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
296        if self.imag >= 0.0 {
297            write!(f, "{}+{}i", self.real, self.imag)
298        } else {
299            write!(f, "{}{}i", self.real, self.imag)
300        }
301    }
302}
303
304impl fmt::Display for Complex64 {
305    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
306        if self.imag >= 0.0 {
307            write!(f, "{}+{}i", self.real, self.imag)
308        } else {
309            write!(f, "{}{}i", self.real, self.imag)
310        }
311    }
312}
313
314// Conversions
315impl From<f32> for Complex32 {
316    fn from(real: f32) -> Self {
317        Self::from_real(real)
318    }
319}
320
321impl From<f64> for Complex64 {
322    fn from(real: f64) -> Self {
323        Self::from_real(real)
324    }
325}
326
327impl From<Complex32> for Complex64 {
328    fn from(c: Complex32) -> Self {
329        Self {
330            real: c.real as f64,
331            imag: c.imag as f64,
332        }
333    }
334}
335
336impl From<Complex64> for Complex32 {
337    fn from(c: Complex64) -> Self {
338        Self {
339            real: c.real as f32,
340            imag: c.imag as f32,
341        }
342    }
343}
344
345#[cfg(test)]
346mod tests {
347    use super::*;
348
349    #[test]
350    fn test_complex32_arithmetic() {
351        let a = Complex32::new(3.0, 4.0);
352        let b = Complex32::new(1.0, 2.0);
353
354        let sum = a + b;
355        assert_eq!(sum.real, 4.0);
356        assert_eq!(sum.imag, 6.0);
357
358        let product = a * b;
359        assert_eq!(product.real, -5.0);
360        assert_eq!(product.imag, 10.0);
361    }
362
363    #[test]
364    fn test_complex64_magnitude() {
365        let c = Complex64::new(3.0, 4.0);
366        assert_eq!(c.magnitude(), 5.0);
367    }
368
369    #[test]
370    fn test_complex_conjugate() {
371        let c = Complex32::new(3.0, 4.0);
372        let conj = c.conjugate();
373        assert_eq!(conj.real, 3.0);
374        assert_eq!(conj.imag, -4.0);
375    }
376}