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}