rug_maths/
complex.rs

1extern crate maths_traits;
2extern crate num_traits;
3extern crate rug;
4
5#[path = "macros.rs"]
6#[macro_use]
7mod macros;
8
9use maths_traits::{
10	algebra,
11	algebra::{additive::*, multiplicative::*},
12	analysis,
13};
14use num_traits::ops::checked::*;
15use std::{
16	fmt::{Display, Formatter, Result as FmtResult},
17	ops,
18};
19
20const COMPLEX_DEFAULT_PREC: (u32, u32) = (32, 32);
21
22#[derive(Clone, Debug, PartialEq)]
23pub struct Complex {
24	pub val: rug::Complex,
25}
26
27impl Complex {
28	pub fn with_val<P, T>(prec: P, val: T) -> Self
29	where
30		rug::Complex: rug::Assign<T>,
31		P: rug::complex::Prec,
32	{
33		Complex {
34			val: rug::Complex::with_val(prec, val),
35		}
36	}
37}
38
39impl Display for Complex {
40	fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
41		self.val.fmt(f)
42	}
43}
44
45impl<T> From<T> for Complex
46where
47	rug::Complex: From<T>,
48{
49	fn from(src: T) -> Self {
50		Complex {
51			val: rug::Complex::from(src),
52		}
53	}
54}
55
56impl AddAssociative for Complex {}
57impl AddCommutative for Complex {}
58impl MulAssociative for Complex {}
59impl MulCommutative for Complex {}
60
61impl_arith! { Complex, Add { add }, AddAssign {add_assign} }
62impl_arith! { Complex, Sub { sub }, SubAssign {sub_assign} }
63impl_arith! { Complex, Mul { mul }, MulAssign {mul_assign} }
64impl_arith! { Complex, Div { div }, DivAssign {div_assign} }
65
66impl CheckedAdd for Complex {
67	fn checked_add(&self, v: &Self) -> Option<Self> {
68		Some(self + v)
69	}
70}
71
72impl CheckedSub for Complex {
73	fn checked_sub(&self, v: &Self) -> Option<Self> {
74		Some(self - v)
75	}
76}
77
78impl CheckedNeg for Complex {
79	fn checked_neg(&self) -> Option<Self> {
80		Some(Self {
81			val: -self.val.clone(),
82		})
83	}
84}
85
86impl CheckedMul for Complex {
87	fn checked_mul(&self, v: &Self) -> Option<Self> {
88		Some(self * v)
89	}
90}
91
92impl CheckedDiv for Complex {
93	fn checked_div(&self, v: &Self) -> Option<Self> {
94		if v.is_zero() {
95			None
96		} else {
97			Some(self / v)
98		}
99	}
100}
101
102impl algebra::group_like::additive::Neg for Complex {
103	type Output = Complex;
104
105	fn neg(self) -> Self::Output {
106		Complex { val: -self.val }
107	}
108}
109
110impl algebra::group_like::additive::Zero for Complex {
111	fn zero() -> Self {
112		Complex {
113			val: rug::Complex::new(COMPLEX_DEFAULT_PREC),
114		}
115	}
116
117	fn is_zero(&self) -> bool {
118		self.val == 0
119	}
120
121	fn set_zero(&mut self) {
122		self.val *= 0;
123	}
124}
125
126impl algebra::group_like::multiplicative::One for Complex {
127	fn one() -> Self {
128		Complex {
129			val: rug::Complex::with_val(COMPLEX_DEFAULT_PREC, 1),
130		}
131	}
132
133	fn is_one(&self) -> bool {
134		self.val == 1
135	}
136
137	fn set_one(&mut self) {
138		self.val *= 0;
139		self.val += 1;
140	}
141}
142
143impl algebra::group_like::multiplicative::Inv for Complex {
144	type Output = Complex;
145
146	fn inv(self) -> Self::Output {
147		Complex { val: 1 / self.val }
148	}
149}
150
151impl algebra::ring_like::Distributive for Complex {}
152
153impl algebra::ring_like::Divisibility for Complex {
154	fn divides(self, rhs: Self) -> bool {
155		let q = rhs / self;
156		q.val.real() == &q.val.real().clone().trunc()
157			&& q.val.imag() == &q.val.imag().clone().trunc()
158	}
159
160	fn divide(self, rhs: Self) -> Option<Self> {
161		match self.clone().divides(rhs.clone()) {
162			false => None,
163			true => Some(rhs / self),
164		}
165	}
166
167	fn unit(&self) -> bool {
168		!self.is_zero()
169	}
170
171	fn inverse(self) -> Option<Self> {
172		match self.unit() {
173			false => None,
174			true => Some(self.inv()),
175		}
176	}
177}
178
179impl algebra::ring_like::NoZeroDivisors for Complex {}
180
181impl algebra::ring_like::Exponential for Complex {
182	fn exp(self) -> Self {
183		Complex {
184			val: self.val.exp(),
185		}
186	}
187
188	fn try_ln(self) -> Option<Self> {
189		Some(Complex { val: self.val.ln() })
190	}
191}
192
193impl analysis::real::RealExponential for Complex {}
194
195macro_rules! complex_fn_trig {
196	($fn:ident) => {
197		fn $fn(self) -> Self {
198			Complex {
199				val: self.val.$fn(),
200			}
201		}
202	};
203}
204
205macro_rules! complex_fn_trig_try {
206	($fn:ident $try_fn:ident) => {
207		fn $try_fn(self) -> Option<Self> {
208			let result = self.val.$fn();
209			if result.real().is_nan() || result.imag().is_nan() {
210				return None;
211			}
212			Some(Complex { val: result })
213		}
214	};
215}
216
217impl analysis::real::Trig for Complex {
218	complex_fn_trig! {sin}
219	complex_fn_trig! {cos}
220	complex_fn_trig! {tan}
221	complex_fn_trig! {sinh}
222	complex_fn_trig! {cosh}
223	complex_fn_trig! {tanh}
224	complex_fn_trig! {asin}
225	complex_fn_trig! {acos}
226	complex_fn_trig! {atan}
227	complex_fn_trig! {asinh}
228	complex_fn_trig! {acosh}
229	complex_fn_trig! {atanh}
230	complex_fn_trig_try! {asin try_asin}
231	complex_fn_trig_try! {acos try_acos}
232	complex_fn_trig_try! {asinh try_asinh}
233	complex_fn_trig_try! {acosh try_acosh}
234	complex_fn_trig_try! {atanh try_atanh}
235
236	fn atan2(_y: Self, _x: Self) -> Self {
237		unimplemented!("This looks meaningless");
238	}
239
240	fn pi() -> Self {
241		Complex {
242			val: rug::Complex::with_val(COMPLEX_DEFAULT_PREC, rug::float::Constant::Pi),
243		}
244	}
245}