Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 258cb6c

Browse files
wolfvJohanMabille
authored andcommitted
add complex functions: arg, angle, conj, norm (xtensor-stack#280)
* add complex functions: arg, angle, conj, norm * add tests for complex functions, fix strided view layout interface * add numeric constants * add numeric_constants to xmath
1 parent a5e7e5a commit 258cb6c

5 files changed

Lines changed: 170 additions & 2 deletions

File tree

include/xtensor/xcomplex.hpp

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,5 +129,87 @@ namespace xt
129129
{
130130
return detail::complex_expression_helper<is_xexpression<std::decay_t<E>>::value>::imag(std::forward<E>(e));
131131
}
132+
133+
#define UNARY_COMPLEX_FUNCTOR(NAME)\
134+
template <class T>\
135+
struct NAME##_fun {\
136+
using argument_type = T;\
137+
using result_type = decltype(std::NAME(std::declval<T>()));\
138+
constexpr result_type operator()(const T& t) const {\
139+
using std::NAME;\
140+
return NAME(t);\
141+
}\
142+
}
143+
144+
namespace math
145+
{
146+
UNARY_COMPLEX_FUNCTOR(conj);
147+
UNARY_COMPLEX_FUNCTOR(norm);
148+
UNARY_COMPLEX_FUNCTOR(arg);
149+
}
150+
151+
#undef UNARY_COMPLEX_FUNCTOR
152+
153+
/**
154+
* @brief Returns an \ref xfunction evaluating to the complex conjugate of the given expression.
155+
*
156+
* @param e the \ref xexpression
157+
*/
158+
template <class E>
159+
inline auto conj(E&& e) noexcept
160+
{
161+
using value_type = typename std::decay_t<E>::value_type;
162+
using functor = math::conj_fun<value_type>;
163+
using result_type = typename functor::result_type;
164+
using type = xfunction<functor, result_type, const_xclosure_t<E>>;
165+
return type(functor(), std::forward<E>(e));
166+
}
167+
168+
/**
169+
* @brief Calculates the phase angle (in radians) elementwise for the complex numbers in e.
170+
* @param e the \ref xexpression
171+
*/
172+
template <class E>
173+
inline auto arg(E&& e) noexcept
174+
{
175+
using value_type = typename std::decay_t<E>::value_type;
176+
using functor = math::arg_fun<value_type>;
177+
using result_type = typename functor::result_type;
178+
using type = xfunction<functor, result_type, const_xclosure_t<E>>;
179+
return type(functor(), std::forward<E>(e));
180+
}
181+
182+
/**
183+
* @brief Calculates the phase angle elementwise for the complex numbers in e.
184+
* Note that this function might be slightly less perfomant than \ref arg.
185+
* @param e the \ref xexpression
186+
* @param deg calculate angle in degrees instead of radians
187+
*/
188+
template <class E>
189+
inline auto angle(E&& e, bool deg = false) noexcept
190+
{
191+
using value_type = complex_value_type_t<typename std::decay_t<E>::value_type>;
192+
value_type multiplier = 1.0;
193+
if (deg)
194+
{
195+
multiplier = value_type(180) / numeric_constants<value_type>::PI;
196+
}
197+
return arg(std::forward<E>(e)) * std::move(multiplier);
198+
}
199+
200+
/**
201+
* Calculates the squared magnitude elementwise for the complex numbers in e.
202+
* Equivalent to pow(real(e), 2) + pow(imag(e), 2).
203+
* @param e the \ref xexpression
204+
*/
205+
template <class E>
206+
inline auto norm(E&& e) noexcept
207+
{
208+
using value_type = typename std::decay_t<E>::value_type;
209+
using functor = math::norm_fun<value_type>;
210+
using result_type = typename functor::result_type;
211+
using type = xfunction<functor, result_type, const_xclosure_t<E>>;
212+
return type(functor(), std::forward<E>(e));
213+
}
132214
}
133215
#endif

include/xtensor/xmath.hpp

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,22 @@
2222

