mathhook_core/algebra/complex/
arithmetic.rs1use super::operations::ComplexOperations;
8use crate::core::Expression;
9use crate::simplify::Simplify;
10
11impl Expression {
12 pub fn real(&self) -> Expression {
27 match self {
28 Expression::Complex(data) => data.real.clone(),
29 _ => self.clone(),
30 }
31 }
32
33 pub fn imag(&self) -> Expression {
48 match self {
49 Expression::Complex(data) => data.imag.clone(),
50 _ => Expression::integer(0),
51 }
52 }
53
54 pub fn conjugate(&self) -> Expression {
72 self.complex_conjugate()
73 }
74
75 pub fn abs(&self) -> Expression {
89 self.complex_modulus()
90 }
91
92 pub fn arg(&self) -> Expression {
106 self.complex_argument()
107 }
108
109 pub fn to_polar(&self) -> (Expression, Expression) {
123 self.to_polar_form()
124 }
125
126 pub fn from_polar(magnitude: Expression, angle: Expression) -> Expression {
146 Self::from_polar_form(magnitude, angle)
147 }
148
149 pub fn from_polar_form(magnitude: Expression, angle: Expression) -> Expression {
163 Expression::complex(
164 Expression::mul(vec![
165 magnitude.clone(),
166 Expression::function("cos", vec![angle.clone()]),
167 ])
168 .simplify(),
169 Expression::mul(vec![magnitude, Expression::function("sin", vec![angle])]).simplify(),
170 )
171 }
172
173 pub fn simplify_complex(expr: &Expression) -> Expression {
188 match expr {
189 Expression::Complex(data) => {
190 let real_simplified = data.real.simplify();
191 let imag_simplified = data.imag.simplify();
192
193 if imag_simplified.is_zero() {
194 return real_simplified;
195 }
196
197 if real_simplified.is_zero() {
198 return Expression::mul(vec![imag_simplified, Expression::i()]).simplify();
199 }
200
201 Expression::complex(real_simplified, imag_simplified)
202 }
203 _ => expr.clone(),
204 }
205 }
206}
207
208#[cfg(test)]
209mod tests {
210 use super::*;
211 use crate::expr;
212
213 #[test]
214 fn test_complex_addition() {
215 let z1 = Expression::complex(expr!(3), expr!(4));
216 let z2 = Expression::complex(expr!(1), expr!(2));
217 let result = z1.complex_add(&z2);
218
219 if let Expression::Complex(data) = result {
220 assert_eq!(data.real, expr!(4));
221 assert_eq!(data.imag, expr!(6));
222 } else {
223 panic!("Expected complex result");
224 }
225 }
226
227 #[test]
228 fn test_complex_subtraction() {
229 let z1 = Expression::complex(expr!(5), expr!(7));
230 let z2 = Expression::complex(expr!(2), expr!(3));
231 let result = z1.complex_subtract(&z2);
232
233 if let Expression::Complex(data) = result {
234 assert_eq!(data.real, expr!(3));
235 assert_eq!(data.imag, expr!(4));
236 } else {
237 panic!("Expected complex result");
238 }
239 }
240
241 #[test]
242 fn test_complex_multiplication() {
243 let z1 = Expression::complex(expr!(3), expr!(4));
244 let z2 = Expression::complex(expr!(1), expr!(2));
245 let result = z1.complex_multiply(&z2);
246
247 if let Expression::Complex(data) = result {
248 assert_eq!(data.real, expr!(-5));
249 assert_eq!(data.imag, expr!(10));
250 } else {
251 panic!("Expected complex result");
252 }
253 }
254
255 #[test]
256 fn test_complex_division() {
257 let z1 = Expression::complex(expr!(2), expr!(3));
258 let z2 = Expression::complex(expr!(1), expr!(-1));
259 let result = z1.complex_divide(&z2);
260
261 if let Expression::Complex(_) = result {
262 } else {
263 panic!("Expected complex result");
264 }
265 }
266
267 #[test]
268 fn test_complex_conjugate() {
269 let z = Expression::complex(expr!(3), expr!(4));
270 let result = z.complex_conjugate();
271
272 if let Expression::Complex(data) = result {
273 assert_eq!(data.real, expr!(3));
274 assert_eq!(data.imag, expr!(-4));
275 } else {
276 panic!("Expected complex result");
277 }
278 }
279
280 #[test]
281 fn test_real_method() {
282 let z = Expression::complex(expr!(3), expr!(4));
283 let real_part = z.real();
284 assert_eq!(real_part, expr!(3));
285
286 let real_num = expr!(5);
287 let real_part = real_num.real();
288 assert_eq!(real_part, expr!(5));
289 }
290
291 #[test]
292 fn test_imag_method() {
293 let z = Expression::complex(expr!(3), expr!(4));
294 let imag_part = z.imag();
295 assert_eq!(imag_part, expr!(4));
296
297 let real_num = expr!(5);
298 let imag_part = real_num.imag();
299 assert_eq!(imag_part, expr!(0));
300 }
301
302 #[test]
303 fn test_conjugate_method() {
304 let z = Expression::complex(expr!(3), expr!(4));
305 let conjugate = z.conjugate();
306
307 if let Expression::Complex(data) = conjugate {
308 assert_eq!(data.real, expr!(3));
309 assert_eq!(data.imag, expr!(-4));
310 } else {
311 panic!("Expected complex result");
312 }
313 }
314
315 #[test]
316 fn test_abs_method() {
317 let z = Expression::complex(expr!(3), expr!(4));
318 let magnitude = z.abs();
319
320 match magnitude {
321 Expression::Function { .. } => {}
322 _ => panic!("Expected function expression for abs"),
323 }
324 }
325
326 #[test]
327 fn test_arg_method() {
328 let z = Expression::complex(expr!(1), expr!(1));
329 let angle = z.arg();
330
331 match angle {
332 Expression::Function { .. } => {}
333 _ => panic!("Expected function expression for arg"),
334 }
335 }
336
337 #[test]
338 fn test_to_polar_method() {
339 let z = Expression::complex(expr!(3), expr!(4));
340 let (_magnitude, _angle) = z.to_polar();
341 }
342
343 #[test]
344 fn test_from_polar_method() {
345 let magnitude = expr!(5);
346 let angle = expr!(0);
347 let _z = Expression::from_polar(magnitude, angle);
348 }
349
350 #[test]
351 fn test_complex_with_symbols() {
352 let x = expr!(x);
353 let y = expr!(y);
354 let a = expr!(a);
355 let b = expr!(b);
356
357 let z1 = Expression::complex(x.clone(), y.clone());
358 let z2 = Expression::complex(a.clone(), b.clone());
359 let result = z1.complex_add(&z2);
360
361 if let Expression::Complex(data) = result {
362 match (&data.real, &data.imag) {
363 (Expression::Add(real_terms), Expression::Add(imag_terms)) => {
364 assert_eq!(real_terms.len(), 2);
365 assert_eq!(imag_terms.len(), 2);
366 }
367 _ => panic!("Expected addition expressions for real and imaginary parts"),
368 }
369 } else {
370 panic!("Expected complex result");
371 }
372 }
373
374 #[test]
375 fn test_simplify_complex() {
376 let z = Expression::complex(expr!(3), expr!(0));
377 let result = Expression::simplify_complex(&z);
378 assert_eq!(result, expr!(3));
379
380 let z = Expression::complex(expr!(0), expr!(4));
381 let result = Expression::simplify_complex(&z);
382 assert_eq!(result, Expression::mul(vec![expr!(4), Expression::i()]));
383 }
384
385 #[test]
386 fn test_complex_zero() {
387 let z = Expression::complex(expr!(0), expr!(0));
388 let real_part = z.real();
389 let imag_part = z.imag();
390 assert_eq!(real_part, expr!(0));
391 assert_eq!(imag_part, expr!(0));
392 }
393
394 #[test]
395 fn test_complex_pure_real() {
396 let z = Expression::complex(expr!(5), expr!(0));
397 assert!(z.is_real());
398 assert!(!z.is_pure_imaginary());
399 }
400
401 #[test]
402 fn test_complex_pure_imaginary() {
403 let z = Expression::complex(expr!(0), expr!(5));
404 assert!(!z.is_real());
405 assert!(z.is_pure_imaginary());
406 }
407
408 #[test]
409 fn test_complex_general() {
410 let z = Expression::complex(expr!(3), expr!(4));
411 assert!(!z.is_real());
412 assert!(z.is_imaginary());
413 assert!(!z.is_pure_imaginary());
414 }
415
416 #[test]
417 fn test_complex_multiplication_zero() {
418 let z1 = Expression::complex(expr!(3), expr!(4));
419 let z2 = Expression::complex(expr!(0), expr!(0));
420 let result = z1.complex_multiply(&z2);
421
422 if let Expression::Complex(data) = result {
423 assert_eq!(data.real, expr!(0));
424 assert_eq!(data.imag, expr!(0));
425 } else {
426 panic!("Expected complex result");
427 }
428 }
429
430 #[test]
431 fn test_complex_addition_negative() {
432 let z1 = Expression::complex(expr!(-2), expr!(-3));
433 let z2 = Expression::complex(expr!(5), expr!(7));
434 let result = z1.complex_add(&z2);
435
436 if let Expression::Complex(data) = result {
437 assert_eq!(data.real, expr!(3));
438 assert_eq!(data.imag, expr!(4));
439 } else {
440 panic!("Expected complex result");
441 }
442 }
443
444 #[test]
445 fn test_conjugate_twice() {
446 let z = Expression::complex(expr!(3), expr!(4));
447 let conjugate = z.conjugate();
448 let double_conjugate = conjugate.conjugate();
449
450 if let Expression::Complex(data) = double_conjugate {
451 assert_eq!(data.real, expr!(3));
452 assert_eq!(data.imag, expr!(4));
453 } else {
454 panic!("Expected complex result");
455 }
456 }
457
458 #[test]
459 fn test_complex_multiply_i() {
460 let z = Expression::complex(expr!(3), expr!(4));
461 let i = Expression::complex(expr!(0), expr!(1));
462 let result = z.complex_multiply(&i);
463
464 if let Expression::Complex(data) = result {
465 assert_eq!(data.real, expr!(-4));
466 assert_eq!(data.imag, expr!(3));
467 } else {
468 panic!("Expected complex result");
469 }
470 }
471
472 #[test]
473 fn test_from_polar_zero_angle() {
474 let magnitude = expr!(5);
475 let angle = expr!(0);
476 let z = Expression::from_polar(magnitude, angle);
477
478 if let Expression::Complex(_) = z {
479 } else {
480 panic!("Expected complex result from polar conversion");
481 }
482 }
483
484 #[test]
485 fn test_complex_real_extraction() {
486 let real = expr!(7);
487 let imag = expr!(-3);
488 let z = Expression::complex(real.clone(), imag.clone());
489
490 assert_eq!(z.real(), real);
491 assert_eq!(z.imag(), imag);
492 }
493
494 #[test]
495 fn test_complex_subtraction_result_zero() {
496 let z1 = Expression::complex(expr!(3), expr!(4));
497 let z2 = Expression::complex(expr!(3), expr!(4));
498 let result = z1.complex_subtract(&z2);
499
500 if let Expression::Complex(data) = result {
501 assert_eq!(data.real, expr!(0));
502 assert_eq!(data.imag, expr!(0));
503 } else {
504 panic!("Expected complex result");
505 }
506 }
507}