Skip to content

Commit dcd6d55

Browse files
authored
Merge pull request #587 from JohanMabille/complex
Complex functions now accept batch of real values
2 parents 4bf826d + 31cfa52 commit dcd6d55

File tree

4 files changed

+171
-23
lines changed

4 files changed

+171
-23
lines changed

include/xsimd/arch/generic/xsimd_generic_complex.hpp

Lines changed: 68 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,42 +3,94 @@
33

44
#include "./xsimd_generic_details.hpp"
55

6-
76
namespace xsimd {
87

98
namespace kernel {
109

1110
using namespace types;
1211

12+
namespace detail
13+
{
14+
template <class B, bool is_complex>
15+
struct real_imag_kernel
16+
{
17+
using return_type = typename B::real_batch;
18+
19+
static return_type real(B const& z)
20+
{
21+
return z.real();
22+
}
23+
24+
static return_type imag(B const& z)
25+
{
26+
return z.imag();
27+
}
28+
};
29+
30+
template <class B>
31+
struct real_imag_kernel<B, false>
32+
{
33+
using return_type = B;
34+
35+
static return_type real(B const& z)
36+
{
37+
return z;
38+
}
39+
40+
static return_type imag(B const&)
41+
{
42+
return B(typename B::value_type(0));
43+
}
44+
};
45+
}
46+
47+
// real
48+
template <class A, class T>
49+
real_batch_type_t<batch<T, A>> real(batch<T, A> const& self, requires_arch<generic>) {
50+
using batch_type = batch<T, A>;
51+
constexpr bool is_cplx = xsimd::detail::is_complex<typename batch_type::value_type>::value;
52+
return detail::real_imag_kernel<batch_type, is_cplx>::real(self);
53+
}
54+
55+
// imag
56+
template <class A, class T>
57+
real_batch_type_t<batch<T, A>> imag(batch<T, A> const& self, requires_arch<generic>) {
58+
using batch_type = batch<T, A>;
59+
constexpr bool is_cplx = xsimd::detail::is_complex<typename batch_type::value_type>::value;
60+
return detail::real_imag_kernel<batch_type, is_cplx>::imag(self);
61+
}
62+
1363
// arg
1464
template<class A, class T>
15-
batch<T, A> arg(batch<std::complex<T>, A> const& self, requires_arch<generic>) {
16-
return atan2(self.imag(), self.real());
65+
real_batch_type_t<batch<T, A>> arg(batch<T, A> const& self, requires_arch<generic>) {
66+
return atan2(imag(self), real(self));
1767
}
1868

19-
2069
// conj
21-
template<class A, class T> batch<std::complex<T>, A> conj(batch<std::complex<T>, A> const& self, requires_arch<generic>) {
22-
return {self.real(), - self.imag()};
70+
template<class A, class T>
71+
complex_batch_type_t<batch<T, A>> conj(batch<T, A> const& self, requires_arch<generic>) {
72+
return {real(self), - imag(self)};
2373
}
2474

2575
// norm
26-
template<class A, class T> batch<T, A> norm(batch<std::complex<T>, A> const& self, requires_arch<generic>) {
27-
return {fma(self.real(), self.real(), self.imag() * self.imag())};
76+
template<class A, class T>
77+
real_batch_type_t<batch<T, A>> norm(batch<T, A> const& self, requires_arch<generic>) {
78+
return {fma(real(self), real(self), imag(self) * imag(self))};
2879
}
2980

30-
3181
// proj
32-
template<class A, class T> batch<std::complex<T>, A> proj(batch<std::complex<T>, A> const& self, requires_arch<generic>) {
33-
using batch_type = batch<std::complex<T>, A>;
82+
template<class A, class T>
83+
complex_batch_type_t<batch<T, A>> proj(batch<T, A> const& self, requires_arch<generic>) {
84+
using batch_type = complex_batch_type_t<batch<T, A>>;
3485
using real_batch = typename batch_type::real_batch;
35-
auto cond = xsimd::isinf(self.real()) || xsimd::isinf(self.imag());
36-
return select(cond, batch_type(constants::infinity<real_batch>(), copysign(real_batch(0.), self.imag())), self);
86+
using real_value_type = typename real_batch::value_type;
87+
auto cond = xsimd::isinf(real(self)) || xsimd::isinf(imag(self));
88+
return select(cond,
89+
batch_type(constants::infinity<real_batch>(),
90+
copysign(real_batch(real_value_type(0)), imag(self))),
91+
batch_type(self));
3792
}
38-
39-
4093
}
41-
4294
}
4395

4496
#endif

include/xsimd/types/xsimd_api.hpp

Lines changed: 30 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -96,11 +96,11 @@ batch<T, A> acosh(batch<T, A> const& x) {
9696
* @ingroup batch_complex
9797
*
9898
* Computes the argument of the batch \c z.
99-
* @param z batch of complex values.
99+
* @param z batch of complex or real values.
100100
* @return the argument of \c z.
101101
*/
102102
template<class T, class A>
103-
batch<T, A> arg(batch<std::complex<T>, A> const& z) {
103+
real_batch_type_t<batch<T, A>> arg(batch<T, A> const& z) {
104104
return kernel::arg<A>(z, A{});
105105
}
106106

@@ -358,7 +358,7 @@ batch<T, A> clip(batch<T, A> const& x, batch<T, A> const& lo, batch<T, A> const&
358358
* @return the argument of \c z.
359359
*/
360360
template<class A, class T>
361-
batch<std::complex<T>, A> conj(batch<std::complex<T>, A> const& z) {
361+
complex_batch_type_t<batch<T, A>> conj(batch<T, A> const& z) {
362362
return kernel::conj(z, A{});
363363
}
364364

@@ -758,6 +758,17 @@ batch<T, A> hypot(batch<T, A> const& x, batch<T, A> const& y) {
758758
return kernel::hypot<A>(x, y, A{});
759759
}
760760

761+
/**
762+
* @ingroup batch_complex
763+
*
764+
* Computes the imaginary part of the batch \c z.
765+
* @param z batch of complex or real values.
766+
* @return the argument of \c z.
767+
*/
768+
template <class T, class A>
769+
real_batch_type_t<batch<T, A>> imag(batch<T, A> const& x) {
770+
return kernel::imag<A>(x, A{});
771+
}
761772

762773
/**
763774
* @ingroup batch_constant
@@ -1115,11 +1126,11 @@ batch<T, A> nextafter(batch<T, A> const& x, batch<T, A> const& y) {
11151126
* @ingroup batch_complex
11161127
*
11171128
* Computes the norm of the batch \c x.
1118-
* @param x batch of complex values.
1129+
* @param x batch of complex or real values.
11191130
* @return the norm of \c x.
11201131
*/
11211132
template<class A, class T>
1122-
batch<T, A> norm(batch<std::complex<T>, A> const& x) {
1133+
real_batch_type_t<batch<T, A>> norm(batch<T, A> const& x) {
11231134
return kernel::norm(x, A{});
11241135
}
11251136

@@ -1167,14 +1178,26 @@ batch<T, A> pow(batch<T, A> const& x, ITy y) {
11671178
* @ingroup batch_complex
11681179
*
11691180
* Computes the projection of the batch \c x.
1170-
* @param x batch of complex values.
1181+
* @param x batch of complex or real values.
11711182
* @return the projection of \c x.
11721183
*/
11731184
template<class A, class T>
1174-
batch<std::complex<T>, A> proj(batch<std::complex<T>, A> const& x) {
1185+
complex_batch_type_t<batch<T, A>> proj(batch<T, A> const& x) {
11751186
return kernel::proj(x, A{});
11761187
}
11771188

1189+
/**
1190+
* @ingroup batch_complex
1191+
*
1192+
* Computes the real part of the batch \c z.
1193+
* @param z batch of complex or real values.
1194+
* @return the argument of \c z.
1195+
*/
1196+
template <class T, class A>
1197+
real_batch_type_t<batch<T, A>> real(batch<T, A> const& x) {
1198+
return kernel::real<A>(x, A{});
1199+
}
1200+
11781201
/**
11791202
* @ingroup batch_math
11801203
*

include/xsimd/types/xsimd_batch.hpp

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -350,6 +350,45 @@ struct batch<std::complex<T>, A> {
350350
template <class T, class A>
351351
constexpr std::size_t batch<std::complex<T>, A>::size;
352352

353+
/*******************
354+
* real_batch_type *
355+
*******************/
356+
357+
template <class B>
358+
struct real_batch_type
359+
{
360+
using type = B;
361+
};
362+
363+
template <class T, class A>
364+
struct real_batch_type<batch<std::complex<T>, A>>
365+
{
366+
using type = batch<T, A>;
367+
};
368+
369+
template <class B>
370+
using real_batch_type_t = typename real_batch_type<B>::type;
371+
372+
/**********************
373+
* complex_batch_type *
374+
**********************/
375+
376+
template <class B>
377+
struct complex_batch_type
378+
{
379+
using real_value_type = typename B::value_type;
380+
using arch_type = typename B::arch_type;
381+
using type = batch<std::complex<real_value_type>, arch_type>;
382+
};
383+
384+
template <class T, class A>
385+
struct complex_batch_type<batch<std::complex<T>, A>>
386+
{
387+
using type = batch<std::complex<T>, A>;
388+
};
389+
390+
template <class B>
391+
using complex_batch_type_t = typename complex_batch_type<B>::type;
353392
}
354393

355394
#include "../types/xsimd_batch_constant.hpp"

test/test_batch_complex.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -486,6 +486,35 @@ class batch_complex_test : public testing::Test
486486
}
487487
}
488488

489+
void test_conj_norm_proj_real() const
490+
{
491+
// conj real batch
492+
{
493+
array_type expected;
494+
std::transform(lhs.cbegin(), lhs.cend(), expected.begin(),
495+
[](const value_type& v) { return std::conj(std::real(v)); });
496+
batch_type res = conj(real(batch_lhs()));
497+
EXPECT_BATCH_EQ(res, expected) << print_function_name("conj(real batch)");
498+
499+
}
500+
// norm real batch
501+
{
502+
real_array_type expected;
503+
std::transform(lhs.cbegin(), lhs.cend(), expected.begin(),
504+
[](const value_type& v) { return std::norm(std::real(v)); });
505+
real_batch_type res = norm(real(batch_lhs()));
506+
EXPECT_BATCH_EQ(res, expected) << print_function_name("norm(real_batch)");
507+
}
508+
// proj real batch
509+
{
510+
array_type expected;
511+
std::transform(lhs.cbegin(), lhs.cend(), expected.begin(),
512+
[](const value_type& v) { return std::proj(std::real(v)); });
513+
batch_type res = proj(real(batch_lhs()));
514+
EXPECT_BATCH_EQ(res, expected) << print_function_name("proj(real_batch)");
515+
}
516+
}
517+
489518
void test_horizontal_operations() const
490519
{
491520
// hadd
@@ -599,6 +628,11 @@ TYPED_TEST(batch_complex_test, conj_norm_proj)
599628
this->test_conj_norm_proj();
600629
}
601630

631+
TYPED_TEST(batch_complex_test, conj_norm_proj_real)
632+
{
633+
this->test_conj_norm_proj_real();
634+
}
635+
602636
TYPED_TEST(batch_complex_test, horizontal_operations)
603637
{
604638
this->test_horizontal_operations();

0 commit comments

Comments
 (0)