2323
namespace xt
2424
{
25+
template <class T>
26+
struct numeric_constants
27+
{
28+
static constexpr T PI = 3.141592653589793238463;
29+
static constexpr T PI_2 = 1.57079632679489661923;
30+
static constexpr T PI_4 = 0.785398163397448309616;
31+
static constexpr T D_1_PI = 0.318309886183790671538;
32+
static constexpr T D_2_PI = 0.636619772367581343076;
33+
static constexpr T D_2_SQRTPI = 1.12837916709551257390;
34+
static constexpr T SQRT2 = 1.41421356237309504880;
35+
static constexpr T SQRT1_2 = 0.707106781186547524401;
36+
static constexpr T E = 2.71828182845904523536;
37+
static constexpr T LOG2E = 1.44269504088896340736;
38+
static constexpr T LOG10E = 0.434294481903251827651;
39+
static constexpr T LN2 = 0.693147180559945309417;
40+
};
2541

2642
/***********
2743
* Helpers *
@@ -46,6 +62,17 @@ namespace xt
4662
}\
4763
}
4864

65+
#define UNARY_MATH_FUNCTOR_COMPLEX_REDUCING(NAME)\
66+
template <class T>\
67+
struct NAME##_fun {\
68+
using argument_type = T;\
69+
using result_type = complex_value_type_t<T>;\
70+
constexpr result_type operator()(const T& arg) const {\
71+
using std::NAME;\
72+
return NAME(arg);\
73+
}\
74+
}
75+
4976
#define BINARY_MATH_FUNCTOR(NAME)\
5077
template <class T>\
5178
struct NAME##_fun {\
@@ -84,7 +111,7 @@ namespace xt
84111

85112
namespace math
86113
{
87-
UNARY_MATH_FUNCTOR(abs);
114+
UNARY_MATH_FUNCTOR_COMPLEX_REDUCING(abs);
88115
UNARY_MATH_FUNCTOR(fabs);
89116
BINARY_MATH_FUNCTOR(fmod);
90117
BINARY_MATH_FUNCTOR(remainder);
@@ -129,6 +156,7 @@ namespace xt
129156
#undef TERNARY_MATH_FUNCTOR
130157
#undef BINARY_MATH_FUNCTOR
131158
#undef UNARY_MATH_FUNCTOR
159+
#undef UNARY_MATH_FUNCTOR_COMPLEX_REDUCING
132160

133161
/*******************
134162
* basic functions *

include/xtensor/xstridedview.hpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,7 @@ namespace xt
120120
const shape_type& shape() const noexcept;
121121
const strides_type& strides() const noexcept;
122122
const backstrides_type& backstrides() const noexcept;
123+
layout_type layout() const noexcept;
123124

124125
reference operator()();
125126
template <class... Args>
@@ -281,6 +282,12 @@ namespace xt
281282
return m_backstrides;
282283
}
283284

285+
template <class CT, class S, class CD>
286+
inline auto xstrided_view<CT, S, CD>::layout() const noexcept -> layout_type
287+
{
288+
return layout_type::row_major;
289+
}
290+
284291
template <class CT, class S, class CD>
285292
inline auto xstrided_view<CT, S, CD>::data() noexcept -> underlying_container_type&
286293
{

include/xtensor/xutils.hpp

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -768,6 +768,25 @@ namespace xt
768768
static constexpr bool value = detail::is_complex<std::decay_t<T>>::value;
769769
};
770770

771+
/*************************************
772+
* complex_value_type implementation *
773+
*************************************/
774+
775+
template <typename T>
776+
struct complex_value_type
777+
{
778+
using type = T;
779+
};
780+
781+
template <typename T>
782+
struct complex_value_type<std::complex<T>>
783+
{
784+
using type = T;
785+
};
786+
787+
template <class T>
788+
using complex_value_type_t = typename complex_value_type<T>::type;
789+
771790
/*********************************
772791
* forward_offset implementation *
773792
*********************************/

test/test_xcomplex.cpp

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,5 +103,37 @@ namespace xt
103103
auto it = r.begin();
104104
EXPECT_EQ(*(it.operator->()), 1.0);
105105
}
106-
}
107106

107+
TEST(xcomplex, abs_angle_conj)
108+
{
109+
xarray<std::complex<double>> cmplarg_0 = {{ 0.40101756+0.71233018i, 0.62731701+0.42786349i, 0.32415089+0.2977805i },
110+
{ 0.24475928+0.49208478i, 0.69475518+0.74029639i, 0.59390240+0.35772892i},
111+
{ 0.63179202+0.41720995i, 0.44025718+0.65472131i, 0.08372648+0.37380143i}};
112+
auto cmplres = xt::abs(cmplarg_0);
113+
xarray<double> cmplexpected = {{ 0.81745298, 0.75933774, 0.44016704},
114+
{ 0.54959488, 1.01524554, 0.69331814},
115+
{ 0.75711643, 0.78897806, 0.38306348}};
116+
117+
EXPECT_TRUE(allclose(cmplexpected, cmplres));
118+
119+
auto cmplres_angle = xt::angle(cmplarg_0);
120+
xarray<double> cmplexpected_angle = {{ 1.05805307, 0.59857922, 0.74302273},
121+
{ 1.10923689, 0.81712241, 0.54213553},
122+
{ 0.58362348, 0.97881125, 1.35044673}};
123+
EXPECT_TRUE(allclose(cmplexpected_angle, cmplres_angle));
124+
125+
auto cmplres_conj = xt::conj(cmplarg_0);
126+
xarray<std::complex<double>> cmplexpected_conj = {{ 0.40101756-0.71233018i, 0.62731701-0.42786349i, 0.32415089-0.2977805i },
127+
{ 0.24475928-0.49208478i, 0.69475518-0.74029639i, 0.59390240-0.35772892i},
128+
{ 0.63179202-0.41720995i, 0.44025718-0.65472131i, 0.08372648-0.37380143i}};
129+
EXPECT_TRUE(allclose(imag(cmplexpected_conj), imag(cmplres_conj)));
130+
EXPECT_TRUE(allclose(real(cmplexpected_conj), real(cmplres_conj)));
131+
132+
auto cmplres_norm = xt::norm(cmplarg_0);
133+
xarray<double> fieldnorm = {{ 0.66822937, 0.5765938 , 0.19374703},
134+
{ 0.30205453, 1.0307235 , 0.48069004},
135+
{ 0.57322529, 0.62248637, 0.14673763}};
136+
137+
EXPECT_TRUE(allclose(fieldnorm, cmplres_norm));
138+
}
139+
}

0 commit comments

Comments
 (0)