oxiblas_core/scalar/
complex.rs1use num_complex::{Complex32, Complex64};
4
5pub type C32 = Complex32;
11
12pub type C64 = Complex64;
14
15#[inline]
30pub const fn c64(re: f64, im: f64) -> C64 {
31 Complex64::new(re, im)
32}
33
34#[inline]
45pub const fn c32(re: f32, im: f32) -> C32 {
46 Complex32::new(re, im)
47}
48
49pub const I64: C64 = Complex64::new(0.0, 1.0);
51
52pub const I32: C32 = Complex32::new(0.0, 1.0);
54
55#[inline]
57pub const fn imag_unit() -> C64 {
58 I64
59}
60
61#[inline]
63pub const fn imag_unit32() -> C32 {
64 I32
65}
66
67#[inline]
78pub const fn imag(im: f64) -> C64 {
79 Complex64::new(0.0, im)
80}
81
82#[inline]
84pub const fn imag32(im: f32) -> C32 {
85 Complex32::new(0.0, im)
86}
87
88#[inline]
99pub const fn real(re: f64) -> C64 {
100 Complex64::new(re, 0.0)
101}
102
103#[inline]
105pub const fn real32(re: f32) -> C32 {
106 Complex32::new(re, 0.0)
107}
108
109#[inline]
125pub fn from_polar(r: f64, theta: f64) -> C64 {
126 Complex64::from_polar(r, theta)
127}
128
129#[inline]
131pub fn from_polar32(r: f32, theta: f32) -> C32 {
132 Complex32::from_polar(r, theta)
133}
134
135pub trait ComplexExt: Sized {
137 type Real;
139
140 #[allow(clippy::wrong_self_convention)] fn is_purely_real(self, tolerance: Self::Real) -> bool;
143
144 #[allow(clippy::wrong_self_convention)] fn is_purely_imaginary(self, tolerance: Self::Real) -> bool;
147
148 fn rotate(self, angle: Self::Real) -> Self;
150
151 fn scale_magnitude(self, factor: Self::Real) -> Self;
153
154 fn normalize(self) -> Self;
156
157 fn reflect_real(self) -> Self;
159
160 fn reflect_imag(self) -> Self;
162
163 fn distance(self, other: Self) -> Self::Real;
165}
166
167impl ComplexExt for C64 {
168 type Real = f64;
169
170 #[inline]
171 fn is_purely_real(self, tolerance: f64) -> bool {
172 self.im.abs() <= tolerance
173 }
174
175 #[inline]
176 fn is_purely_imaginary(self, tolerance: f64) -> bool {
177 self.re.abs() <= tolerance
178 }
179
180 #[inline]
181 fn rotate(self, angle: f64) -> Self {
182 self * Complex64::from_polar(1.0, angle)
183 }
184
185 #[inline]
186 fn scale_magnitude(self, factor: f64) -> Self {
187 let (r, theta) = self.to_polar();
188 Complex64::from_polar(r * factor, theta)
189 }
190
191 #[inline]
192 fn normalize(self) -> Self {
193 let norm = self.norm();
194 if norm == 0.0 {
195 Complex64::new(0.0, 0.0)
196 } else {
197 self / norm
198 }
199 }
200
201 #[inline]
202 fn reflect_real(self) -> Self {
203 self.conj()
204 }
205
206 #[inline]
207 fn reflect_imag(self) -> Self {
208 Complex64::new(-self.re, self.im)
209 }
210
211 #[inline]
212 fn distance(self, other: Self) -> f64 {
213 (self - other).norm()
214 }
215}
216
217impl ComplexExt for C32 {
218 type Real = f32;
219
220 #[inline]
221 fn is_purely_real(self, tolerance: f32) -> bool {
222 self.im.abs() <= tolerance
223 }
224
225 #[inline]
226 fn is_purely_imaginary(self, tolerance: f32) -> bool {
227 self.re.abs() <= tolerance
228 }
229
230 #[inline]
231 fn rotate(self, angle: f32) -> Self {
232 self * Complex32::from_polar(1.0, angle)
233 }
234
235 #[inline]
236 fn scale_magnitude(self, factor: f32) -> Self {
237 let (r, theta) = self.to_polar();
238 Complex32::from_polar(r * factor, theta)
239 }
240
241 #[inline]
242 fn normalize(self) -> Self {
243 let norm = self.norm();
244 if norm == 0.0 {
245 Complex32::new(0.0, 0.0)
246 } else {
247 self / norm
248 }
249 }
250
251 #[inline]
252 fn reflect_real(self) -> Self {
253 self.conj()
254 }
255
256 #[inline]
257 fn reflect_imag(self) -> Self {
258 Complex32::new(-self.re, self.im)
259 }
260
261 #[inline]
262 fn distance(self, other: Self) -> f32 {
263 (self - other).norm()
264 }
265}
266
267pub trait ToComplex<C> {
269 fn to_complex(self) -> C;
271
272 fn with_imag(self, im: Self) -> C;
274}
275
276impl ToComplex<C64> for f64 {
277 #[inline]
278 fn to_complex(self) -> C64 {
279 Complex64::new(self, 0.0)
280 }
281
282 #[inline]
283 fn with_imag(self, im: f64) -> C64 {
284 Complex64::new(self, im)
285 }
286}
287
288impl ToComplex<C32> for f32 {
289 #[inline]
290 fn to_complex(self) -> C32 {
291 Complex32::new(self, 0.0)
292 }
293
294 #[inline]
295 fn with_imag(self, im: f32) -> C32 {
296 Complex32::new(self, im)
297 }
298}