1 /***************************************************************************
2 * Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht          *
3 * Copyright (c) QuantStack                                                 *
4 *                                                                          *
5 * Distributed under the terms of the BSD 3-Clause License.                 *
6 *                                                                          *
7 * The full license is in the file LICENSE, distributed with this software. *
8 ****************************************************************************/
9 
10 #include "xtl/xcomplex.hpp"
11 
12 #include <complex>
13 
14 #include "test_common_macros.hpp"
15 #include "xtl/xclosure.hpp"
16 
17 namespace xtl
18 {
19     using namespace std::complex_literals;
20 
21     using complex_type = xcomplex<double>;
22     using complex_ref_type = xcomplex<double&, double&>;
23 
TEST(xcomplex,constructor)24     TEST(xcomplex, constructor)
25     {
26         complex_type c0;
27         EXPECT_APPROX_EQ(c0.real(), 0.);
28         EXPECT_APPROX_EQ(c0.imag(), 0.);
29 
30         complex_type c1(2.);
31         EXPECT_APPROX_EQ(c1.real(), 2.);
32         EXPECT_APPROX_EQ(c1.imag(), 0.);
33 
34         complex_type c2(2., 3.);
35         EXPECT_APPROX_EQ(c2.real(), 2.);
36         EXPECT_APPROX_EQ(c2.imag(), 3.);
37 
38         complex_type c3(c2);
39         EXPECT_APPROX_EQ(c3.real(), c2.real());
40         EXPECT_APPROX_EQ(c3.imag(), c2.imag());
41 
42         complex_type c4(std::move(c3));
43         EXPECT_APPROX_EQ(c4.real(), c2.real());
44         EXPECT_APPROX_EQ(c4.imag(), c2.imag());
45 
46         std::complex<double> sc(1., 2.);
47         complex_type c5(sc);
48         EXPECT_APPROX_EQ(c5.real(), sc.real());
49         EXPECT_APPROX_EQ(c5.imag(), sc.imag());
50 
51         complex_type c6(std::move(sc));
52         EXPECT_APPROX_EQ(c6.real(), c5.real());
53         EXPECT_APPROX_EQ(c6.imag(), c5.imag());
54 
55         double re = 1.2, im = 4.5;
56         complex_ref_type c7(re, im);
57         EXPECT_APPROX_EQ(c7.real(), re);
58         EXPECT_APPROX_EQ(c7.imag(), im);
59 
60         xcomplex<float> f(1.f, 2.f);
61         complex_type c8(f);
62         EXPECT_APPROX_EQ(c8.real(), 1.);
63         EXPECT_APPROX_EQ(c8.imag(), 2.);
64     }
65 
TEST(xcomplex,assign)66     TEST(xcomplex, assign)
67     {
68         complex_type c0(1., 2.);
69         complex_type c1(4., 5.);
70 
71         c0 = 3.;
72         EXPECT_APPROX_EQ(c0.real(), 3.);
73         EXPECT_APPROX_EQ(c0.imag(), 0.);
74 
75         c0 = std::move(4.);
76         EXPECT_APPROX_EQ(c0.real(), 4.);
77         EXPECT_APPROX_EQ(c0.imag(), 0.);
78 
79         c0 = c1;
80         EXPECT_APPROX_EQ(c0.real(), c1.real());
81         EXPECT_APPROX_EQ(c0.imag(), c1.imag());
82 
83         c0 = complex_type(2., 3.);
84         EXPECT_APPROX_EQ(c0.real(), 2.);
85         EXPECT_APPROX_EQ(c0.imag(), 3.);
86 
87         std::complex<double> c2(1.4, 5.2);
88         c0 = c2;
89         EXPECT_APPROX_EQ(c0.real(), c2.real());
90         EXPECT_APPROX_EQ(c0.imag(), c2.imag());
91 
92         c0 = std::complex<double>(1.2, 2.5);
93         EXPECT_APPROX_EQ(c0.real(), 1.2);
94         EXPECT_APPROX_EQ(c0.imag(), 2.5);
95     }
96 
TEST(xcomplex,conversion)97     TEST(xcomplex, conversion)
98     {
99         complex_type c(1., 2.);
100         std::complex<double> sc = c;
101         EXPECT_APPROX_EQ(c.real(), sc.real());
102         EXPECT_APPROX_EQ(c.imag(), sc.imag());
103     }
104 
TEST(xcomplex,comparison)105     TEST(xcomplex, comparison)
106     {
107         using int_complex_type = xcomplex<int>;
108 
109         int_complex_type vc0(1, 2);
110         int_complex_type vc1(2, 4);
111 
112         EXPECT_TRUE(vc0 == vc0);
113         EXPECT_FALSE(vc0 == vc1);
114 
115         EXPECT_FALSE(vc0 != vc0);
116         EXPECT_TRUE(vc0 != vc1);
117     }
118 
TEST(xcomplex,computed_assign)119     TEST(xcomplex, computed_assign)
120     {
121         complex_type vc0(1., 2.);
122         complex_type vc1(2., 4.);
123 
124         complex_type c0(vc0);
125         c0 += vc1;
126         EXPECT_APPROX_EQ(c0.real(), 3.);
127         EXPECT_APPROX_EQ(c0.imag(), 6.);
128 
129         complex_type c1(vc0);
130         c1 -= vc1;
131         EXPECT_APPROX_EQ(c1.real(), -1.);
132         EXPECT_APPROX_EQ(c1.imag(), -2.);
133 
134         complex_type c2(vc0);
135         c2 *= vc1;
136         EXPECT_APPROX_EQ(c2.real(), -6.);
137         EXPECT_APPROX_EQ(c2.imag(), 8.);
138 
139         complex_type c3(vc0);
140         c3 /= vc1;
141         EXPECT_APPROX_EQ(c3.real(), 0.5);
142         EXPECT_APPROX_EQ(c3.imag(), 0.);
143 
144         double v = 0.5;
145 
146         complex_type c4(vc0);
147         c4 += v;
148         EXPECT_APPROX_EQ(c4.real(), 1.5);
149         EXPECT_APPROX_EQ(c4.imag(), 2.);
150 
151         complex_type c5(vc0);
152         c5 -= v;
153         EXPECT_APPROX_EQ(c5.real(), 0.5);
154         EXPECT_APPROX_EQ(c5.imag(), 2.);
155 
156         complex_type c6(vc0);
157         c6 *= v;
158         EXPECT_APPROX_EQ(c6.real(), 0.5);
159         EXPECT_APPROX_EQ(c6.imag(), 1.);
160 
161         complex_type c7(vc0);
162         c7 /= v;
163         EXPECT_APPROX_EQ(c7.real(), 2.);
164         EXPECT_APPROX_EQ(c7.imag(), 4.);
165 
166         xcomplex<double, double, true> sc(vc1);
167         xcomplex<double, double, true> c8(vc0);
168         c8 *= sc;
169         EXPECT_APPROX_EQ(c8.real(), -6.);
170         EXPECT_APPROX_EQ(c8.imag(), 8.);
171 
172         xcomplex<double, double, true> c9(vc0);
173         c9 /= sc;
174         EXPECT_APPROX_EQ(c9.real(), 0.5);
175         EXPECT_APPROX_EQ(c9.imag(), 0.);
176     }
177 
TEST(xcomplex,arithmetic)178     TEST(xcomplex, arithmetic)
179     {
180         complex_type vc0(1., 2.);
181         complex_type vc1(2., 4.);
182 
183         complex_type c0 = vc0 + vc1;
184         EXPECT_APPROX_EQ(c0.real(), 3.);
185         EXPECT_APPROX_EQ(c0.imag(), 6.);
186 
187         complex_type c1 = vc0 - vc1;
188         EXPECT_APPROX_EQ(c1.real(), -1.);
189         EXPECT_APPROX_EQ(c1.imag(), -2.);
190 
191         complex_type c2 = vc0 * vc1;
192         EXPECT_APPROX_EQ(c2.real(), -6.);
193         EXPECT_APPROX_EQ(c2.imag(), 8.);
194 
195         complex_type c3 = vc0 / vc1;
196         EXPECT_APPROX_EQ(c3.real(), 0.5);
197         EXPECT_APPROX_EQ(c3.imag(), 0.);
198 
199         double v = 0.5;
200 
201         complex_type c4 = vc0 + v;
202         EXPECT_APPROX_EQ(c4.real(), 1.5);
203         EXPECT_APPROX_EQ(c4.imag(), 2.);
204 
205         complex_type c5 = vc0 - v;
206         EXPECT_APPROX_EQ(c5.real(), 0.5);
207         EXPECT_APPROX_EQ(c5.imag(), 2.);
208 
209         complex_type c6 = vc0 * v;
210         EXPECT_APPROX_EQ(c6.real(), 0.5);
211         EXPECT_APPROX_EQ(c6.imag(), 1.);
212 
213         complex_type c7 = vc0 / v;
214         EXPECT_APPROX_EQ(c7.real(), 2.);
215         EXPECT_APPROX_EQ(c7.imag(), 4.);
216     }
217 
TEST(xcomplex,real_imag)218     TEST(xcomplex, real_imag)
219     {
220         complex_type c(1., 2.);
221 
222         auto d1 = real(c);
223         EXPECT_APPROX_EQ(d1, c.real());
224 
225         auto d2 = real(std::move(c));
226         EXPECT_APPROX_EQ(d2, c.real());
227 
228         auto d3 = imag(c);
229         EXPECT_APPROX_EQ(d3, c.imag());
230 
231         auto d4 = imag(std::move(c));
232         EXPECT_APPROX_EQ(d4, c.imag());
233     }
234 
TEST(xcomplex,free_functions)235     TEST(xcomplex, free_functions)
236     {
237         complex_type c(1., 2.);
238         std::complex<double> sc(c);
239 
240         EXPECT_APPROX_EQ(abs(c), std::abs(sc));
241         EXPECT_APPROX_EQ(arg(c), std::arg(sc));
242         EXPECT_APPROX_EQ(norm(c), std::norm(sc));
243         EXPECT_COMPLEX_APPROX_EQ(conj(c), complex_type(std::conj(sc)));
244         EXPECT_COMPLEX_APPROX_EQ(proj(c), complex_type(std::proj(sc)));
245     }
246 
TEST(xcomplex,exponential)247     TEST(xcomplex, exponential)
248     {
249         complex_type c(1., 2.);
250         std::complex<double> sc(c);
251         EXPECT_COMPLEX_APPROX_EQ(exp(c), complex_type(std::exp(sc)));
252         EXPECT_COMPLEX_APPROX_EQ(log(c), complex_type(std::log(sc)));
253         EXPECT_COMPLEX_APPROX_EQ(log10(c), complex_type(std::log10(sc)));
254     }
255 
TEST(xcomplex,power)256     TEST(xcomplex, power)
257     {
258         complex_type c(1., 2.);
259         std::complex<double> sc(c);
260         double d = 1.5;
261         // this test is failing because comparing floating points is a bad idea
262         //EXPECT_EQ(pow(c, c), complex_type(std::pow(sc, sc)));
263         EXPECT_COMPLEX_APPROX_EQ(pow(c, d), complex_type(std::pow(sc, d)));
264         EXPECT_COMPLEX_APPROX_EQ(pow(d, c), complex_type(std::pow(d, sc)));
265         EXPECT_COMPLEX_APPROX_EQ(sqrt(c), complex_type(std::sqrt(sc)));
266     }
267 
TEST(xcomplex,trigonometric)268     TEST(xcomplex, trigonometric)
269     {
270         complex_type c(1., 2.);
271         std::complex<double> sc(c);
272         EXPECT_COMPLEX_APPROX_EQ(sin(c), complex_type(std::sin(sc)));
273         EXPECT_COMPLEX_APPROX_EQ(cos(c), complex_type(std::cos(sc)));
274         EXPECT_COMPLEX_APPROX_EQ(tan(c), complex_type(std::tan(sc)));
275         EXPECT_COMPLEX_APPROX_EQ(asin(c), complex_type(std::asin(sc)));
276         EXPECT_COMPLEX_APPROX_EQ(acos(c), complex_type(std::acos(sc)));
277         EXPECT_COMPLEX_APPROX_EQ(atan(c), complex_type(std::atan(sc)));
278     }
279 
TEST(xcomplex,hyperbolic)280     TEST(xcomplex, hyperbolic)
281     {
282         complex_type c(1., 2.);
283         std::complex<double> sc(c);
284         EXPECT_COMPLEX_APPROX_EQ(sinh(c), complex_type(std::sinh(sc)));
285         EXPECT_COMPLEX_APPROX_EQ(cosh(c), complex_type(std::cosh(sc)));
286         EXPECT_COMPLEX_APPROX_EQ(tanh(c), complex_type(std::tanh(sc)));
287         EXPECT_COMPLEX_APPROX_EQ(asinh(c), complex_type(std::asinh(sc)));
288         EXPECT_COMPLEX_APPROX_EQ(acosh(c), complex_type(std::acosh(sc)));
289         EXPECT_COMPLEX_APPROX_EQ(atanh(c), complex_type(std::atanh(sc)));
290     }
291 
TEST(xcomplex,forward_offset)292     TEST(xcomplex, forward_offset)
293     {
294         // Test that lvalues can be modified
295         std::complex<double> clv;
296         forward_real(clv) = 3.0;
297         EXPECT_EQ(std::real(clv), 3.0);
298 
299         forward_imag(clv) = 1.0;
300         EXPECT_EQ(std::imag(clv), 1.0);
301 
302         double rlv = 2.0;
303         forward_real(rlv) = 1.0;
304         EXPECT_EQ(forward_imag(rlv), 0.0);
305         EXPECT_EQ(forward_real(rlv), 1.0);
306     }
307 
TEST(xcomplex,scalar)308     TEST(xcomplex, scalar)
309     {
310         double d = 1.0;
311         ASSERT_EQ(1.0, real(d));
312         ASSERT_EQ(0.0, imag(d));
313         real(d) = 2.0;
314         ASSERT_EQ(2.0, d);
315     }
316 
TEST(xcomplex,closure)317     TEST(xcomplex, closure)
318     {
319         double x = 5.0;
320         auto x_closure = closure(x);
321         std::complex<double> b(0, 5), c;
322         EXPECT_COMPLEX_APPROX_EQ(b + x_closure, b + 5.0);
323         EXPECT_COMPLEX_APPROX_EQ(x_closure + b, 5.0 + b);
324         EXPECT_COMPLEX_APPROX_EQ(b - x_closure, b - 5.0);
325         EXPECT_COMPLEX_APPROX_EQ(x_closure - b, 5.0 - b);
326         EXPECT_COMPLEX_APPROX_EQ(b * x_closure, b * 5.0);
327         EXPECT_COMPLEX_APPROX_EQ(x_closure * b, 5.0 * b);
328         EXPECT_COMPLEX_APPROX_EQ(b / x_closure, b / 5.0);
329         EXPECT_COMPLEX_APPROX_EQ(x_closure / b, 5.0 / b);
330     }
331 }
332 
333