/***************************************************************************
* Copyright (c) Johan Mabille, Sylvain Corlay and Wolf Vollprecht *
* Copyright (c) QuantStack *
* *
* Distributed under the terms of the BSD 3-Clause License. *
* *
* The full license is in the file LICENSE, distributed with this software. *
****************************************************************************/
#include
#include
#include "xtensor/containers/xarray.hpp"
#include "xtensor/generators/xbuilder.hpp"
#include "xtensor/io/xio.hpp"
#include "xtensor/misc/xcomplex.hpp"
#include "xtensor/reducers/xnorm.hpp"
#include "xtensor/views/xview.hpp"
#include "test_common_macros.hpp"
namespace xt
{
using namespace std::complex_literals;
TEST(xcomplex, expression)
{
xarray e = {{1.0, 1.0 + 1.0i}, {1.0 - 1.0i, 1.0}};
// Test real expression
auto r = real(e);
auto i = imag(e);
ASSERT_EQ(r.dimension(), size_t(2));
ASSERT_EQ(i.dimension(), size_t(2));
ASSERT_EQ(r.shape()[0], size_t(2));
ASSERT_EQ(r.shape()[1], size_t(2));
ASSERT_EQ(i.shape()[0], size_t(2));
ASSERT_EQ(i.shape()[1], size_t(2));
ASSERT_EQ(i(0, 0), 0);
ASSERT_EQ(i(0, 1), 1);
ASSERT_EQ(i(1, 0), -1);
ASSERT_EQ(i(1, 1), 0);
// Test assignment to an array
xarray ar = r;
EXPECT_TRUE(all(equal(ar, ones({2, 2}))));
}
TEST(xcomplex, lvalue)
{
xarray e = {{1.0, 1.0 + 1.0i}, {1.0 - 1.0i, 1.0}};
// Test assigning an expression to the complex view
real(e) = zeros({2, 2});
xarray expect1 = {{0.0, 0.0 + 1.0i}, {0.0 - 1.0i, 0.0}};
EXPECT_TRUE(all(equal(e, expect1)));
imag(e) = zeros({2, 2});
EXPECT_TRUE(all(equal(e, zeros({2, 2}))));
}
TEST(xcomplex, scalar_assignmnent)
{
xarray e = {{1.0, 1.0 + 1.0i}, {1.0 - 1.0i, 1.0}};
// Test assigning an expression to the complex view
real(e) = 0.0;
xarray expect1 = {{0.0, 0.0 + 1.0i}, {0.0 - 1.0i, 0.0}};
EXPECT_TRUE(all(equal(e, expect1)));
}
TEST(xcomplex, noncomplex)
{
xarray e = ones({2, 2});
auto r = real(e);
auto i = imag(e);
EXPECT_TRUE(all(equal(r, e)));
EXPECT_TRUE(all(equal(i, zeros({2, 2}))));
}
TEST(xcomplex, scalar)
{
double d = 1.0;
ASSERT_EQ(1.0, real(d));
ASSERT_EQ(0.0, imag(d));
real(d) = 2.0;
ASSERT_EQ(2.0, d);
}
TEST(xcomplex, pointer)
{
xarray e = {{1.0, 1.0 + 1.0i}, {1.0 - 1.0i, 1.0}};
auto r = real(e);
auto it = r.begin();
EXPECT_EQ(*(it.operator->()), 1.0);
}
TEST(xcomplex, arg)
{
xarray cmplarg_0 = {
{0.40101756 + 0.71233018i, 0.62731701 + 0.42786349i, 0.32415089 + 0.2977805i},
{0.24475928 + 0.49208478i, 0.69475518 + 0.74029639i, 0.59390240 + 0.35772892i},
{0.63179202 + 0.41720995i, 0.44025718 + 0.65472131i, 0.08372648 + 0.37380143i}
};
xarray res = xt::arg(cmplarg_0);
}
TEST(xcomplex, abs_angle_conj)
{
xarray cmplarg_0 = {
{0.40101756 + 0.71233018i, 0.62731701 + 0.42786349i, 0.32415089 + 0.2977805i},
{0.24475928 + 0.49208478i, 0.69475518 + 0.74029639i, 0.59390240 + 0.35772892i},
{0.63179202 + 0.41720995i, 0.44025718 + 0.65472131i, 0.08372648 + 0.37380143i}
};
auto cmplres = xt::abs(cmplarg_0);
xarray cmplexpected = {
{0.81745298, 0.75933774, 0.44016704},
{0.54959488, 1.01524554, 0.69331814},
{0.75711643, 0.78897806, 0.38306348}
};
EXPECT_TRUE(allclose(cmplexpected, cmplres));
auto cmplres_angle = xt::angle(cmplarg_0);
xarray cmplexpected_angle = {
{1.05805307, 0.59857922, 0.74302273},
{1.10923689, 0.81712241, 0.54213553},
{0.58362348, 0.97881125, 1.35044673}
};
EXPECT_TRUE(allclose(cmplexpected_angle, cmplres_angle));
using assign_t_angle = xassign_traits;
#if XTENSOR_USE_XSIMD
EXPECT_TRUE(assign_t_angle::simd_linear_assign());
#endif
auto cmplres_conj = xt::conj(cmplarg_0);
xarray cmplexpected_conj = {
{0.40101756 - 0.71233018i, 0.62731701 - 0.42786349i, 0.32415089 - 0.2977805i},
{0.24475928 - 0.49208478i, 0.69475518 - 0.74029639i, 0.59390240 - 0.35772892i},
{0.63179202 - 0.41720995i, 0.44025718 - 0.65472131i, 0.08372648 - 0.37380143i}
};
EXPECT_TRUE(allclose(cmplexpected_conj, cmplres_conj));
using assign_t_conj = xassign_traits;
#if XTENSOR_USE_XSIMD
auto b1 = cmplres_angle.template load_simd(0);
auto b2 = cmplres_conj.template load_simd(0);
static_cast(b1);
static_cast(b2);
EXPECT_TRUE(assign_t_conj::simd_linear_assign());
#endif
auto cmplres_norm = xt::norm(cmplarg_0);
xarray fieldnorm = {
{0.66822937, 0.5765938, 0.19374703},
{0.30205453, 1.0307235, 0.48069004},
{0.57322529, 0.62248637, 0.14673763}
};
using assign_t_norm = xassign_traits;
#if XTENSOR_USE_XSIMD
EXPECT_TRUE(assign_t_norm::simd_linear_assign());
#endif
EXPECT_TRUE(allclose(fieldnorm, cmplres_norm));
}
TEST(xcomplex, arg)
{
xarray cmplarg_0 = {
{0.40101756 + 0.71233018i, 0.62731701 + 0.42786349i, 0.32415089 + 0.2977805i},
{0.24475928 + 0.49208478i, 0.69475518 + 0.74029639i, 0.59390240 + 0.35772892i},
{0.63179202 + 0.41720995i, 0.44025718 + 0.65472131i, 0.08372648 + 0.37380143i}
};
auto cmplres = xt::arg(cmplarg_0);
auto evc = xt::eval(cmplres);
auto it = cmplarg_0.begin();
for (auto el : evc)
{
auto exp = std::arg(*it);
EXPECT_DOUBLE_EQ(el, exp);
++it;
}
using assign_t_arg = xassign_traits;
#if XTENSOR_USE_XSIMD
EXPECT_TRUE(assign_t_arg::simd_linear_assign());
#endif
}
TEST(xcomplex, conj_real)
{
xarray A = {
{0.81745298, 0.75933774, 0.44016704},
{0.54959488, 1.01524554, 0.69331814},
{0.75711643, 0.78897806, 0.38306348}
};
xarray B = xt::real(xt::conj(A));
EXPECT_EQ(A, B);
}
TEST(xcomplex, isnan)
{
using c_t = std::complex;
double nan = std::numeric_limits::quiet_NaN();
xarray e = {c_t(0, 1), c_t(0, nan), c_t(-nan, 2), c_t(nan, -nan)};
xarray expected = {false, true, true, true};
// Full qualification required by Windows
EXPECT_TRUE(all(equal(expected, xt::isnan(e))));
}
TEST(xcomplex, isinf)
{
using c_t = std::complex;
double inf = std::numeric_limits::infinity();
xarray e = {c_t(0, 1), c_t(0, inf), c_t(-inf, 2), c_t(inf, -inf), c_t(0, -inf)};
xarray expected = {false, true, true, true, true};
EXPECT_TRUE(all(equal(expected, xt::isinf(e))));
}
TEST(xcomplex, isclose)
{
xarray arg = {
{0.40101756 + 0.71233018i, 0.62731701 + 0.42786349i, 0.32415089 + 0.2977805i},
{0.24475928 + 0.49208478i, 0.69475518 + 0.74029639i, 0.59390240 + 0.35772892i},
{0.63179202 + 0.41720995i, 0.44025718 + 0.65472131i, 0.08372648 + 0.37380143i}
};
xarray compare = {
{0.401 + 0.712i, 0.627 + 0.427i, 0.324 + 0.297i},
{0.244 + 0.492i, 0.694 + 0.740i, 0.593 + 0.357i},
{0.631 + 0.417i, 0.440 + 0.654i, 0.083 + 0.373i}
};
auto veryclose = isclose(arg, compare, 1e-5);
auto looselyclose = isclose(arg, compare, 1e-1);
EXPECT_TRUE(all(equal(false, veryclose)));
EXPECT_TRUE(all(equal(true, looselyclose)));
double inf = std::numeric_limits::infinity();
double nan = std::numeric_limits::quiet_NaN();
using c_t = std::complex;
EXPECT_TRUE(isclose(c_t(0, nan), c_t(0, nan))() == false);
EXPECT_TRUE(isclose(c_t(0, nan), c_t(0, nan), 1e-5, 1e-3, true)() == true);
EXPECT_TRUE(isclose(c_t(0, inf), c_t(0, inf))() == true);
EXPECT_TRUE(isclose(c_t(0, -inf), c_t(0, inf))() == false);
EXPECT_TRUE(isclose(c_t(inf, -inf), c_t(0, inf))() == false);
EXPECT_TRUE(isclose(c_t(5, 5), c_t(5, -5))() == false);
}
TEST(xcomplex, real_expression)
{
using cpx = std::complex;
xtensor a = {{cpx(1, 1), cpx(-1, 1), cpx(-2, -2)}, {cpx(-1, 0), cpx(0, 1), cpx(2, 2)}};
xtensor exp = {{2, -2, -4}, {-2, 0, 4}};
xtensor res = real(a + a);
EXPECT_EQ(res, exp);
}
TEST(xcomplex, conj)
{
using cpx = std::complex;
xtensor a = {{cpx(1, 1), cpx(-1, 1), cpx(-2, -2)}, {cpx(-1, 0), cpx(0, 1), cpx(2, 2)}};
xtensor res = conj(a);
xtensor exp = {{cpx(1, -1), cpx(-1, -1), cpx(-2, 2)}, {cpx(-1, 0), cpx(0, -1), cpx(2, -2)}};
EXPECT_EQ(res, exp);
}
TEST(xcomplex, exp)
{
xt::xarray ph =
{274.7323f, 276.3974f, 274.7323f, 276.3974f, 274.7323f, 276.3974f, 274.7323f, 276.3974f};
xt::xarray input = ph * std::complex(0, 1.f);
xt::xarray res = xt::exp(input);
auto expected = xt::xarray::from_shape({size_t(8)});
std::transform(
input.cbegin(),
input.cend(),
expected.begin(),
[](const std::complex& arg)
{
return std::exp(arg);
}
);
EXPECT_EQ(expected, res);
}
TEST(xcomplex, longdouble)
{
using cmplx = std::complex;
xt::xtensor a = xt::empty({5, 5});
xt::real(a) = 123.321L;
xt::imag(a) = -123.321L;
EXPECT_EQ(a(4, 4), cmplx(123.321L, -123.321L));
xt::real(a) = xt::imag(a);
EXPECT_EQ(a(0, 0), cmplx(-123.321L, -123.321L));
EXPECT_EQ(a(4, 4), cmplx(-123.321L, -123.321L));
}
TEST(xcomplex, build_from_double)
{
xt::xarray r = {1., 2., 3.};
xt::xarray rc(r);
EXPECT_EQ(rc(0).real(), r(0));
EXPECT_EQ(rc(1).real(), r(1));
EXPECT_EQ(rc(2).real(), r(2));
}
TEST(xcomplex, xcomplex)
{
using complex_type = xtl::xcomplex;
xt::xarray a = xt::ones(std::vector(3, 7));
auto simd_loaded = a.template load_simd(
0
);
(void) simd_loaded;
}
TEST(xcomplex, view)
{
using cpx = std::complex;
xt::xtensor a = {{cpx(1, 1), cpx(-1, 1), cpx(-2, -2)}, {cpx(-1, 0), cpx(0, 1), cpx(2, 2)}};
xtensor c = conj(view(a, 0, xt::all()));
xtensor exp_conj = {cpx(1, -1), cpx(-1, -1), cpx(-2, 2)};
EXPECT_EQ(c, exp_conj);
xtensor r = real(view(a, 0, xt::all()));
xtensor exp_real = {double(1), double(-1), double(-2)};
EXPECT_EQ(r, exp_real);
xtensor im = imag(view(a, 0, xt::all()));
xtensor exp_im = {double(1), double(1), double(-2)};
EXPECT_EQ(im, exp_im);
}
}