/*************************************************************************** * 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, decltype(cmplres_angle)>; #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>, decltype(cmplres_conj)>; #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, decltype(cmplres_norm)>; #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, decltype(cmplres)>; #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::size>( 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); } }