rs_sci/
complex.rs

1use std::fmt::{Display, Formatter, Result as FmtResult};
2use std::ops::{Add, Div, Mul, Neg, Sub};
3
4#[derive(Debug, Clone, Copy, PartialEq)]
5pub struct Complex<T> {
6    re: T,
7    im: T,
8}
9
10#[macro_export]
11macro_rules! complex {
12    ($re:expr, $im:expr) => {
13        Complex::<f32>::new($re as f32, $im as f32)
14    };
15    ($re:expr) => {
16        Complex::<f32>::new($re as f32, 0.0)
17    };
18}
19
20#[macro_export]
21macro_rules! im {
22    ($im:expr) => {
23        Complex::<f32>::new(0.0, $im as f32)
24    };
25}
26
27impl<T> Complex<T> {
28    /// creates new complex number from real and imaginary parts
29    ///
30    /// #### Example
31    /// ```txt
32    /// let z = Complex::new(3.0, 4.0); // 3 + 4i
33    /// ```
34    /// ---
35    /// basic constructor for complex numbers
36    pub fn new(re: T, im: T) -> Self {
37        Self { re, im }
38    }
39}
40
41impl<T: Copy> Complex<T> {
42    pub fn re(&self) -> T {
43        self.re
44    }
45
46    pub fn im(&self) -> T {
47        self.im
48    }
49}
50
51impl Complex<f64> {
52    /// calculates absolute value (modulus) of complex number
53    ///
54    /// #### Example
55    /// ```txt
56    /// let z = Complex::new(3.0, 4.0);
57    /// assert_eq!(z.modulus(), 5.0);
58    /// ```
59    /// ---
60    /// computes √(re² + im²)
61    pub fn modulus(&self) -> f64 {
62        (self.re * self.re + self.im * self.im).sqrt()
63    }
64
65    /// calculates argument (phase) of complex number
66    ///
67    /// #### Example
68    /// ```txt
69    /// let z = Complex::new(1.0, 1.0);
70    /// assert_eq!(z.argument(), std::f64::consts::PI/4.0);
71    /// ```
72    /// ---
73    /// returns angle in radians from positive real axis
74
75    pub fn argument(&self) -> f64 {
76        self.im.atan2(self.re)
77    }
78    /// returns complex conjugate
79    ///
80    /// #### Example
81    /// ```txt
82    /// let z = Complex::new(3.0, 4.0);
83    /// let conj = z.conjugate(); // 3 - 4i
84    /// ```
85    /// ---
86    /// negates imaginary part while keeping real part
87
88    pub fn conjugate(&self) -> Self {
89        Self::new(self.re, -self.im)
90    }
91    /// computes exponential of complex number
92    ///
93    /// #### Example
94    /// ```txt
95    /// let z = Complex::I * std::f64::consts::PI;
96    /// let exp_z = z.exp(); // ≈ -1 + 0i
97    /// ```
98    /// ---
99    /// uses euler's formula: e^(a+bi) = e^a(cos(b) + i*sin(b))
100    pub fn exp(&self) -> Self {
101        let r = self.re.exp();
102        Self::new(r * self.im.cos(), r * self.im.sin())
103    }
104    /// computes natural logarithm of complex number
105    ///
106    /// #### Example
107    /// ```txt
108    /// let z = Complex::new(1.0, 0.0);
109    /// let ln_z = z.ln(); // 0 + 0i
110    /// ```
111    /// ---
112    /// returns ln|z| + i*arg(z)
113    pub fn ln(&self) -> Self {
114        Complex::new(self.modulus().ln(), self.argument())
115    }
116    /// raises complex number to real power
117    ///
118    /// #### Example
119    /// ```txt
120    /// let z = Complex::new(1.0, 1.0);
121    /// let z_squared = z.pow(2.0);
122    /// ```
123    /// ---
124    /// uses polar form for computation
125    pub fn pow(&self, n: f64) -> Self {
126        let r = self.modulus().powf(n);
127        let theta = self.argument() * n;
128        Self::new(r * theta.cos(), r * theta.sin())
129    }
130    /// calculates square root of complex number
131    ///
132    /// #### Example
133    /// ```txt
134    /// let z = Complex::new(-1.0, 0.0);
135    /// let sqrt_z = z.sqrt(); // 0 + 1i
136    /// ```
137    /// ---
138    /// returns principal square root
139    pub fn sqrt(&self) -> Self {
140        let r = self.modulus().sqrt();
141        let theta = self.argument() / 2.0;
142        Self::new(r * theta.cos(), r * theta.sin())
143    }
144
145    pub fn sin(&self) -> Self {
146        Self::new(
147            self.re.sin() * self.im.cosh(),
148            self.re.cos() * self.im.sinh(),
149        )
150    }
151
152    pub fn cos(&self) -> Self {
153        Self::new(
154            self.re.cos() * self.im.cosh(),
155            -self.re.sin() * self.im.sinh(),
156        )
157    }
158
159    pub fn tan(&self) -> Self {
160        self.sin() / self.cos()
161    }
162
163    pub fn sinh(&self) -> Self {
164        Self::new(
165            self.re.sinh() * self.im.cos(),
166            self.re.cosh() * self.im.sin(),
167        )
168    }
169
170    pub fn cosh(&self) -> Self {
171        Self::new(
172            self.re.cosh() * self.im.cos(),
173            self.re.sinh() * self.im.sin(),
174        )
175    }
176
177    pub fn tanh(&self) -> Self {
178        self.sinh() / self.cosh()
179    }
180}
181impl<T: Copy + Add<Output = T>> Add for Complex<T> {
182    type Output = Self;
183
184    fn add(self, rhs: Self) -> Self::Output {
185        Self {
186            re: self.re + rhs.re,
187            im: self.im + rhs.im,
188        }
189    }
190}
191
192impl<T: Copy + Sub<Output = T>> Sub for Complex<T> {
193    type Output = Self;
194
195    fn sub(self, rhs: Self) -> Self::Output {
196        Self {
197            re: self.re - rhs.re,
198            im: self.im - rhs.im,
199        }
200    }
201}
202
203impl<T: Copy + Add<Output = T> + Sub<Output = T> + Mul<Output = T>> Mul for Complex<T> {
204    type Output = Self;
205
206    fn mul(self, rhs: Self) -> Self::Output {
207        Self {
208            re: self.re * rhs.re - self.im * rhs.im,
209            im: self.re * rhs.im + self.im * rhs.re,
210        }
211    }
212}
213
214impl<T: Copy + Add<Output = T> + Sub<Output = T> + Mul<Output = T> + Div<Output = T>> Div
215    for Complex<T>
216{
217    type Output = Self;
218
219    fn div(self, rhs: Self) -> Self::Output {
220        let denom = rhs.re * rhs.re + rhs.im * rhs.im;
221        Self {
222            re: (self.re * rhs.re + self.im * rhs.im) / denom,
223            im: (self.im * rhs.re - self.re * rhs.im) / denom,
224        }
225    }
226}
227
228impl<T: Neg<Output = T>> Neg for Complex<T> {
229    type Output = Self;
230
231    fn neg(self) -> Self::Output {
232        Self::new(-self.re, -self.im)
233    }
234}
235
236impl<T: Display> Display for Complex<T> {
237    fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
238        write!(f, "{}+{}i", self.re, self.im)
239    }
240}
241
242impl From<f64> for Complex<f64> {
243    fn from(x: f64) -> Self {
244        Self::new(x, 0.0)
245    }
246}
247
248impl From<i32> for Complex<f64> {
249    fn from(x: i32) -> Self {
250        Self::new(x as f64, 0.0)
251    }
252}
253
254impl Complex<f64> {
255    pub const I: Complex<f64> = Complex { re: 0.0, im: 1.0 };
256    pub const ONE: Complex<f64> = Complex { re: 1.0, im: 0.0 };
257    pub const ZERO: Complex<f64> = Complex { re: 0.0, im: 0.0 };
258}
259
260impl Complex<f64> {
261    /// creates complex number from polar coordinates
262    ///
263    /// #### Example
264    /// ```txt
265    /// let z = Complex::from_polar(2.0, std::f64::consts::PI/4.0);
266    /// ```
267    /// ---
268    /// converts (r,θ) to x + yi form
269    pub fn from_polar(r: f64, theta: f64) -> Self {
270        Self::new(r * theta.cos(), r * theta.sin())
271    }
272
273    /// converts to polar coordinates
274    ///
275    /// #### Example
276    /// ```txt
277    /// let z = Complex::new(1.0, 1.0);
278    /// let (r, theta) = z.to_polar();
279    /// ```
280    /// ---
281    /// returns tuple of (modulus, argument)
282    pub fn to_polar(&self) -> (f64, f64) {
283        (self.modulus(), self.argument())
284    }
285}