diff --git a/common/unit_test/Test_Transpose.cpp b/common/unit_test/Test_Transpose.cpp index 982fa3c3..659d8a35 100644 --- a/common/unit_test/Test_Transpose.cpp +++ b/common/unit_test/Test_Transpose.cpp @@ -18,12 +18,24 @@ struct MapAxes : public ::testing::Test { }; template -struct Transpose : public ::testing::Test { +struct Transpose1D : public ::testing::Test { + using layout_type = T; +}; + +template +struct Transpose2D : public ::testing::Test { + using layout_type = T; +}; + +template +struct Transpose3D : public ::testing::Test { using layout_type = T; }; TYPED_TEST_SUITE(MapAxes, test_types); -TYPED_TEST_SUITE(Transpose, test_types); +TYPED_TEST_SUITE(Transpose1D, test_types); +TYPED_TEST_SUITE(Transpose2D, test_types); +TYPED_TEST_SUITE(Transpose3D, test_types); // Tests for map axes over ND views template @@ -317,8 +329,9 @@ TYPED_TEST(MapAxes, 3DView) { } // Tests for transpose +// 1D Transpose template -void test_transpose_1d() { +void test_transpose_1d_1dview() { // When transpose is not necessary, we should not call transpose method const int len = 30; View1D x("x", len), ref("ref", len); @@ -337,121 +350,127 @@ void test_transpose_1d() { } template -void test_transpose_2d() { +void test_transpose_1d_2dview() { using RealView2Dtype = Kokkos::View; + constexpr int DIM = 2; const int n0 = 3, n1 = 5; - RealView2Dtype x("x", n0, n1), ref("ref", n1, n0); - RealView2Dtype xt_axis01, xt_axis10; // views are allocated internally + RealView2Dtype x("x", n0, n1); Kokkos::Random_XorShift64_Pool<> random_pool(12345); Kokkos::fill_random(x, random_pool, 1.0); - // Transposed views - auto h_x = Kokkos::create_mirror_view(x); - auto h_ref = Kokkos::create_mirror_view(ref); + auto h_x = Kokkos::create_mirror_view(x); Kokkos::deep_copy(h_x, x); - for (int i0 = 0; i0 < h_x.extent(0); i0++) { - for (int i1 = 0; i1 < h_x.extent(1); i1++) { - h_ref(i1, i0) = h_x(i0, i1); + // Transposed views + axes_type default_axes({0, 1}); + + for (int axis0 = 0; axis0 < DIM; axis0++) { + auto [map, map_inv] = KokkosFFT::Impl::get_map_axes(x, axis0); + axes_type out_extents; + for (int i = 0; i < DIM; i++) { + out_extents.at(i) = x.extent(map.at(i)); } - } - Kokkos::deep_copy(ref, h_ref); - Kokkos::fence(); + auto [_n0, _n1] = out_extents; - EXPECT_THROW( - KokkosFFT::Impl::transpose(execution_space(), x, xt_axis01, - axes_type<2>({0, 1})), // xt is identical to x - std::runtime_error); + RealView2Dtype xt; + if (map == default_axes) { + EXPECT_THROW(KokkosFFT::Impl::transpose(execution_space(), x, xt, + map), // xt is identical to x + std::runtime_error); + } else { + // Transposed Views + RealView2Dtype ref("ref", _n0, _n1); + auto h_ref = Kokkos::create_mirror_view(ref); + // Filling the transposed View + for (int i0 = 0; i0 < h_x.extent(0); i0++) { + for (int i1 = 0; i1 < h_x.extent(1); i1++) { + h_ref(i1, i0) = h_x(i0, i1); + } + } - KokkosFFT::Impl::transpose(execution_space(), x, xt_axis10, - axes_type<2>({1, 0})); // xt is the transpose of x - EXPECT_TRUE(allclose(xt_axis10, ref, 1.e-5, 1.e-12)); + Kokkos::deep_copy(ref, h_ref); + Kokkos::fence(); + + KokkosFFT::Impl::transpose(execution_space(), x, xt, + map); // xt is the transpose of x + EXPECT_TRUE(allclose(xt, ref, 1.e-5, 1.e-12)); + + // Inverse (transpose of transpose is identical to the original) + RealView2Dtype _x; + KokkosFFT::Impl::transpose(execution_space(), xt, _x, map_inv); + EXPECT_TRUE(allclose(_x, x, 1.e-5, 1.e-12)); + } + } } template -void test_transpose_3d() { +void test_transpose_1d_3dview() { using RealView3Dtype = Kokkos::View; + constexpr int DIM = 3; const int n0 = 3, n1 = 5, n2 = 8; RealView3Dtype x("x", n0, n1, n2); - RealView3Dtype xt_axis012, xt_axis021, xt_axis102, xt_axis120, xt_axis201, - xt_axis210; // views are allocated internally - RealView3Dtype ref_axis021("ref_axis021", n0, n2, n1), - ref_axis102("ref_axis102", n1, n0, n2); - RealView3Dtype ref_axis120("ref_axis120", n1, n2, n0), - ref_axis201("ref_axis201", n2, n0, n1), - ref_axis210("ref_axis210", n2, n1, n0); Kokkos::Random_XorShift64_Pool<> random_pool(12345); Kokkos::fill_random(x, random_pool, 1.0); - // Transposed views - auto h_x = Kokkos::create_mirror_view(x); - auto h_ref_axis021 = Kokkos::create_mirror_view(ref_axis021); - auto h_ref_axis102 = Kokkos::create_mirror_view(ref_axis102); - auto h_ref_axis120 = Kokkos::create_mirror_view(ref_axis120); - auto h_ref_axis201 = Kokkos::create_mirror_view(ref_axis201); - auto h_ref_axis210 = Kokkos::create_mirror_view(ref_axis210); - + auto h_x = Kokkos::create_mirror_view(x); Kokkos::deep_copy(h_x, x); - for (int i0 = 0; i0 < h_x.extent(0); i0++) { - for (int i1 = 0; i1 < h_x.extent(1); i1++) { - for (int i2 = 0; i2 < h_x.extent(2); i2++) { - h_ref_axis021(i0, i2, i1) = h_x(i0, i1, i2); - h_ref_axis102(i1, i0, i2) = h_x(i0, i1, i2); - h_ref_axis120(i1, i2, i0) = h_x(i0, i1, i2); - h_ref_axis201(i2, i0, i1) = h_x(i0, i1, i2); - h_ref_axis210(i2, i1, i0) = h_x(i0, i1, i2); - } - } - } - - Kokkos::deep_copy(ref_axis021, h_ref_axis021); - Kokkos::deep_copy(ref_axis102, h_ref_axis102); - Kokkos::deep_copy(ref_axis120, h_ref_axis120); - Kokkos::deep_copy(ref_axis201, h_ref_axis201); - Kokkos::deep_copy(ref_axis210, h_ref_axis210); - - Kokkos::fence(); - - EXPECT_THROW(KokkosFFT::Impl::transpose( - execution_space(), x, xt_axis012, - axes_type<3>({0, 1, 2})), // xt is identical to x - std::runtime_error); + // Transposed views + axes_type default_axes({0, 1, 2}); - KokkosFFT::Impl::transpose( - execution_space(), x, xt_axis021, - axes_type<3>({0, 2, 1})); // xt is the transpose of x - EXPECT_TRUE(allclose(xt_axis021, ref_axis021, 1.e-5, 1.e-12)); + for (int axis0 = 0; axis0 < DIM; axis0++) { + auto [map, map_inv] = KokkosFFT::Impl::get_map_axes(x, axis0); + axes_type out_extents; + for (int i = 0; i < DIM; i++) { + out_extents.at(i) = x.extent(map.at(i)); + } + auto [_n0, _n1, _n2] = out_extents; - KokkosFFT::Impl::transpose( - execution_space(), x, xt_axis102, - axes_type<3>({1, 0, 2})); // xt is the transpose of x - EXPECT_TRUE(allclose(xt_axis102, ref_axis102, 1.e-5, 1.e-12)); + RealView3Dtype xt; + if (map == default_axes) { + EXPECT_THROW(KokkosFFT::Impl::transpose(execution_space(), x, xt, + map), // xt is identical to x + std::runtime_error); + } else { + // Transposed Views + RealView3Dtype ref("ref", _n0, _n1, _n2); + auto h_ref = Kokkos::create_mirror_view(ref); + // Filling the transposed View + for (int i0 = 0; i0 < h_x.extent(0); i0++) { + for (int i1 = 0; i1 < h_x.extent(1); i1++) { + for (int i2 = 0; i2 < h_x.extent(2); i2++) { + int _i0 = (map[0] == 1) ? i1 : (map[0] == 2) ? i2 : i0; + int _i1 = (map[1] == 0) ? i0 : (map[1] == 2) ? i2 : i1; + int _i2 = (map[2] == 0) ? i0 : (map[2] == 1) ? i1 : i2; + + h_ref(_i0, _i1, _i2) = h_x(i0, i1, i2); + } + } + } - KokkosFFT::Impl::transpose( - execution_space(), x, xt_axis120, - axes_type<3>({1, 2, 0})); // xt is the transpose of x - EXPECT_TRUE(allclose(xt_axis120, ref_axis120, 1.e-5, 1.e-12)); + Kokkos::deep_copy(ref, h_ref); + Kokkos::fence(); - KokkosFFT::Impl::transpose( - execution_space(), x, xt_axis201, - axes_type<3>({2, 0, 1})); // xt is the transpose of x - EXPECT_TRUE(allclose(xt_axis201, ref_axis201, 1.e-5, 1.e-12)); + KokkosFFT::Impl::transpose(execution_space(), x, xt, + map); // xt is the transpose of x + EXPECT_TRUE(allclose(xt, ref, 1.e-5, 1.e-12)); - KokkosFFT::Impl::transpose( - execution_space(), x, xt_axis210, - axes_type<3>({2, 1, 0})); // xt is the transpose of x - EXPECT_TRUE(allclose(xt_axis210, ref_axis210, 1.e-5, 1.e-12)); + // Inverse (transpose of transpose is identical to the original) + RealView3Dtype _x; + KokkosFFT::Impl::transpose(execution_space(), xt, _x, map_inv); + EXPECT_TRUE(allclose(_x, x, 1.e-5, 1.e-12)); + } + } } template -void test_transpose_4d() { - using RealView4DType = Kokkos::View; +void test_transpose_1d_4dview() { + using RealView4Dtype = Kokkos::View; + constexpr int DIM = 4; const int n0 = 2, n1 = 3, n2 = 4, n3 = 5; - constexpr std::size_t DIM = 4; - RealView4DType x("x", n0, n1, n2, n3); + RealView4Dtype x("x", n0, n1, n2, n3); Kokkos::Random_XorShift64_Pool<> random_pool(12345); Kokkos::fill_random(x, random_pool, 1.0); @@ -462,107 +481,72 @@ void test_transpose_4d() { // Transposed views axes_type default_axes({0, 1, 2, 3}); - std::vector > list_of_tested_axes = { - axes_type({0, 1, 2, 3}), axes_type({0, 1, 3, 2}), - axes_type({0, 2, 1, 3}), axes_type({0, 2, 3, 1}), - axes_type({0, 3, 1, 2}), axes_type({0, 3, 2, 1}), - axes_type({1, 0, 2, 3}), axes_type({1, 0, 3, 2}), - axes_type({1, 2, 0, 3}), axes_type({1, 2, 3, 0}), - axes_type({1, 3, 0, 2}), axes_type({1, 3, 2, 0}), - axes_type({2, 0, 1, 3}), axes_type({2, 0, 3, 1}), - axes_type({2, 1, 0, 3}), axes_type({2, 1, 3, 0}), - axes_type({2, 3, 0, 1}), axes_type({2, 3, 1, 0}), - axes_type({3, 0, 1, 2}), axes_type({3, 0, 2, 1}), - axes_type({3, 1, 0, 2}), axes_type({3, 1, 2, 0}), - axes_type({3, 2, 0, 1}), axes_type({3, 2, 1, 0})}; - - for (auto& tested_axes : list_of_tested_axes) { + for (int axis0 = 0; axis0 < DIM; axis0++) { + auto [map, map_inv] = KokkosFFT::Impl::get_map_axes(x, axis0); axes_type out_extents; - auto [map, map_inv] = KokkosFFT::Impl::get_map_axes(x, tested_axes); - - // Convert to vector, need to reverse the order for LayoutLeft - std::vector _map(map.begin(), map.end()); - if (std::is_same::value) { - std::reverse(_map.begin(), _map.end()); - } - for (int i = 0; i < DIM; i++) { - out_extents.at(i) = x.extent(_map.at(i)); + out_extents.at(i) = x.extent(map.at(i)); } - auto [_n0, _n1, _n2, _n3] = out_extents; - RealView4DType xt; - RealView4DType ref("ref", _n0, _n1, _n2, _n3); - - // Transposed Views - auto h_ref = Kokkos::create_mirror_view(ref); - - // Filling the transposed View - for (int i0 = 0; i0 < h_x.extent(0); i0++) { - for (int i1 = 0; i1 < h_x.extent(1); i1++) { - for (int i2 = 0; i2 < h_x.extent(2); i2++) { - for (int i3 = 0; i3 < h_x.extent(3); i3++) { - int _i0 = i0, _i1 = i1, _i2 = i2, _i3 = i3; - if (_map[0] == 1) { - _i0 = i1; - } else if (_map[0] == 2) { - _i0 = i2; - } else if (_map[0] == 3) { - _i0 = i3; - } - - if (_map[1] == 0) { - _i1 = i0; - } else if (_map[1] == 2) { - _i1 = i2; - } else if (_map[1] == 3) { - _i1 = i3; - } - - if (_map[2] == 0) { - _i2 = i0; - } else if (_map[2] == 1) { - _i2 = i1; - } else if (_map[2] == 3) { - _i2 = i3; - } - if (_map[3] == 0) { - _i3 = i0; - } else if (_map[3] == 1) { - _i3 = i1; - } else if (_map[3] == 2) { - _i3 = i2; + RealView4Dtype xt; + if (map == default_axes) { + EXPECT_THROW(KokkosFFT::Impl::transpose(execution_space(), x, xt, + map), // xt is identical to x + std::runtime_error); + } else { + // Transposed Views + RealView4Dtype ref("ref", _n0, _n1, _n2, _n3); + auto h_ref = Kokkos::create_mirror_view(ref); + // Filling the transposed View + for (int i0 = 0; i0 < h_x.extent(0); i0++) { + for (int i1 = 0; i1 < h_x.extent(1); i1++) { + for (int i2 = 0; i2 < h_x.extent(2); i2++) { + for (int i3 = 0; i3 < h_x.extent(3); i3++) { + int _i0 = (map[0] == 1) ? i1 + : (map[0] == 2) ? i2 + : (map[0] == 3) ? i3 + : i0; + int _i1 = (map[1] == 0) ? i0 + : (map[1] == 2) ? i2 + : (map[1] == 3) ? i3 + : i1; + int _i2 = (map[2] == 0) ? i0 + : (map[2] == 1) ? i1 + : (map[2] == 3) ? i3 + : i2; + int _i3 = (map[3] == 0) ? i0 + : (map[3] == 1) ? i1 + : (map[3] == 2) ? i2 + : i3; + + h_ref(_i0, _i1, _i2, _i3) = h_x(i0, i1, i2, i3); } - - h_ref(_i0, _i1, _i2, _i3) = h_x(i0, i1, i2, i3); } } } - } - Kokkos::deep_copy(ref, h_ref); - Kokkos::fence(); + Kokkos::deep_copy(ref, h_ref); + Kokkos::fence(); - if (tested_axes == default_axes) { - EXPECT_THROW( - KokkosFFT::Impl::transpose(execution_space(), x, xt, - tested_axes), // xt is identical to x - std::runtime_error); - } else { KokkosFFT::Impl::transpose(execution_space(), x, xt, - tested_axes); // xt is the transpose of x + map); // xt is the transpose of x EXPECT_TRUE(allclose(xt, ref, 1.e-5, 1.e-12)); + + // Inverse (transpose of transpose is identical to the original) + RealView4Dtype _x; + KokkosFFT::Impl::transpose(execution_space(), xt, _x, map_inv); + EXPECT_TRUE(allclose(_x, x, 1.e-5, 1.e-12)); } } } template -void test_transpose_5d() { - using RealView5DType = Kokkos::View; +void test_transpose_1d_5dview() { + using RealView5Dtype = Kokkos::View; + constexpr int DIM = 5; const int n0 = 2, n1 = 3, n2 = 4, n3 = 5, n4 = 6; - constexpr std::size_t DIM = 5; - RealView5DType x("x", n0, n1, n2, n3, n4); + RealView5Dtype x("x", n0, n1, n2, n3, n4); Kokkos::Random_XorShift64_Pool<> random_pool(12345); Kokkos::fill_random(x, random_pool, 1.0); @@ -573,137 +557,83 @@ void test_transpose_5d() { // Transposed views axes_type default_axes({0, 1, 2, 3, 4}); - // Randomly choosen axes - std::vector > list_of_tested_axes = { - axes_type({0, 1, 2, 3, 4}), axes_type({0, 1, 3, 2, 4}), - axes_type({0, 2, 1, 3, 4}), axes_type({0, 2, 3, 4, 1}), - axes_type({0, 3, 4, 1, 2}), axes_type({0, 3, 2, 1, 4}), - axes_type({0, 4, 3, 1, 2}), axes_type({0, 4, 2, 1, 3}), - axes_type({1, 0, 2, 3, 4}), axes_type({1, 0, 4, 3, 2}), - axes_type({1, 2, 0, 3, 4}), axes_type({1, 2, 3, 4, 0}), - axes_type({1, 3, 0, 4, 2}), axes_type({1, 3, 4, 2, 0}), - axes_type({1, 4, 0, 2, 3}), axes_type({1, 4, 3, 2, 0}), - axes_type({2, 0, 1, 3, 4}), axes_type({2, 0, 4, 3, 1}), - axes_type({2, 1, 0, 3, 4}), axes_type({2, 1, 3, 4, 0}), - axes_type({2, 3, 4, 0, 1}), axes_type({2, 3, 4, 1, 0}), - axes_type({2, 4, 3, 0, 1}), axes_type({2, 4, 1, 0, 3}), - axes_type({3, 0, 1, 2, 4}), axes_type({3, 0, 2, 4, 1}), - axes_type({3, 1, 0, 2, 4}), axes_type({3, 1, 4, 2, 0}), - axes_type({3, 2, 0, 1, 4}), axes_type({3, 2, 1, 4, 0}), - axes_type({3, 4, 0, 1, 2}), axes_type({3, 4, 1, 2, 0}), - axes_type({4, 0, 1, 2, 3}), axes_type({4, 0, 1, 3, 2}), - axes_type({4, 1, 2, 0, 3}), axes_type({4, 1, 2, 3, 0}), - axes_type({4, 2, 3, 1, 0}), axes_type({4, 2, 3, 0, 1}), - axes_type({4, 3, 1, 0, 2}), axes_type({4, 3, 2, 0, 1})}; - - for (auto& tested_axes : list_of_tested_axes) { + for (int axis0 = 0; axis0 < DIM; axis0++) { + auto [map, map_inv] = KokkosFFT::Impl::get_map_axes(x, axis0); axes_type out_extents; - auto [map, map_inv] = KokkosFFT::Impl::get_map_axes(x, tested_axes); - - // Convert to vector, need to reverse the order for LayoutLeft - std::vector _map(map.begin(), map.end()); - if (std::is_same::value) { - std::reverse(_map.begin(), _map.end()); - } - for (int i = 0; i < DIM; i++) { - out_extents.at(i) = x.extent(_map.at(i)); + out_extents.at(i) = x.extent(map.at(i)); } - auto [_n0, _n1, _n2, _n3, _n4] = out_extents; - RealView5DType xt; - RealView5DType ref("ref", _n0, _n1, _n2, _n3, _n4); - - // Transposed Views - auto h_ref = Kokkos::create_mirror_view(ref); - - // Filling the transposed View - for (int i0 = 0; i0 < h_x.extent(0); i0++) { - for (int i1 = 0; i1 < h_x.extent(1); i1++) { - for (int i2 = 0; i2 < h_x.extent(2); i2++) { - for (int i3 = 0; i3 < h_x.extent(3); i3++) { - for (int i4 = 0; i4 < h_x.extent(4); i4++) { - int _i0 = i0, _i1 = i1, _i2 = i2, _i3 = i3, _i4 = i4; - if (_map[0] == 1) { - _i0 = i1; - } else if (_map[0] == 2) { - _i0 = i2; - } else if (_map[0] == 3) { - _i0 = i3; - } else if (_map[0] == 4) { - _i0 = i4; - } - - if (_map[1] == 0) { - _i1 = i0; - } else if (_map[1] == 2) { - _i1 = i2; - } else if (_map[1] == 3) { - _i1 = i3; - } else if (_map[1] == 4) { - _i1 = i4; - } - - if (_map[2] == 0) { - _i2 = i0; - } else if (_map[2] == 1) { - _i2 = i1; - } else if (_map[2] == 3) { - _i2 = i3; - } else if (_map[2] == 4) { - _i2 = i4; - } - if (_map[3] == 0) { - _i3 = i0; - } else if (_map[3] == 1) { - _i3 = i1; - } else if (_map[3] == 2) { - _i3 = i2; - } else if (_map[3] == 4) { - _i3 = i4; - } - - if (_map[4] == 0) { - _i4 = i0; - } else if (_map[4] == 1) { - _i4 = i1; - } else if (_map[4] == 2) { - _i4 = i2; - } else if (_map[4] == 3) { - _i4 = i3; + RealView5Dtype xt; + if (map == default_axes) { + EXPECT_THROW(KokkosFFT::Impl::transpose(execution_space(), x, xt, + map), // xt is identical to x + std::runtime_error); + } else { + // Transposed Views + RealView5Dtype ref("ref", _n0, _n1, _n2, _n3, _n4); + auto h_ref = Kokkos::create_mirror_view(ref); + // Filling the transposed View + for (int i0 = 0; i0 < h_x.extent(0); i0++) { + for (int i1 = 0; i1 < h_x.extent(1); i1++) { + for (int i2 = 0; i2 < h_x.extent(2); i2++) { + for (int i3 = 0; i3 < h_x.extent(3); i3++) { + for (int i4 = 0; i4 < h_x.extent(4); i4++) { + int _i0 = (map[0] == 1) ? i1 + : (map[0] == 2) ? i2 + : (map[0] == 3) ? i3 + : (map[0] == 4) ? i4 + : i0; + int _i1 = (map[1] == 0) ? i0 + : (map[1] == 2) ? i2 + : (map[1] == 3) ? i3 + : (map[1] == 4) ? i4 + : i1; + int _i2 = (map[2] == 0) ? i0 + : (map[2] == 1) ? i1 + : (map[2] == 3) ? i3 + : (map[2] == 4) ? i4 + : i2; + int _i3 = (map[3] == 0) ? i0 + : (map[3] == 1) ? i1 + : (map[3] == 2) ? i2 + : (map[3] == 4) ? i4 + : i3; + int _i4 = (map[4] == 0) ? i0 + : (map[4] == 1) ? i1 + : (map[4] == 2) ? i2 + : (map[4] == 3) ? i3 + : i4; + h_ref(_i0, _i1, _i2, _i3, _i4) = h_x(i0, i1, i2, i3, i4); } - - h_ref(_i0, _i1, _i2, _i3, _i4) = h_x(i0, i1, i2, i3, i4); } } } } - } - Kokkos::deep_copy(ref, h_ref); - Kokkos::fence(); + Kokkos::deep_copy(ref, h_ref); + Kokkos::fence(); - if (tested_axes == default_axes) { - EXPECT_THROW( - KokkosFFT::Impl::transpose(execution_space(), x, xt, - tested_axes), // xt is identical to x - std::runtime_error); - } else { KokkosFFT::Impl::transpose(execution_space(), x, xt, - tested_axes); // xt is the transpose of x + map); // xt is the transpose of x EXPECT_TRUE(allclose(xt, ref, 1.e-5, 1.e-12)); + + // Inverse (transpose of transpose is identical to the original) + RealView5Dtype _x; + KokkosFFT::Impl::transpose(execution_space(), xt, _x, map_inv); + EXPECT_TRUE(allclose(_x, x, 1.e-5, 1.e-12)); } } } template -void test_transpose_6d() { - using RealView6DType = +void test_transpose_1d_6dview() { + using RealView6Dtype = Kokkos::View; + constexpr int DIM = 6; const int n0 = 2, n1 = 3, n2 = 4, n3 = 5, n4 = 6, n5 = 7; - constexpr std::size_t DIM = 6; - RealView6DType x("x", n0, n1, n2, n3, n4, n5); + RealView6Dtype x("x", n0, n1, n2, n3, n4, n5); Kokkos::Random_XorShift64_Pool<> random_pool(12345); Kokkos::fill_random(x, random_pool, 1.0); @@ -714,151 +644,97 @@ void test_transpose_6d() { // Transposed views axes_type default_axes({0, 1, 2, 3, 4, 5}); - // Too much combinations, choose axes randomly - std::vector > list_of_tested_axes; - - constexpr int nb_trials = 100; - auto rng = std::default_random_engine{}; - - for (int i = 0; i < nb_trials; i++) { - axes_type tmp_axes = default_axes; - std::shuffle(std::begin(tmp_axes), std::end(tmp_axes), rng); - list_of_tested_axes.push_back(tmp_axes); - } - - for (auto& tested_axes : list_of_tested_axes) { + for (int axis0 = 0; axis0 < DIM; axis0++) { + auto [map, map_inv] = KokkosFFT::Impl::get_map_axes(x, axis0); axes_type out_extents; - auto [map, map_inv] = KokkosFFT::Impl::get_map_axes(x, tested_axes); - - // Convert to vector, need to reverse the order for LayoutLeft - std::vector _map(map.begin(), map.end()); - if (std::is_same::value) { - std::reverse(_map.begin(), _map.end()); - } - for (int i = 0; i < DIM; i++) { - out_extents.at(i) = x.extent(_map.at(i)); + out_extents.at(i) = x.extent(map.at(i)); } - auto [_n0, _n1, _n2, _n3, _n4, _n5] = out_extents; - RealView6DType xt; - RealView6DType ref("ref", _n0, _n1, _n2, _n3, _n4, _n5); - - // Transposed Views - auto h_ref = Kokkos::create_mirror_view(ref); - - // Filling the transposed View - for (int i0 = 0; i0 < h_x.extent(0); i0++) { - for (int i1 = 0; i1 < h_x.extent(1); i1++) { - for (int i2 = 0; i2 < h_x.extent(2); i2++) { - for (int i3 = 0; i3 < h_x.extent(3); i3++) { - for (int i4 = 0; i4 < h_x.extent(4); i4++) { - for (int i5 = 0; i5 < h_x.extent(5); i5++) { - int _i0 = i0, _i1 = i1, _i2 = i2, _i3 = i3, _i4 = i4, _i5 = i5; - if (_map[0] == 1) { - _i0 = i1; - } else if (_map[0] == 2) { - _i0 = i2; - } else if (_map[0] == 3) { - _i0 = i3; - } else if (_map[0] == 4) { - _i0 = i4; - } else if (_map[0] == 5) { - _i0 = i5; - } - - if (_map[1] == 0) { - _i1 = i0; - } else if (_map[1] == 2) { - _i1 = i2; - } else if (_map[1] == 3) { - _i1 = i3; - } else if (_map[1] == 4) { - _i1 = i4; - } else if (_map[1] == 5) { - _i1 = i5; - } - - if (_map[2] == 0) { - _i2 = i0; - } else if (_map[2] == 1) { - _i2 = i1; - } else if (_map[2] == 3) { - _i2 = i3; - } else if (_map[2] == 4) { - _i2 = i4; - } else if (_map[2] == 5) { - _i2 = i5; - } - - if (_map[3] == 0) { - _i3 = i0; - } else if (_map[3] == 1) { - _i3 = i1; - } else if (_map[3] == 2) { - _i3 = i2; - } else if (_map[3] == 4) { - _i3 = i4; - } else if (_map[3] == 5) { - _i3 = i5; - } - - if (_map[4] == 0) { - _i4 = i0; - } else if (_map[4] == 1) { - _i4 = i1; - } else if (_map[4] == 2) { - _i4 = i2; - } else if (_map[4] == 3) { - _i4 = i3; - } else if (_map[4] == 5) { - _i4 = i5; - } - if (_map[5] == 0) { - _i5 = i0; - } else if (_map[5] == 1) { - _i5 = i1; - } else if (_map[5] == 2) { - _i5 = i2; - } else if (_map[5] == 3) { - _i5 = i3; - } else if (_map[5] == 4) { - _i5 = i4; + RealView6Dtype xt; + if (map == default_axes) { + EXPECT_THROW(KokkosFFT::Impl::transpose(execution_space(), x, xt, + map), // xt is identical to x + std::runtime_error); + } else { + // Transposed Views + RealView6Dtype ref("ref", _n0, _n1, _n2, _n3, _n4, _n5); + auto h_ref = Kokkos::create_mirror_view(ref); + // Filling the transposed View + for (int i0 = 0; i0 < h_x.extent(0); i0++) { + for (int i1 = 0; i1 < h_x.extent(1); i1++) { + for (int i2 = 0; i2 < h_x.extent(2); i2++) { + for (int i3 = 0; i3 < h_x.extent(3); i3++) { + for (int i4 = 0; i4 < h_x.extent(4); i4++) { + for (int i5 = 0; i5 < h_x.extent(5); i5++) { + int _i0 = (map[0] == 1) ? i1 + : (map[0] == 2) ? i2 + : (map[0] == 3) ? i3 + : (map[0] == 4) ? i4 + : (map[0] == 5) ? i5 + : i0; + int _i1 = (map[1] == 0) ? i0 + : (map[1] == 2) ? i2 + : (map[1] == 3) ? i3 + : (map[1] == 4) ? i4 + : (map[1] == 5) ? i5 + : i1; + int _i2 = (map[2] == 0) ? i0 + : (map[2] == 1) ? i1 + : (map[2] == 3) ? i3 + : (map[2] == 4) ? i4 + : (map[2] == 5) ? i5 + : i2; + int _i3 = (map[3] == 0) ? i0 + : (map[3] == 1) ? i1 + : (map[3] == 2) ? i2 + : (map[3] == 4) ? i4 + : (map[3] == 5) ? i5 + : i3; + int _i4 = (map[4] == 0) ? i0 + : (map[4] == 1) ? i1 + : (map[4] == 2) ? i2 + : (map[4] == 3) ? i3 + : (map[4] == 5) ? i5 + : i4; + int _i5 = (map[5] == 0) ? i0 + : (map[5] == 1) ? i1 + : (map[5] == 2) ? i2 + : (map[5] == 3) ? i3 + : (map[5] == 4) ? i4 + : i5; + h_ref(_i0, _i1, _i2, _i3, _i4, _i5) = + h_x(i0, i1, i2, i3, i4, i5); } - - h_ref(_i0, _i1, _i2, _i3, _i4, _i5) = - h_x(i0, i1, i2, i3, i4, i5); } } } } } - } - Kokkos::deep_copy(ref, h_ref); - Kokkos::fence(); + Kokkos::deep_copy(ref, h_ref); + Kokkos::fence(); - if (tested_axes == default_axes) { - EXPECT_THROW( - KokkosFFT::Impl::transpose(execution_space(), x, xt, - tested_axes), // xt is identical to x - std::runtime_error); - } else { KokkosFFT::Impl::transpose(execution_space(), x, xt, - tested_axes); // xt is the transpose of x + map); // xt is the transpose of x EXPECT_TRUE(allclose(xt, ref, 1.e-5, 1.e-12)); + + // Inverse (transpose of transpose is identical to the original) + RealView6Dtype _x; + KokkosFFT::Impl::transpose(execution_space(), xt, _x, map_inv); + EXPECT_TRUE(allclose(_x, x, 1.e-5, 1.e-12)); } } } template -void test_transpose_7d() { - using RealView7DType = +void test_transpose_1d_7dview() { + using RealView7Dtype = Kokkos::View; + constexpr int DIM = 7; const int n0 = 2, n1 = 3, n2 = 4, n3 = 5, n4 = 6, n5 = 7, n6 = 8; - constexpr std::size_t DIM = 7; - RealView7DType x("x", n0, n1, n2, n3, n4, n5, n6); + RealView7Dtype x("x", n0, n1, n2, n3, n4, n5, n6); Kokkos::Random_XorShift64_Pool<> random_pool(12345); Kokkos::fill_random(x, random_pool, 1.0); @@ -869,180 +745,112 @@ void test_transpose_7d() { // Transposed views axes_type default_axes({0, 1, 2, 3, 4, 5, 6}); - // Too much combinations, choose axes randomly - std::vector > list_of_tested_axes; - - constexpr int nb_trials = 100; - auto rng = std::default_random_engine{}; - - for (int i = 0; i < nb_trials; i++) { - axes_type tmp_axes = default_axes; - std::shuffle(std::begin(tmp_axes), std::end(tmp_axes), rng); - list_of_tested_axes.push_back(tmp_axes); - } - - for (auto& tested_axes : list_of_tested_axes) { + for (int axis0 = 0; axis0 < DIM; axis0++) { + auto [map, map_inv] = KokkosFFT::Impl::get_map_axes(x, axis0); axes_type out_extents; - auto [map, map_inv] = KokkosFFT::Impl::get_map_axes(x, tested_axes); - - // Convert to vector, need to reverse the order for LayoutLeft - std::vector _map(map.begin(), map.end()); - if (std::is_same::value) { - std::reverse(_map.begin(), _map.end()); - } - for (int i = 0; i < DIM; i++) { - out_extents.at(i) = x.extent(_map.at(i)); + out_extents.at(i) = x.extent(map.at(i)); } - auto [_n0, _n1, _n2, _n3, _n4, _n5, _n6] = out_extents; - RealView7DType xt; - RealView7DType ref("ref", _n0, _n1, _n2, _n3, _n4, _n5, _n6); - - // Transposed Views - auto h_ref = Kokkos::create_mirror_view(ref); - - // Filling the transposed View - for (int i0 = 0; i0 < h_x.extent(0); i0++) { - for (int i1 = 0; i1 < h_x.extent(1); i1++) { - for (int i2 = 0; i2 < h_x.extent(2); i2++) { - for (int i3 = 0; i3 < h_x.extent(3); i3++) { - for (int i4 = 0; i4 < h_x.extent(4); i4++) { - for (int i5 = 0; i5 < h_x.extent(5); i5++) { - for (int i6 = 0; i6 < h_x.extent(6); i6++) { - int _i0 = i0, _i1 = i1, _i2 = i2, _i3 = i3, _i4 = i4, - _i5 = i5, _i6 = i6; - if (_map[0] == 1) { - _i0 = i1; - } else if (_map[0] == 2) { - _i0 = i2; - } else if (_map[0] == 3) { - _i0 = i3; - } else if (_map[0] == 4) { - _i0 = i4; - } else if (_map[0] == 5) { - _i0 = i5; - } else if (_map[0] == 6) { - _i0 = i6; - } - if (_map[1] == 0) { - _i1 = i0; - } else if (_map[1] == 2) { - _i1 = i2; - } else if (_map[1] == 3) { - _i1 = i3; - } else if (_map[1] == 4) { - _i1 = i4; - } else if (_map[1] == 5) { - _i1 = i5; - } else if (_map[1] == 6) { - _i1 = i6; - } - - if (_map[2] == 0) { - _i2 = i0; - } else if (_map[2] == 1) { - _i2 = i1; - } else if (_map[2] == 3) { - _i2 = i3; - } else if (_map[2] == 4) { - _i2 = i4; - } else if (_map[2] == 5) { - _i2 = i5; - } else if (_map[2] == 6) { - _i2 = i6; - } - - if (_map[3] == 0) { - _i3 = i0; - } else if (_map[3] == 1) { - _i3 = i1; - } else if (_map[3] == 2) { - _i3 = i2; - } else if (_map[3] == 4) { - _i3 = i4; - } else if (_map[3] == 5) { - _i3 = i5; - } else if (_map[3] == 6) { - _i3 = i6; - } - - if (_map[4] == 0) { - _i4 = i0; - } else if (_map[4] == 1) { - _i4 = i1; - } else if (_map[4] == 2) { - _i4 = i2; - } else if (_map[4] == 3) { - _i4 = i3; - } else if (_map[4] == 5) { - _i4 = i5; - } else if (_map[4] == 6) { - _i4 = i6; - } - - if (_map[5] == 0) { - _i5 = i0; - } else if (_map[5] == 1) { - _i5 = i1; - } else if (_map[5] == 2) { - _i5 = i2; - } else if (_map[5] == 3) { - _i5 = i3; - } else if (_map[5] == 4) { - _i5 = i4; - } else if (_map[5] == 6) { - _i5 = i6; - } - - if (_map[6] == 0) { - _i6 = i0; - } else if (_map[6] == 1) { - _i6 = i1; - } else if (_map[6] == 2) { - _i6 = i2; - } else if (_map[6] == 3) { - _i6 = i3; - } else if (_map[6] == 4) { - _i6 = i4; - } else if (_map[6] == 5) { - _i6 = i5; + RealView7Dtype xt; + if (map == default_axes) { + EXPECT_THROW(KokkosFFT::Impl::transpose(execution_space(), x, xt, + map), // xt is identical to x + std::runtime_error); + } else { + // Transposed Views + RealView7Dtype ref("ref", _n0, _n1, _n2, _n3, _n4, _n5, _n6); + auto h_ref = Kokkos::create_mirror_view(ref); + // Filling the transposed View + for (int i0 = 0; i0 < h_x.extent(0); i0++) { + for (int i1 = 0; i1 < h_x.extent(1); i1++) { + for (int i2 = 0; i2 < h_x.extent(2); i2++) { + for (int i3 = 0; i3 < h_x.extent(3); i3++) { + for (int i4 = 0; i4 < h_x.extent(4); i4++) { + for (int i5 = 0; i5 < h_x.extent(5); i5++) { + for (int i6 = 0; i6 < h_x.extent(6); i6++) { + int _i0 = (map[0] == 1) ? i1 + : (map[0] == 2) ? i2 + : (map[0] == 3) ? i3 + : (map[0] == 4) ? i4 + : (map[0] == 5) ? i5 + : (map[0] == 6) ? i6 + : i0; + int _i1 = (map[1] == 0) ? i0 + : (map[1] == 2) ? i2 + : (map[1] == 3) ? i3 + : (map[1] == 4) ? i4 + : (map[1] == 5) ? i5 + : (map[1] == 6) ? i6 + : i1; + int _i2 = (map[2] == 0) ? i0 + : (map[2] == 1) ? i1 + : (map[2] == 3) ? i3 + : (map[2] == 4) ? i4 + : (map[2] == 5) ? i5 + : (map[2] == 6) ? i6 + : i2; + int _i3 = (map[3] == 0) ? i0 + : (map[3] == 1) ? i1 + : (map[3] == 2) ? i2 + : (map[3] == 4) ? i4 + : (map[3] == 5) ? i5 + : (map[3] == 6) ? i6 + : i3; + int _i4 = (map[4] == 0) ? i0 + : (map[4] == 1) ? i1 + : (map[4] == 2) ? i2 + : (map[4] == 3) ? i3 + : (map[4] == 5) ? i5 + : (map[4] == 6) ? i6 + : i4; + int _i5 = (map[5] == 0) ? i0 + : (map[5] == 1) ? i1 + : (map[5] == 2) ? i2 + : (map[5] == 3) ? i3 + : (map[5] == 4) ? i4 + : (map[5] == 6) ? i6 + : i5; + int _i6 = (map[6] == 0) ? i0 + : (map[6] == 1) ? i1 + : (map[6] == 2) ? i2 + : (map[6] == 3) ? i3 + : (map[6] == 4) ? i4 + : (map[6] == 5) ? i5 + : i6; + h_ref(_i0, _i1, _i2, _i3, _i4, _i5, _i6) = + h_x(i0, i1, i2, i3, i4, i5, i6); } - - h_ref(_i0, _i1, _i2, _i3, _i4, _i5, _i6) = - h_x(i0, i1, i2, i3, i4, i5, i6); } } } } } } - } - Kokkos::deep_copy(ref, h_ref); - Kokkos::fence(); + Kokkos::deep_copy(ref, h_ref); + Kokkos::fence(); - if (tested_axes == default_axes) { - EXPECT_THROW( - KokkosFFT::Impl::transpose(execution_space(), x, xt, - tested_axes), // xt is identical to x - std::runtime_error); - } else { KokkosFFT::Impl::transpose(execution_space(), x, xt, - tested_axes); // xt is the transpose of x + map); // xt is the transpose of x EXPECT_TRUE(allclose(xt, ref, 1.e-5, 1.e-12)); + + // Inverse (transpose of transpose is identical to the original) + RealView7Dtype _x; + KokkosFFT::Impl::transpose(execution_space(), xt, _x, map_inv); + EXPECT_TRUE(allclose(_x, x, 1.e-5, 1.e-12)); } } } template -void test_transpose_8d() { - using RealView8DType = +void test_transpose_1d_8dview() { + using RealView8Dtype = Kokkos::View; + constexpr int DIM = 8; const int n0 = 2, n1 = 3, n2 = 4, n3 = 5, n4 = 6, n5 = 7, n6 = 8, n7 = 9; - constexpr std::size_t DIM = 8; - RealView8DType x("x", n0, n1, n2, n3, n4, n5, n6, n7); + RealView8Dtype x("x", n0, n1, n2, n3, n4, n5, n6, n7); Kokkos::Random_XorShift64_Pool<> random_pool(12345); Kokkos::fill_random(x, random_pool, 1.0); @@ -1053,180 +861,99 @@ void test_transpose_8d() { // Transposed views axes_type default_axes({0, 1, 2, 3, 4, 5, 6, 7}); - // Too much combinations, choose axes randomly - std::vector > list_of_tested_axes; - - constexpr int nb_trials = 100; - auto rng = std::default_random_engine{}; - - for (int i = 0; i < nb_trials; i++) { - axes_type tmp_axes = default_axes; - std::shuffle(std::begin(tmp_axes), std::end(tmp_axes), rng); - list_of_tested_axes.push_back(tmp_axes); - } - - for (auto& tested_axes : list_of_tested_axes) { + for (int axis0 = 0; axis0 < DIM; axis0++) { + auto [map, map_inv] = KokkosFFT::Impl::get_map_axes(x, axis0); axes_type out_extents; - auto [map, map_inv] = KokkosFFT::Impl::get_map_axes(x, tested_axes); - - // Convert to vector, need to reverse the order for LayoutLeft - std::vector _map(map.begin(), map.end()); - if (std::is_same::value) { - std::reverse(_map.begin(), _map.end()); - } - for (int i = 0; i < DIM; i++) { - out_extents.at(i) = x.extent(_map.at(i)); + out_extents.at(i) = x.extent(map.at(i)); } - auto [_n0, _n1, _n2, _n3, _n4, _n5, _n6, _n7] = out_extents; - RealView8DType xt; - RealView8DType ref("ref", _n0, _n1, _n2, _n3, _n4, _n5, _n6, _n7); - - // Transposed Views - auto h_ref = Kokkos::create_mirror_view(ref); - - // Filling the transposed View - for (int i0 = 0; i0 < h_x.extent(0); i0++) { - for (int i1 = 0; i1 < h_x.extent(1); i1++) { - for (int i2 = 0; i2 < h_x.extent(2); i2++) { - for (int i3 = 0; i3 < h_x.extent(3); i3++) { - for (int i4 = 0; i4 < h_x.extent(4); i4++) { - for (int i5 = 0; i5 < h_x.extent(5); i5++) { - for (int i6 = 0; i6 < h_x.extent(6); i6++) { - for (int i7 = 0; i7 < h_x.extent(7); i7++) { - int _i0 = i0, _i1 = i1, _i2 = i2, _i3 = i3, _i4 = i4, - _i5 = i5, _i6 = i6, _i7 = i7; - if (_map[0] == 1) { - _i0 = i1; - } else if (_map[0] == 2) { - _i0 = i2; - } else if (_map[0] == 3) { - _i0 = i3; - } else if (_map[0] == 4) { - _i0 = i4; - } else if (_map[0] == 5) { - _i0 = i5; - } else if (_map[0] == 6) { - _i0 = i6; - } else if (_map[0] == 7) { - _i0 = i7; - } - - if (_map[1] == 0) { - _i1 = i0; - } else if (_map[1] == 2) { - _i1 = i2; - } else if (_map[1] == 3) { - _i1 = i3; - } else if (_map[1] == 4) { - _i1 = i4; - } else if (_map[1] == 5) { - _i1 = i5; - } else if (_map[1] == 6) { - _i1 = i6; - } else if (_map[1] == 7) { - _i1 = i7; - } - - if (_map[2] == 0) { - _i2 = i0; - } else if (_map[2] == 1) { - _i2 = i1; - } else if (_map[2] == 3) { - _i2 = i3; - } else if (_map[2] == 4) { - _i2 = i4; - } else if (_map[2] == 5) { - _i2 = i5; - } else if (_map[2] == 6) { - _i2 = i6; - } else if (_map[2] == 7) { - _i2 = i7; - } - - if (_map[3] == 0) { - _i3 = i0; - } else if (_map[3] == 1) { - _i3 = i1; - } else if (_map[3] == 2) { - _i3 = i2; - } else if (_map[3] == 4) { - _i3 = i4; - } else if (_map[3] == 5) { - _i3 = i5; - } else if (_map[3] == 6) { - _i3 = i6; - } else if (_map[3] == 7) { - _i3 = i7; - } - - if (_map[4] == 0) { - _i4 = i0; - } else if (_map[4] == 1) { - _i4 = i1; - } else if (_map[4] == 2) { - _i4 = i2; - } else if (_map[4] == 3) { - _i4 = i3; - } else if (_map[4] == 5) { - _i4 = i5; - } else if (_map[4] == 6) { - _i4 = i6; - } else if (_map[4] == 7) { - _i4 = i7; - } - - if (_map[5] == 0) { - _i5 = i0; - } else if (_map[5] == 1) { - _i5 = i1; - } else if (_map[5] == 2) { - _i5 = i2; - } else if (_map[5] == 3) { - _i5 = i3; - } else if (_map[5] == 4) { - _i5 = i4; - } else if (_map[5] == 6) { - _i5 = i6; - } else if (_map[5] == 7) { - _i5 = i7; - } - - if (_map[6] == 0) { - _i6 = i0; - } else if (_map[6] == 1) { - _i6 = i1; - } else if (_map[6] == 2) { - _i6 = i2; - } else if (_map[6] == 3) { - _i6 = i3; - } else if (_map[6] == 4) { - _i6 = i4; - } else if (_map[6] == 5) { - _i6 = i5; - } else if (_map[6] == 7) { - _i6 = i7; - } - if (_map[7] == 0) { - _i7 = i0; - } else if (_map[7] == 1) { - _i7 = i1; - } else if (_map[7] == 2) { - _i7 = i2; - } else if (_map[7] == 3) { - _i7 = i3; - } else if (_map[7] == 4) { - _i7 = i4; - } else if (_map[7] == 5) { - _i7 = i5; - } else if (_map[7] == 6) { - _i7 = i6; + RealView8Dtype xt; + if (map == default_axes) { + EXPECT_THROW(KokkosFFT::Impl::transpose(execution_space(), x, xt, + map), // xt is identical to x + std::runtime_error); + } else { + // Transposed Views + RealView8Dtype ref("ref", _n0, _n1, _n2, _n3, _n4, _n5, _n6, _n7); + auto h_ref = Kokkos::create_mirror_view(ref); + // Filling the transposed View + for (int i0 = 0; i0 < h_x.extent(0); i0++) { + for (int i1 = 0; i1 < h_x.extent(1); i1++) { + for (int i2 = 0; i2 < h_x.extent(2); i2++) { + for (int i3 = 0; i3 < h_x.extent(3); i3++) { + for (int i4 = 0; i4 < h_x.extent(4); i4++) { + for (int i5 = 0; i5 < h_x.extent(5); i5++) { + for (int i6 = 0; i6 < h_x.extent(6); i6++) { + for (int i7 = 0; i7 < h_x.extent(7); i7++) { + int _i0 = (map[0] == 1) ? i1 + : (map[0] == 2) ? i2 + : (map[0] == 3) ? i3 + : (map[0] == 4) ? i4 + : (map[0] == 5) ? i5 + : (map[0] == 6) ? i6 + : (map[0] == 7) ? i7 + : i0; + int _i1 = (map[1] == 0) ? i0 + : (map[1] == 2) ? i2 + : (map[1] == 3) ? i3 + : (map[1] == 4) ? i4 + : (map[1] == 5) ? i5 + : (map[1] == 6) ? i6 + : (map[1] == 7) ? i7 + : i1; + int _i2 = (map[2] == 0) ? i0 + : (map[2] == 1) ? i1 + : (map[2] == 3) ? i3 + : (map[2] == 4) ? i4 + : (map[2] == 5) ? i5 + : (map[2] == 6) ? i6 + : (map[2] == 7) ? i7 + : i2; + int _i3 = (map[3] == 0) ? i0 + : (map[3] == 1) ? i1 + : (map[3] == 2) ? i2 + : (map[3] == 4) ? i4 + : (map[3] == 5) ? i5 + : (map[3] == 6) ? i6 + : (map[3] == 7) ? i7 + : i3; + int _i4 = (map[4] == 0) ? i0 + : (map[4] == 1) ? i1 + : (map[4] == 2) ? i2 + : (map[4] == 3) ? i3 + : (map[4] == 5) ? i5 + : (map[4] == 6) ? i6 + : (map[4] == 7) ? i7 + : i4; + int _i5 = (map[5] == 0) ? i0 + : (map[5] == 1) ? i1 + : (map[5] == 2) ? i2 + : (map[5] == 3) ? i3 + : (map[5] == 4) ? i4 + : (map[5] == 6) ? i6 + : (map[5] == 7) ? i7 + : i5; + int _i6 = (map[6] == 0) ? i0 + : (map[6] == 1) ? i1 + : (map[6] == 2) ? i2 + : (map[6] == 3) ? i3 + : (map[6] == 4) ? i4 + : (map[6] == 5) ? i5 + : (map[6] == 7) ? i7 + : i6; + int _i7 = (map[7] == 0) ? i0 + : (map[7] == 1) ? i1 + : (map[7] == 2) ? i2 + : (map[7] == 3) ? i3 + : (map[7] == 4) ? i4 + : (map[7] == 5) ? i5 + : (map[7] == 6) ? i6 + : i7; + h_ref(_i0, _i1, _i2, _i3, _i4, _i5, _i6, _i7) = + h_x(i0, i1, i2, i3, i4, i5, i6, i7); } - - h_ref(_i0, _i1, _i2, _i3, _i4, _i5, _i6, _i7) = - h_x(i0, i1, i2, i3, i4, i5, i6, i7); } } } @@ -1234,68 +961,1413 @@ void test_transpose_8d() { } } } - } - Kokkos::deep_copy(ref, h_ref); - Kokkos::fence(); + Kokkos::deep_copy(ref, h_ref); + Kokkos::fence(); - if (tested_axes == default_axes) { - EXPECT_THROW( - KokkosFFT::Impl::transpose(execution_space(), x, xt, - tested_axes), // xt is identical to x - std::runtime_error); - } else { KokkosFFT::Impl::transpose(execution_space(), x, xt, - tested_axes); // xt is the transpose of x + map); // xt is the transpose of x EXPECT_TRUE(allclose(xt, ref, 1.e-5, 1.e-12)); + + // Inverse (transpose of transpose is identical to the original) + RealView8Dtype _x; + KokkosFFT::Impl::transpose(execution_space(), xt, _x, map_inv); + EXPECT_TRUE(allclose(_x, x, 1.e-5, 1.e-12)); } } } -TYPED_TEST(Transpose, 1DView) { +TYPED_TEST(Transpose1D, 1DView) { + using layout_type = typename TestFixture::layout_type; + + test_transpose_1d_1dview(); +} + +TYPED_TEST(Transpose1D, 2DView) { + using layout_type = typename TestFixture::layout_type; + + test_transpose_1d_2dview(); +} + +TYPED_TEST(Transpose1D, 3DView) { + using layout_type = typename TestFixture::layout_type; + + test_transpose_1d_3dview(); +} + +TYPED_TEST(Transpose1D, 4DView) { + using layout_type = typename TestFixture::layout_type; + + test_transpose_1d_4dview(); +} + +TYPED_TEST(Transpose1D, 5DView) { + using layout_type = typename TestFixture::layout_type; + + test_transpose_1d_5dview(); +} + +TYPED_TEST(Transpose1D, 6DView) { + using layout_type = typename TestFixture::layout_type; + + test_transpose_1d_6dview(); +} + +TYPED_TEST(Transpose1D, 7DView) { using layout_type = typename TestFixture::layout_type; - test_transpose_1d(); + test_transpose_1d_7dview(); } -TYPED_TEST(Transpose, 2DView) { +TYPED_TEST(Transpose1D, 8DView) { using layout_type = typename TestFixture::layout_type; - test_transpose_2d(); + test_transpose_1d_8dview(); +} + +template +void test_transpose_2d_2dview() { + using RealView2Dtype = Kokkos::View; + const int n0 = 3, n1 = 5; + RealView2Dtype x("x", n0, n1), _x("_x", n0, n1), ref("ref", n1, n0); + RealView2Dtype xt_axis01, xt_axis10; // views are allocated internally + + Kokkos::Random_XorShift64_Pool<> random_pool(12345); + Kokkos::fill_random(x, random_pool, 1.0); + + // Transposed views + auto h_x = Kokkos::create_mirror_view(x); + auto h_ref = Kokkos::create_mirror_view(ref); + Kokkos::deep_copy(h_x, x); + + for (int i0 = 0; i0 < h_x.extent(0); i0++) { + for (int i1 = 0; i1 < h_x.extent(1); i1++) { + h_ref(i1, i0) = h_x(i0, i1); + } + } + Kokkos::deep_copy(ref, h_ref); + Kokkos::fence(); + + EXPECT_THROW( + KokkosFFT::Impl::transpose(execution_space(), x, xt_axis01, + axes_type<2>({0, 1})), // xt is identical to x + std::runtime_error); + + KokkosFFT::Impl::transpose(execution_space(), x, xt_axis10, + axes_type<2>({1, 0})); // xt is the transpose of x + EXPECT_TRUE(allclose(xt_axis10, ref, 1.e-5, 1.e-12)); + + // Inverse (transpose of transpose is identical to the original) + KokkosFFT::Impl::transpose(execution_space(), xt_axis10, _x, + axes_type<2>({1, 0})); // xt is the transpose of x + EXPECT_TRUE(allclose(_x, x, 1.e-5, 1.e-12)); +} + +template +void test_transpose_2d_3dview() { + using RealView3Dtype = Kokkos::View; + constexpr int DIM = 3; + const int n0 = 3, n1 = 5, n2 = 8; + RealView3Dtype x("x", n0, n1, n2); + + Kokkos::Random_XorShift64_Pool<> random_pool(12345); + Kokkos::fill_random(x, random_pool, 1.0); + + auto h_x = Kokkos::create_mirror_view(x); + Kokkos::deep_copy(h_x, x); + + // Transposed views + axes_type default_axes({0, 1, 2}); + + for (int axis0 = 0; axis0 < DIM; axis0++) { + for (int axis1 = 0; axis1 < DIM; axis1++) { + if (axis0 == axis1) continue; + KokkosFFT::axis_type<2> axes = {axis0, axis1}; + + auto [map, map_inv] = KokkosFFT::Impl::get_map_axes(x, axes); + axes_type out_extents; + for (int i = 0; i < DIM; i++) { + out_extents.at(i) = x.extent(map.at(i)); + } + auto [_n0, _n1, _n2] = out_extents; + + RealView3Dtype xt; + if (map == default_axes) { + EXPECT_THROW(KokkosFFT::Impl::transpose(execution_space(), x, xt, + map), // xt is identical to x + std::runtime_error); + } else { + // Transposed Views + RealView3Dtype ref("ref", _n0, _n1, _n2); + auto h_ref = Kokkos::create_mirror_view(ref); + // Filling the transposed View + for (int i0 = 0; i0 < h_x.extent(0); i0++) { + for (int i1 = 0; i1 < h_x.extent(1); i1++) { + for (int i2 = 0; i2 < h_x.extent(2); i2++) { + int _i0 = (map[0] == 1) ? i1 : (map[0] == 2) ? i2 : i0; + int _i1 = (map[1] == 0) ? i0 : (map[1] == 2) ? i2 : i1; + int _i2 = (map[2] == 0) ? i0 : (map[2] == 1) ? i1 : i2; + + h_ref(_i0, _i1, _i2) = h_x(i0, i1, i2); + } + } + } + + Kokkos::deep_copy(ref, h_ref); + Kokkos::fence(); + + KokkosFFT::Impl::transpose(execution_space(), x, xt, + map); // xt is the transpose of x + EXPECT_TRUE(allclose(xt, ref, 1.e-5, 1.e-12)); + + // Inverse (transpose of transpose is identical to the original) + RealView3Dtype _x; + KokkosFFT::Impl::transpose(execution_space(), xt, _x, map_inv); + EXPECT_TRUE(allclose(_x, x, 1.e-5, 1.e-12)); + } + } + } +} + +template +void test_transpose_2d_4dview() { + using RealView4Dtype = Kokkos::View; + constexpr int DIM = 4; + const int n0 = 2, n1 = 3, n2 = 4, n3 = 5; + RealView4Dtype x("x", n0, n1, n2, n3); + + Kokkos::Random_XorShift64_Pool<> random_pool(12345); + Kokkos::fill_random(x, random_pool, 1.0); + + auto h_x = Kokkos::create_mirror_view(x); + Kokkos::deep_copy(h_x, x); + + // Transposed views + axes_type default_axes({0, 1, 2, 3}); + + for (int axis0 = 0; axis0 < DIM; axis0++) { + for (int axis1 = 0; axis1 < DIM; axis1++) { + if (axis0 == axis1) continue; + KokkosFFT::axis_type<2> axes = {axis0, axis1}; + + auto [map, map_inv] = KokkosFFT::Impl::get_map_axes(x, axes); + axes_type out_extents; + for (int i = 0; i < DIM; i++) { + out_extents.at(i) = x.extent(map.at(i)); + } + auto [_n0, _n1, _n2, _n3] = out_extents; + + RealView4Dtype xt; + if (map == default_axes) { + EXPECT_THROW(KokkosFFT::Impl::transpose(execution_space(), x, xt, + map), // xt is identical to x + std::runtime_error); + } else { + // Transposed Views + RealView4Dtype ref("ref", _n0, _n1, _n2, _n3); + auto h_ref = Kokkos::create_mirror_view(ref); + // Filling the transposed View + for (int i0 = 0; i0 < h_x.extent(0); i0++) { + for (int i1 = 0; i1 < h_x.extent(1); i1++) { + for (int i2 = 0; i2 < h_x.extent(2); i2++) { + for (int i3 = 0; i3 < h_x.extent(3); i3++) { + int _i0 = (map[0] == 1) ? i1 + : (map[0] == 2) ? i2 + : (map[0] == 3) ? i3 + : i0; + int _i1 = (map[1] == 0) ? i0 + : (map[1] == 2) ? i2 + : (map[1] == 3) ? i3 + : i1; + int _i2 = (map[2] == 0) ? i0 + : (map[2] == 1) ? i1 + : (map[2] == 3) ? i3 + : i2; + int _i3 = (map[3] == 0) ? i0 + : (map[3] == 1) ? i1 + : (map[3] == 2) ? i2 + : i3; + + h_ref(_i0, _i1, _i2, _i3) = h_x(i0, i1, i2, i3); + } + } + } + } + + Kokkos::deep_copy(ref, h_ref); + Kokkos::fence(); + + KokkosFFT::Impl::transpose(execution_space(), x, xt, + map); // xt is the transpose of x + EXPECT_TRUE(allclose(xt, ref, 1.e-5, 1.e-12)); + + // Inverse (transpose of transpose is identical to the original) + RealView4Dtype _x; + KokkosFFT::Impl::transpose(execution_space(), xt, _x, map_inv); + EXPECT_TRUE(allclose(_x, x, 1.e-5, 1.e-12)); + } + } + } +} + +template +void test_transpose_2d_5dview() { + using RealView5Dtype = Kokkos::View; + constexpr int DIM = 5; + const int n0 = 2, n1 = 3, n2 = 4, n3 = 5, n4 = 6; + RealView5Dtype x("x", n0, n1, n2, n3, n4); + + Kokkos::Random_XorShift64_Pool<> random_pool(12345); + Kokkos::fill_random(x, random_pool, 1.0); + + auto h_x = Kokkos::create_mirror_view(x); + Kokkos::deep_copy(h_x, x); + + // Transposed views + axes_type default_axes({0, 1, 2, 3, 4}); + + for (int axis0 = 0; axis0 < DIM; axis0++) { + for (int axis1 = 0; axis1 < DIM; axis1++) { + if (axis0 == axis1) continue; + KokkosFFT::axis_type<2> axes = {axis0, axis1}; + + auto [map, map_inv] = KokkosFFT::Impl::get_map_axes(x, axes); + axes_type out_extents; + for (int i = 0; i < DIM; i++) { + out_extents.at(i) = x.extent(map.at(i)); + } + auto [_n0, _n1, _n2, _n3, _n4] = out_extents; + + RealView5Dtype xt; + if (map == default_axes) { + EXPECT_THROW(KokkosFFT::Impl::transpose(execution_space(), x, xt, + map), // xt is identical to x + std::runtime_error); + } else { + // Transposed Views + RealView5Dtype ref("ref", _n0, _n1, _n2, _n3, _n4); + auto h_ref = Kokkos::create_mirror_view(ref); + // Filling the transposed View + for (int i0 = 0; i0 < h_x.extent(0); i0++) { + for (int i1 = 0; i1 < h_x.extent(1); i1++) { + for (int i2 = 0; i2 < h_x.extent(2); i2++) { + for (int i3 = 0; i3 < h_x.extent(3); i3++) { + for (int i4 = 0; i4 < h_x.extent(4); i4++) { + int _i0 = (map[0] == 1) ? i1 + : (map[0] == 2) ? i2 + : (map[0] == 3) ? i3 + : (map[0] == 4) ? i4 + : i0; + int _i1 = (map[1] == 0) ? i0 + : (map[1] == 2) ? i2 + : (map[1] == 3) ? i3 + : (map[1] == 4) ? i4 + : i1; + int _i2 = (map[2] == 0) ? i0 + : (map[2] == 1) ? i1 + : (map[2] == 3) ? i3 + : (map[2] == 4) ? i4 + : i2; + int _i3 = (map[3] == 0) ? i0 + : (map[3] == 1) ? i1 + : (map[3] == 2) ? i2 + : (map[3] == 4) ? i4 + : i3; + int _i4 = (map[4] == 0) ? i0 + : (map[4] == 1) ? i1 + : (map[4] == 2) ? i2 + : (map[4] == 3) ? i3 + : i4; + h_ref(_i0, _i1, _i2, _i3, _i4) = h_x(i0, i1, i2, i3, i4); + } + } + } + } + } + + Kokkos::deep_copy(ref, h_ref); + Kokkos::fence(); + + KokkosFFT::Impl::transpose(execution_space(), x, xt, + map); // xt is the transpose of x + EXPECT_TRUE(allclose(xt, ref, 1.e-5, 1.e-12)); + + // Inverse (transpose of transpose is identical to the original) + RealView5Dtype _x; + KokkosFFT::Impl::transpose(execution_space(), xt, _x, map_inv); + EXPECT_TRUE(allclose(_x, x, 1.e-5, 1.e-12)); + } + } + } +} + +template +void test_transpose_2d_6dview() { + using RealView6Dtype = + Kokkos::View; + constexpr int DIM = 6; + const int n0 = 2, n1 = 3, n2 = 4, n3 = 5, n4 = 6, n5 = 7; + RealView6Dtype x("x", n0, n1, n2, n3, n4, n5); + + Kokkos::Random_XorShift64_Pool<> random_pool(12345); + Kokkos::fill_random(x, random_pool, 1.0); + + auto h_x = Kokkos::create_mirror_view(x); + Kokkos::deep_copy(h_x, x); + + // Transposed views + axes_type default_axes({0, 1, 2, 3, 4, 5}); + + for (int axis0 = 0; axis0 < DIM; axis0++) { + for (int axis1 = 0; axis1 < DIM; axis1++) { + if (axis0 == axis1) continue; + KokkosFFT::axis_type<2> axes = {axis0, axis1}; + + auto [map, map_inv] = KokkosFFT::Impl::get_map_axes(x, axes); + axes_type out_extents; + for (int i = 0; i < DIM; i++) { + out_extents.at(i) = x.extent(map.at(i)); + } + auto [_n0, _n1, _n2, _n3, _n4, _n5] = out_extents; + + RealView6Dtype xt; + if (map == default_axes) { + EXPECT_THROW(KokkosFFT::Impl::transpose(execution_space(), x, xt, + map), // xt is identical to x + std::runtime_error); + } else { + // Transposed Views + RealView6Dtype ref("ref", _n0, _n1, _n2, _n3, _n4, _n5); + auto h_ref = Kokkos::create_mirror_view(ref); + // Filling the transposed View + for (int i0 = 0; i0 < h_x.extent(0); i0++) { + for (int i1 = 0; i1 < h_x.extent(1); i1++) { + for (int i2 = 0; i2 < h_x.extent(2); i2++) { + for (int i3 = 0; i3 < h_x.extent(3); i3++) { + for (int i4 = 0; i4 < h_x.extent(4); i4++) { + for (int i5 = 0; i5 < h_x.extent(5); i5++) { + int _i0 = (map[0] == 1) ? i1 + : (map[0] == 2) ? i2 + : (map[0] == 3) ? i3 + : (map[0] == 4) ? i4 + : (map[0] == 5) ? i5 + : i0; + int _i1 = (map[1] == 0) ? i0 + : (map[1] == 2) ? i2 + : (map[1] == 3) ? i3 + : (map[1] == 4) ? i4 + : (map[1] == 5) ? i5 + : i1; + int _i2 = (map[2] == 0) ? i0 + : (map[2] == 1) ? i1 + : (map[2] == 3) ? i3 + : (map[2] == 4) ? i4 + : (map[2] == 5) ? i5 + : i2; + int _i3 = (map[3] == 0) ? i0 + : (map[3] == 1) ? i1 + : (map[3] == 2) ? i2 + : (map[3] == 4) ? i4 + : (map[3] == 5) ? i5 + : i3; + int _i4 = (map[4] == 0) ? i0 + : (map[4] == 1) ? i1 + : (map[4] == 2) ? i2 + : (map[4] == 3) ? i3 + : (map[4] == 5) ? i5 + : i4; + int _i5 = (map[5] == 0) ? i0 + : (map[5] == 1) ? i1 + : (map[5] == 2) ? i2 + : (map[5] == 3) ? i3 + : (map[5] == 4) ? i4 + : i5; + h_ref(_i0, _i1, _i2, _i3, _i4, _i5) = + h_x(i0, i1, i2, i3, i4, i5); + } + } + } + } + } + } + + Kokkos::deep_copy(ref, h_ref); + Kokkos::fence(); + + KokkosFFT::Impl::transpose(execution_space(), x, xt, + map); // xt is the transpose of x + EXPECT_TRUE(allclose(xt, ref, 1.e-5, 1.e-12)); + + // Inverse (transpose of transpose is identical to the original) + RealView6Dtype _x; + KokkosFFT::Impl::transpose(execution_space(), xt, _x, map_inv); + EXPECT_TRUE(allclose(_x, x, 1.e-5, 1.e-12)); + } + } + } +} + +template +void test_transpose_2d_7dview() { + using RealView7Dtype = + Kokkos::View; + constexpr int DIM = 7; + const int n0 = 2, n1 = 3, n2 = 4, n3 = 5, n4 = 6, n5 = 7, n6 = 8; + RealView7Dtype x("x", n0, n1, n2, n3, n4, n5, n6); + + Kokkos::Random_XorShift64_Pool<> random_pool(12345); + Kokkos::fill_random(x, random_pool, 1.0); + + auto h_x = Kokkos::create_mirror_view(x); + Kokkos::deep_copy(h_x, x); + + // Transposed views + axes_type default_axes({0, 1, 2, 3, 4, 5, 6}); + + for (int axis0 = 0; axis0 < DIM; axis0++) { + for (int axis1 = 0; axis1 < DIM; axis1++) { + if (axis0 == axis1) continue; + KokkosFFT::axis_type<2> axes = {axis0, axis1}; + + auto [map, map_inv] = KokkosFFT::Impl::get_map_axes(x, axes); + axes_type out_extents; + for (int i = 0; i < DIM; i++) { + out_extents.at(i) = x.extent(map.at(i)); + } + auto [_n0, _n1, _n2, _n3, _n4, _n5, _n6] = out_extents; + + RealView7Dtype xt; + if (map == default_axes) { + EXPECT_THROW(KokkosFFT::Impl::transpose(execution_space(), x, xt, + map), // xt is identical to x + std::runtime_error); + } else { + // Transposed Views + RealView7Dtype ref("ref", _n0, _n1, _n2, _n3, _n4, _n5, _n6); + auto h_ref = Kokkos::create_mirror_view(ref); + // Filling the transposed View + for (int i0 = 0; i0 < h_x.extent(0); i0++) { + for (int i1 = 0; i1 < h_x.extent(1); i1++) { + for (int i2 = 0; i2 < h_x.extent(2); i2++) { + for (int i3 = 0; i3 < h_x.extent(3); i3++) { + for (int i4 = 0; i4 < h_x.extent(4); i4++) { + for (int i5 = 0; i5 < h_x.extent(5); i5++) { + for (int i6 = 0; i6 < h_x.extent(6); i6++) { + int _i0 = (map[0] == 1) ? i1 + : (map[0] == 2) ? i2 + : (map[0] == 3) ? i3 + : (map[0] == 4) ? i4 + : (map[0] == 5) ? i5 + : (map[0] == 6) ? i6 + : i0; + int _i1 = (map[1] == 0) ? i0 + : (map[1] == 2) ? i2 + : (map[1] == 3) ? i3 + : (map[1] == 4) ? i4 + : (map[1] == 5) ? i5 + : (map[1] == 6) ? i6 + : i1; + int _i2 = (map[2] == 0) ? i0 + : (map[2] == 1) ? i1 + : (map[2] == 3) ? i3 + : (map[2] == 4) ? i4 + : (map[2] == 5) ? i5 + : (map[2] == 6) ? i6 + : i2; + int _i3 = (map[3] == 0) ? i0 + : (map[3] == 1) ? i1 + : (map[3] == 2) ? i2 + : (map[3] == 4) ? i4 + : (map[3] == 5) ? i5 + : (map[3] == 6) ? i6 + : i3; + int _i4 = (map[4] == 0) ? i0 + : (map[4] == 1) ? i1 + : (map[4] == 2) ? i2 + : (map[4] == 3) ? i3 + : (map[4] == 5) ? i5 + : (map[4] == 6) ? i6 + : i4; + int _i5 = (map[5] == 0) ? i0 + : (map[5] == 1) ? i1 + : (map[5] == 2) ? i2 + : (map[5] == 3) ? i3 + : (map[5] == 4) ? i4 + : (map[5] == 6) ? i6 + : i5; + int _i6 = (map[6] == 0) ? i0 + : (map[6] == 1) ? i1 + : (map[6] == 2) ? i2 + : (map[6] == 3) ? i3 + : (map[6] == 4) ? i4 + : (map[6] == 5) ? i5 + : i6; + h_ref(_i0, _i1, _i2, _i3, _i4, _i5, _i6) = + h_x(i0, i1, i2, i3, i4, i5, i6); + } + } + } + } + } + } + } + + Kokkos::deep_copy(ref, h_ref); + Kokkos::fence(); + + KokkosFFT::Impl::transpose(execution_space(), x, xt, + map); // xt is the transpose of x + EXPECT_TRUE(allclose(xt, ref, 1.e-5, 1.e-12)); + + // Inverse (transpose of transpose is identical to the original) + RealView7Dtype _x; + KokkosFFT::Impl::transpose(execution_space(), xt, _x, map_inv); + EXPECT_TRUE(allclose(_x, x, 1.e-5, 1.e-12)); + } + } + } +} + +template +void test_transpose_2d_8dview() { + using RealView8Dtype = + Kokkos::View; + constexpr int DIM = 8; + const int n0 = 2, n1 = 3, n2 = 4, n3 = 5, n4 = 6, n5 = 7, n6 = 8, n7 = 9; + RealView8Dtype x("x", n0, n1, n2, n3, n4, n5, n6, n7); + + Kokkos::Random_XorShift64_Pool<> random_pool(12345); + Kokkos::fill_random(x, random_pool, 1.0); + + auto h_x = Kokkos::create_mirror_view(x); + Kokkos::deep_copy(h_x, x); + + // Transposed views + axes_type default_axes({0, 1, 2, 3, 4, 5, 6, 7}); + + for (int axis0 = 0; axis0 < DIM; axis0++) { + for (int axis1 = 0; axis1 < DIM; axis1++) { + if (axis0 == axis1) continue; + KokkosFFT::axis_type<2> axes = {axis0, axis1}; + + auto [map, map_inv] = KokkosFFT::Impl::get_map_axes(x, axes); + axes_type out_extents; + for (int i = 0; i < DIM; i++) { + out_extents.at(i) = x.extent(map.at(i)); + } + auto [_n0, _n1, _n2, _n3, _n4, _n5, _n6, _n7] = out_extents; + + RealView8Dtype xt; + if (map == default_axes) { + EXPECT_THROW(KokkosFFT::Impl::transpose(execution_space(), x, xt, + map), // xt is identical to x + std::runtime_error); + } else { + // Transposed Views + RealView8Dtype ref("ref", _n0, _n1, _n2, _n3, _n4, _n5, _n6, _n7); + auto h_ref = Kokkos::create_mirror_view(ref); + // Filling the transposed View + for (int i0 = 0; i0 < h_x.extent(0); i0++) { + for (int i1 = 0; i1 < h_x.extent(1); i1++) { + for (int i2 = 0; i2 < h_x.extent(2); i2++) { + for (int i3 = 0; i3 < h_x.extent(3); i3++) { + for (int i4 = 0; i4 < h_x.extent(4); i4++) { + for (int i5 = 0; i5 < h_x.extent(5); i5++) { + for (int i6 = 0; i6 < h_x.extent(6); i6++) { + for (int i7 = 0; i7 < h_x.extent(7); i7++) { + int _i0 = (map[0] == 1) ? i1 + : (map[0] == 2) ? i2 + : (map[0] == 3) ? i3 + : (map[0] == 4) ? i4 + : (map[0] == 5) ? i5 + : (map[0] == 6) ? i6 + : (map[0] == 7) ? i7 + : i0; + int _i1 = (map[1] == 0) ? i0 + : (map[1] == 2) ? i2 + : (map[1] == 3) ? i3 + : (map[1] == 4) ? i4 + : (map[1] == 5) ? i5 + : (map[1] == 6) ? i6 + : (map[1] == 7) ? i7 + : i1; + int _i2 = (map[2] == 0) ? i0 + : (map[2] == 1) ? i1 + : (map[2] == 3) ? i3 + : (map[2] == 4) ? i4 + : (map[2] == 5) ? i5 + : (map[2] == 6) ? i6 + : (map[2] == 7) ? i7 + : i2; + int _i3 = (map[3] == 0) ? i0 + : (map[3] == 1) ? i1 + : (map[3] == 2) ? i2 + : (map[3] == 4) ? i4 + : (map[3] == 5) ? i5 + : (map[3] == 6) ? i6 + : (map[3] == 7) ? i7 + : i3; + int _i4 = (map[4] == 0) ? i0 + : (map[4] == 1) ? i1 + : (map[4] == 2) ? i2 + : (map[4] == 3) ? i3 + : (map[4] == 5) ? i5 + : (map[4] == 6) ? i6 + : (map[4] == 7) ? i7 + : i4; + int _i5 = (map[5] == 0) ? i0 + : (map[5] == 1) ? i1 + : (map[5] == 2) ? i2 + : (map[5] == 3) ? i3 + : (map[5] == 4) ? i4 + : (map[5] == 6) ? i6 + : (map[5] == 7) ? i7 + : i5; + int _i6 = (map[6] == 0) ? i0 + : (map[6] == 1) ? i1 + : (map[6] == 2) ? i2 + : (map[6] == 3) ? i3 + : (map[6] == 4) ? i4 + : (map[6] == 5) ? i5 + : (map[6] == 7) ? i7 + : i6; + int _i7 = (map[7] == 0) ? i0 + : (map[7] == 1) ? i1 + : (map[7] == 2) ? i2 + : (map[7] == 3) ? i3 + : (map[7] == 4) ? i4 + : (map[7] == 5) ? i5 + : (map[7] == 6) ? i6 + : i7; + h_ref(_i0, _i1, _i2, _i3, _i4, _i5, _i6, _i7) = + h_x(i0, i1, i2, i3, i4, i5, i6, i7); + } + } + } + } + } + } + } + } + + Kokkos::deep_copy(ref, h_ref); + Kokkos::fence(); + + KokkosFFT::Impl::transpose(execution_space(), x, xt, + map); // xt is the transpose of x + EXPECT_TRUE(allclose(xt, ref, 1.e-5, 1.e-12)); + + // Inverse (transpose of transpose is identical to the original) + RealView8Dtype _x; + KokkosFFT::Impl::transpose(execution_space(), xt, _x, map_inv); + EXPECT_TRUE(allclose(_x, x, 1.e-5, 1.e-12)); + } + } + } +} + +TYPED_TEST(Transpose2D, 2DView) { + using layout_type = typename TestFixture::layout_type; + + test_transpose_2d_2dview(); +} + +TYPED_TEST(Transpose2D, 3DView) { + using layout_type = typename TestFixture::layout_type; + + test_transpose_2d_3dview(); +} + +TYPED_TEST(Transpose2D, 4DView) { + using layout_type = typename TestFixture::layout_type; + + test_transpose_2d_4dview(); +} + +TYPED_TEST(Transpose2D, 5DView) { + using layout_type = typename TestFixture::layout_type; + + test_transpose_2d_5dview(); +} + +TYPED_TEST(Transpose2D, 6DView) { + using layout_type = typename TestFixture::layout_type; + + test_transpose_2d_6dview(); +} + +TYPED_TEST(Transpose2D, 7DView) { + using layout_type = typename TestFixture::layout_type; + + test_transpose_2d_7dview(); +} + +TYPED_TEST(Transpose2D, 8DView) { + using layout_type = typename TestFixture::layout_type; + + test_transpose_2d_8dview(); +} + +template +void test_transpose_3d_3dview() { + using RealView3Dtype = Kokkos::View; + const int n0 = 3, n1 = 5, n2 = 8; + RealView3Dtype x("x", n0, n1, n2); + RealView3Dtype xt_axis012, xt_axis021, xt_axis102, xt_axis120, xt_axis201, + xt_axis210; // views are allocated internally + RealView3Dtype ref_axis021("ref_axis021", n0, n2, n1), + ref_axis102("ref_axis102", n1, n0, n2); + RealView3Dtype ref_axis120("ref_axis120", n1, n2, n0), + ref_axis201("ref_axis201", n2, n0, n1), + ref_axis210("ref_axis210", n2, n1, n0); + + Kokkos::Random_XorShift64_Pool<> random_pool(12345); + Kokkos::fill_random(x, random_pool, 1.0); + + // Transposed views + auto h_x = Kokkos::create_mirror_view(x); + auto h_ref_axis021 = Kokkos::create_mirror_view(ref_axis021); + auto h_ref_axis102 = Kokkos::create_mirror_view(ref_axis102); + auto h_ref_axis120 = Kokkos::create_mirror_view(ref_axis120); + auto h_ref_axis201 = Kokkos::create_mirror_view(ref_axis201); + auto h_ref_axis210 = Kokkos::create_mirror_view(ref_axis210); + + Kokkos::deep_copy(h_x, x); + + for (int i0 = 0; i0 < h_x.extent(0); i0++) { + for (int i1 = 0; i1 < h_x.extent(1); i1++) { + for (int i2 = 0; i2 < h_x.extent(2); i2++) { + h_ref_axis021(i0, i2, i1) = h_x(i0, i1, i2); + h_ref_axis102(i1, i0, i2) = h_x(i0, i1, i2); + h_ref_axis120(i1, i2, i0) = h_x(i0, i1, i2); + h_ref_axis201(i2, i0, i1) = h_x(i0, i1, i2); + h_ref_axis210(i2, i1, i0) = h_x(i0, i1, i2); + } + } + } + + Kokkos::deep_copy(ref_axis021, h_ref_axis021); + Kokkos::deep_copy(ref_axis102, h_ref_axis102); + Kokkos::deep_copy(ref_axis120, h_ref_axis120); + Kokkos::deep_copy(ref_axis201, h_ref_axis201); + Kokkos::deep_copy(ref_axis210, h_ref_axis210); + + Kokkos::fence(); + + EXPECT_THROW(KokkosFFT::Impl::transpose( + execution_space(), x, xt_axis012, + axes_type<3>({0, 1, 2})), // xt is identical to x + std::runtime_error); + + KokkosFFT::Impl::transpose( + execution_space(), x, xt_axis021, + axes_type<3>({0, 2, 1})); // xt is the transpose of x + EXPECT_TRUE(allclose(xt_axis021, ref_axis021, 1.e-5, 1.e-12)); + + KokkosFFT::Impl::transpose( + execution_space(), x, xt_axis102, + axes_type<3>({1, 0, 2})); // xt is the transpose of x + EXPECT_TRUE(allclose(xt_axis102, ref_axis102, 1.e-5, 1.e-12)); + + KokkosFFT::Impl::transpose( + execution_space(), x, xt_axis120, + axes_type<3>({1, 2, 0})); // xt is the transpose of x + EXPECT_TRUE(allclose(xt_axis120, ref_axis120, 1.e-5, 1.e-12)); + + KokkosFFT::Impl::transpose( + execution_space(), x, xt_axis201, + axes_type<3>({2, 0, 1})); // xt is the transpose of x + EXPECT_TRUE(allclose(xt_axis201, ref_axis201, 1.e-5, 1.e-12)); + + KokkosFFT::Impl::transpose( + execution_space(), x, xt_axis210, + axes_type<3>({2, 1, 0})); // xt is the transpose of x + EXPECT_TRUE(allclose(xt_axis210, ref_axis210, 1.e-5, 1.e-12)); +} + +template +void test_transpose_3d_4dview() { + using RealView4Dtype = Kokkos::View; + constexpr int DIM = 4; + const int n0 = 2, n1 = 3, n2 = 4, n3 = 5; + RealView4Dtype x("x", n0, n1, n2, n3); + + Kokkos::Random_XorShift64_Pool<> random_pool(12345); + Kokkos::fill_random(x, random_pool, 1.0); + + auto h_x = Kokkos::create_mirror_view(x); + Kokkos::deep_copy(h_x, x); + + // Transposed views + axes_type default_axes({0, 1, 2, 3}); + + for (int axis0 = 0; axis0 < DIM; axis0++) { + for (int axis1 = 0; axis1 < DIM; axis1++) { + for (int axis2 = 0; axis2 < DIM; axis2++) { + if (axis0 == axis1 || axis0 == axis2 || axis1 == axis2) continue; + KokkosFFT::axis_type<3> axes = {axis0, axis1, axis2}; + + auto [map, map_inv] = KokkosFFT::Impl::get_map_axes(x, axes); + axes_type out_extents; + for (int i = 0; i < DIM; i++) { + out_extents.at(i) = x.extent(map.at(i)); + } + auto [_n0, _n1, _n2, _n3] = out_extents; + + RealView4Dtype xt; + if (map == default_axes) { + EXPECT_THROW(KokkosFFT::Impl::transpose(execution_space(), x, xt, + map), // xt is identical to x + std::runtime_error); + } else { + // Transposed Views + RealView4Dtype ref("ref", _n0, _n1, _n2, _n3); + auto h_ref = Kokkos::create_mirror_view(ref); + // Filling the transposed View + for (int i0 = 0; i0 < h_x.extent(0); i0++) { + for (int i1 = 0; i1 < h_x.extent(1); i1++) { + for (int i2 = 0; i2 < h_x.extent(2); i2++) { + for (int i3 = 0; i3 < h_x.extent(3); i3++) { + int _i0 = (map[0] == 1) ? i1 + : (map[0] == 2) ? i2 + : (map[0] == 3) ? i3 + : i0; + int _i1 = (map[1] == 0) ? i0 + : (map[1] == 2) ? i2 + : (map[1] == 3) ? i3 + : i1; + int _i2 = (map[2] == 0) ? i0 + : (map[2] == 1) ? i1 + : (map[2] == 3) ? i3 + : i2; + int _i3 = (map[3] == 0) ? i0 + : (map[3] == 1) ? i1 + : (map[3] == 2) ? i2 + : i3; + + h_ref(_i0, _i1, _i2, _i3) = h_x(i0, i1, i2, i3); + } + } + } + } + + Kokkos::deep_copy(ref, h_ref); + Kokkos::fence(); + + KokkosFFT::Impl::transpose(execution_space(), x, xt, + map); // xt is the transpose of x + EXPECT_TRUE(allclose(xt, ref, 1.e-5, 1.e-12)); + + // Inverse (transpose of transpose is identical to the original) + RealView4Dtype _x; + KokkosFFT::Impl::transpose(execution_space(), xt, _x, map_inv); + EXPECT_TRUE(allclose(_x, x, 1.e-5, 1.e-12)); + } + } + } + } +} + +template +void test_transpose_3d_5dview() { + using RealView5Dtype = Kokkos::View; + constexpr int DIM = 5; + const int n0 = 2, n1 = 3, n2 = 4, n3 = 5, n4 = 6; + RealView5Dtype x("x", n0, n1, n2, n3, n4); + + Kokkos::Random_XorShift64_Pool<> random_pool(12345); + Kokkos::fill_random(x, random_pool, 1.0); + + auto h_x = Kokkos::create_mirror_view(x); + Kokkos::deep_copy(h_x, x); + + // Transposed views + axes_type default_axes({0, 1, 2, 3, 4}); + + for (int axis0 = 0; axis0 < DIM; axis0++) { + for (int axis1 = 0; axis1 < DIM; axis1++) { + for (int axis2 = 0; axis2 < DIM; axis2++) { + if (axis0 == axis1 || axis0 == axis2 || axis1 == axis2) continue; + + KokkosFFT::axis_type<3> axes = {axis0, axis1, axis2}; + + auto [map, map_inv] = KokkosFFT::Impl::get_map_axes(x, axes); + axes_type out_extents; + for (int i = 0; i < DIM; i++) { + out_extents.at(i) = x.extent(map.at(i)); + } + auto [_n0, _n1, _n2, _n3, _n4] = out_extents; + + RealView5Dtype xt; + if (map == default_axes) { + EXPECT_THROW(KokkosFFT::Impl::transpose(execution_space(), x, xt, + map), // xt is identical to x + std::runtime_error); + } else { + // Transposed Views + RealView5Dtype ref("ref", _n0, _n1, _n2, _n3, _n4); + auto h_ref = Kokkos::create_mirror_view(ref); + // Filling the transposed View + for (int i0 = 0; i0 < h_x.extent(0); i0++) { + for (int i1 = 0; i1 < h_x.extent(1); i1++) { + for (int i2 = 0; i2 < h_x.extent(2); i2++) { + for (int i3 = 0; i3 < h_x.extent(3); i3++) { + for (int i4 = 0; i4 < h_x.extent(4); i4++) { + int _i0 = (map[0] == 1) ? i1 + : (map[0] == 2) ? i2 + : (map[0] == 3) ? i3 + : (map[0] == 4) ? i4 + : i0; + int _i1 = (map[1] == 0) ? i0 + : (map[1] == 2) ? i2 + : (map[1] == 3) ? i3 + : (map[1] == 4) ? i4 + : i1; + int _i2 = (map[2] == 0) ? i0 + : (map[2] == 1) ? i1 + : (map[2] == 3) ? i3 + : (map[2] == 4) ? i4 + : i2; + int _i3 = (map[3] == 0) ? i0 + : (map[3] == 1) ? i1 + : (map[3] == 2) ? i2 + : (map[3] == 4) ? i4 + : i3; + int _i4 = (map[4] == 0) ? i0 + : (map[4] == 1) ? i1 + : (map[4] == 2) ? i2 + : (map[4] == 3) ? i3 + : i4; + h_ref(_i0, _i1, _i2, _i3, _i4) = h_x(i0, i1, i2, i3, i4); + } + } + } + } + } + + Kokkos::deep_copy(ref, h_ref); + Kokkos::fence(); + + KokkosFFT::Impl::transpose(execution_space(), x, xt, + map); // xt is the transpose of x + EXPECT_TRUE(allclose(xt, ref, 1.e-5, 1.e-12)); + + // Inverse (transpose of transpose is identical to the original) + RealView5Dtype _x; + KokkosFFT::Impl::transpose(execution_space(), xt, _x, map_inv); + EXPECT_TRUE(allclose(_x, x, 1.e-5, 1.e-12)); + } + } + } + } +} + +template +void test_transpose_3d_6dview() { + using RealView6Dtype = + Kokkos::View; + constexpr int DIM = 6; + const int n0 = 2, n1 = 3, n2 = 4, n3 = 5, n4 = 6, n5 = 7; + RealView6Dtype x("x", n0, n1, n2, n3, n4, n5); + + Kokkos::Random_XorShift64_Pool<> random_pool(12345); + Kokkos::fill_random(x, random_pool, 1.0); + + auto h_x = Kokkos::create_mirror_view(x); + Kokkos::deep_copy(h_x, x); + + // Transposed views + axes_type default_axes({0, 1, 2, 3, 4, 5}); + + for (int axis0 = 0; axis0 < DIM; axis0++) { + for (int axis1 = 0; axis1 < DIM; axis1++) { + for (int axis2 = 0; axis2 < DIM; axis2++) { + if (axis0 == axis1 || axis0 == axis2 || axis1 == axis2) continue; + + KokkosFFT::axis_type<3> axes = {axis0, axis1, axis2}; + + auto [map, map_inv] = KokkosFFT::Impl::get_map_axes(x, axes); + axes_type out_extents; + for (int i = 0; i < DIM; i++) { + out_extents.at(i) = x.extent(map.at(i)); + } + auto [_n0, _n1, _n2, _n3, _n4, _n5] = out_extents; + + RealView6Dtype xt; + if (map == default_axes) { + EXPECT_THROW(KokkosFFT::Impl::transpose(execution_space(), x, xt, + map), // xt is identical to x + std::runtime_error); + } else { + // Transposed Views + RealView6Dtype ref("ref", _n0, _n1, _n2, _n3, _n4, _n5); + auto h_ref = Kokkos::create_mirror_view(ref); + // Filling the transposed View + for (int i0 = 0; i0 < h_x.extent(0); i0++) { + for (int i1 = 0; i1 < h_x.extent(1); i1++) { + for (int i2 = 0; i2 < h_x.extent(2); i2++) { + for (int i3 = 0; i3 < h_x.extent(3); i3++) { + for (int i4 = 0; i4 < h_x.extent(4); i4++) { + for (int i5 = 0; i5 < h_x.extent(5); i5++) { + int _i0 = (map[0] == 1) ? i1 + : (map[0] == 2) ? i2 + : (map[0] == 3) ? i3 + : (map[0] == 4) ? i4 + : (map[0] == 5) ? i5 + : i0; + int _i1 = (map[1] == 0) ? i0 + : (map[1] == 2) ? i2 + : (map[1] == 3) ? i3 + : (map[1] == 4) ? i4 + : (map[1] == 5) ? i5 + : i1; + int _i2 = (map[2] == 0) ? i0 + : (map[2] == 1) ? i1 + : (map[2] == 3) ? i3 + : (map[2] == 4) ? i4 + : (map[2] == 5) ? i5 + : i2; + int _i3 = (map[3] == 0) ? i0 + : (map[3] == 1) ? i1 + : (map[3] == 2) ? i2 + : (map[3] == 4) ? i4 + : (map[3] == 5) ? i5 + : i3; + int _i4 = (map[4] == 0) ? i0 + : (map[4] == 1) ? i1 + : (map[4] == 2) ? i2 + : (map[4] == 3) ? i3 + : (map[4] == 5) ? i5 + : i4; + int _i5 = (map[5] == 0) ? i0 + : (map[5] == 1) ? i1 + : (map[5] == 2) ? i2 + : (map[5] == 3) ? i3 + : (map[5] == 4) ? i4 + : i5; + h_ref(_i0, _i1, _i2, _i3, _i4, _i5) = + h_x(i0, i1, i2, i3, i4, i5); + } + } + } + } + } + } + + Kokkos::deep_copy(ref, h_ref); + Kokkos::fence(); + + KokkosFFT::Impl::transpose(execution_space(), x, xt, + map); // xt is the transpose of x + EXPECT_TRUE(allclose(xt, ref, 1.e-5, 1.e-12)); + + // Inverse (transpose of transpose is identical to the original) + RealView6Dtype _x; + KokkosFFT::Impl::transpose(execution_space(), xt, _x, map_inv); + EXPECT_TRUE(allclose(_x, x, 1.e-5, 1.e-12)); + } + } + } + } +} + +template +void test_transpose_3d_7dview() { + using RealView7Dtype = + Kokkos::View; + constexpr int DIM = 7; + const int n0 = 2, n1 = 3, n2 = 4, n3 = 5, n4 = 6, n5 = 7, n6 = 8; + RealView7Dtype x("x", n0, n1, n2, n3, n4, n5, n6); + + Kokkos::Random_XorShift64_Pool<> random_pool(12345); + Kokkos::fill_random(x, random_pool, 1.0); + + auto h_x = Kokkos::create_mirror_view(x); + Kokkos::deep_copy(h_x, x); + + // Transposed views + axes_type default_axes({0, 1, 2, 3, 4, 5, 6}); + + for (int axis0 = 0; axis0 < DIM; axis0++) { + for (int axis1 = 0; axis1 < DIM; axis1++) { + for (int axis2 = 0; axis2 < DIM; axis2++) { + if (axis0 == axis1 || axis0 == axis2 || axis1 == axis2) continue; + + KokkosFFT::axis_type<3> axes = {axis0, axis1, axis2}; + + auto [map, map_inv] = KokkosFFT::Impl::get_map_axes(x, axes); + axes_type out_extents; + for (int i = 0; i < DIM; i++) { + out_extents.at(i) = x.extent(map.at(i)); + } + auto [_n0, _n1, _n2, _n3, _n4, _n5, _n6] = out_extents; + + RealView7Dtype xt; + if (map == default_axes) { + EXPECT_THROW(KokkosFFT::Impl::transpose(execution_space(), x, xt, + map), // xt is identical to x + std::runtime_error); + } else { + // Transposed Views + RealView7Dtype ref("ref", _n0, _n1, _n2, _n3, _n4, _n5, _n6); + auto h_ref = Kokkos::create_mirror_view(ref); + // Filling the transposed View + for (int i0 = 0; i0 < h_x.extent(0); i0++) { + for (int i1 = 0; i1 < h_x.extent(1); i1++) { + for (int i2 = 0; i2 < h_x.extent(2); i2++) { + for (int i3 = 0; i3 < h_x.extent(3); i3++) { + for (int i4 = 0; i4 < h_x.extent(4); i4++) { + for (int i5 = 0; i5 < h_x.extent(5); i5++) { + for (int i6 = 0; i6 < h_x.extent(6); i6++) { + int _i0 = (map[0] == 1) ? i1 + : (map[0] == 2) ? i2 + : (map[0] == 3) ? i3 + : (map[0] == 4) ? i4 + : (map[0] == 5) ? i5 + : (map[0] == 6) ? i6 + : i0; + int _i1 = (map[1] == 0) ? i0 + : (map[1] == 2) ? i2 + : (map[1] == 3) ? i3 + : (map[1] == 4) ? i4 + : (map[1] == 5) ? i5 + : (map[1] == 6) ? i6 + : i1; + int _i2 = (map[2] == 0) ? i0 + : (map[2] == 1) ? i1 + : (map[2] == 3) ? i3 + : (map[2] == 4) ? i4 + : (map[2] == 5) ? i5 + : (map[2] == 6) ? i6 + : i2; + int _i3 = (map[3] == 0) ? i0 + : (map[3] == 1) ? i1 + : (map[3] == 2) ? i2 + : (map[3] == 4) ? i4 + : (map[3] == 5) ? i5 + : (map[3] == 6) ? i6 + : i3; + int _i4 = (map[4] == 0) ? i0 + : (map[4] == 1) ? i1 + : (map[4] == 2) ? i2 + : (map[4] == 3) ? i3 + : (map[4] == 5) ? i5 + : (map[4] == 6) ? i6 + : i4; + int _i5 = (map[5] == 0) ? i0 + : (map[5] == 1) ? i1 + : (map[5] == 2) ? i2 + : (map[5] == 3) ? i3 + : (map[5] == 4) ? i4 + : (map[5] == 6) ? i6 + : i5; + int _i6 = (map[6] == 0) ? i0 + : (map[6] == 1) ? i1 + : (map[6] == 2) ? i2 + : (map[6] == 3) ? i3 + : (map[6] == 4) ? i4 + : (map[6] == 5) ? i5 + : i6; + h_ref(_i0, _i1, _i2, _i3, _i4, _i5, _i6) = + h_x(i0, i1, i2, i3, i4, i5, i6); + } + } + } + } + } + } + } + + Kokkos::deep_copy(ref, h_ref); + Kokkos::fence(); + + KokkosFFT::Impl::transpose(execution_space(), x, xt, + map); // xt is the transpose of x + EXPECT_TRUE(allclose(xt, ref, 1.e-5, 1.e-12)); + + // Inverse (transpose of transpose is identical to the original) + RealView7Dtype _x; + KokkosFFT::Impl::transpose(execution_space(), xt, _x, map_inv); + EXPECT_TRUE(allclose(_x, x, 1.e-5, 1.e-12)); + } + } + } + } +} + +template +void test_transpose_3d_8dview() { + using RealView8Dtype = + Kokkos::View; + constexpr int DIM = 8; + const int n0 = 2, n1 = 3, n2 = 4, n3 = 5, n4 = 6, n5 = 7, n6 = 8, n7 = 9; + RealView8Dtype x("x", n0, n1, n2, n3, n4, n5, n6, n7); + + Kokkos::Random_XorShift64_Pool<> random_pool(12345); + Kokkos::fill_random(x, random_pool, 1.0); + + auto h_x = Kokkos::create_mirror_view(x); + Kokkos::deep_copy(h_x, x); + + // Transposed views + axes_type default_axes({0, 1, 2, 3, 4, 5, 6, 7}); + + for (int axis0 = 0; axis0 < DIM; axis0++) { + for (int axis1 = 0; axis1 < DIM; axis1++) { + for (int axis2 = 0; axis2 < DIM; axis2++) { + if (axis0 == axis1 || axis0 == axis2 || axis1 == axis2) continue; + + KokkosFFT::axis_type<3> axes = {axis0, axis1, axis2}; + + auto [map, map_inv] = KokkosFFT::Impl::get_map_axes(x, axes); + axes_type out_extents; + for (int i = 0; i < DIM; i++) { + out_extents.at(i) = x.extent(map.at(i)); + } + auto [_n0, _n1, _n2, _n3, _n4, _n5, _n6, _n7] = out_extents; + + RealView8Dtype xt; + if (map == default_axes) { + EXPECT_THROW(KokkosFFT::Impl::transpose(execution_space(), x, xt, + map), // xt is identical to x + std::runtime_error); + } else { + // Transposed Views + RealView8Dtype ref("ref", _n0, _n1, _n2, _n3, _n4, _n5, _n6, _n7); + auto h_ref = Kokkos::create_mirror_view(ref); + // Filling the transposed View + for (int i0 = 0; i0 < h_x.extent(0); i0++) { + for (int i1 = 0; i1 < h_x.extent(1); i1++) { + for (int i2 = 0; i2 < h_x.extent(2); i2++) { + for (int i3 = 0; i3 < h_x.extent(3); i3++) { + for (int i4 = 0; i4 < h_x.extent(4); i4++) { + for (int i5 = 0; i5 < h_x.extent(5); i5++) { + for (int i6 = 0; i6 < h_x.extent(6); i6++) { + for (int i7 = 0; i7 < h_x.extent(7); i7++) { + int _i0 = (map[0] == 1) ? i1 + : (map[0] == 2) ? i2 + : (map[0] == 3) ? i3 + : (map[0] == 4) ? i4 + : (map[0] == 5) ? i5 + : (map[0] == 6) ? i6 + : (map[0] == 7) ? i7 + : i0; + int _i1 = (map[1] == 0) ? i0 + : (map[1] == 2) ? i2 + : (map[1] == 3) ? i3 + : (map[1] == 4) ? i4 + : (map[1] == 5) ? i5 + : (map[1] == 6) ? i6 + : (map[1] == 7) ? i7 + : i1; + int _i2 = (map[2] == 0) ? i0 + : (map[2] == 1) ? i1 + : (map[2] == 3) ? i3 + : (map[2] == 4) ? i4 + : (map[2] == 5) ? i5 + : (map[2] == 6) ? i6 + : (map[2] == 7) ? i7 + : i2; + int _i3 = (map[3] == 0) ? i0 + : (map[3] == 1) ? i1 + : (map[3] == 2) ? i2 + : (map[3] == 4) ? i4 + : (map[3] == 5) ? i5 + : (map[3] == 6) ? i6 + : (map[3] == 7) ? i7 + : i3; + int _i4 = (map[4] == 0) ? i0 + : (map[4] == 1) ? i1 + : (map[4] == 2) ? i2 + : (map[4] == 3) ? i3 + : (map[4] == 5) ? i5 + : (map[4] == 6) ? i6 + : (map[4] == 7) ? i7 + : i4; + int _i5 = (map[5] == 0) ? i0 + : (map[5] == 1) ? i1 + : (map[5] == 2) ? i2 + : (map[5] == 3) ? i3 + : (map[5] == 4) ? i4 + : (map[5] == 6) ? i6 + : (map[5] == 7) ? i7 + : i5; + int _i6 = (map[6] == 0) ? i0 + : (map[6] == 1) ? i1 + : (map[6] == 2) ? i2 + : (map[6] == 3) ? i3 + : (map[6] == 4) ? i4 + : (map[6] == 5) ? i5 + : (map[6] == 7) ? i7 + : i6; + int _i7 = (map[7] == 0) ? i0 + : (map[7] == 1) ? i1 + : (map[7] == 2) ? i2 + : (map[7] == 3) ? i3 + : (map[7] == 4) ? i4 + : (map[7] == 5) ? i5 + : (map[7] == 6) ? i6 + : i7; + h_ref(_i0, _i1, _i2, _i3, _i4, _i5, _i6, _i7) = + h_x(i0, i1, i2, i3, i4, i5, i6, i7); + } + } + } + } + } + } + } + } + + Kokkos::deep_copy(ref, h_ref); + Kokkos::fence(); + + KokkosFFT::Impl::transpose(execution_space(), x, xt, + map); // xt is the transpose of x + EXPECT_TRUE(allclose(xt, ref, 1.e-5, 1.e-12)); + + // Inverse (transpose of transpose is identical to the original) + RealView8Dtype _x; + KokkosFFT::Impl::transpose(execution_space(), xt, _x, map_inv); + EXPECT_TRUE(allclose(_x, x, 1.e-5, 1.e-12)); + } + } + } + } } -TYPED_TEST(Transpose, 3DView) { +TYPED_TEST(Transpose3D, 3DView) { using layout_type = typename TestFixture::layout_type; - test_transpose_3d(); + test_transpose_3d_3dview(); } -TYPED_TEST(Transpose, 4DView) { +TYPED_TEST(Transpose3D, 4DView) { using layout_type = typename TestFixture::layout_type; - test_transpose_4d(); + test_transpose_3d_4dview(); } -TYPED_TEST(Transpose, 5DView) { +TYPED_TEST(Transpose3D, 5DView) { using layout_type = typename TestFixture::layout_type; - test_transpose_5d(); + test_transpose_3d_5dview(); } -TYPED_TEST(Transpose, 6DView) { +TYPED_TEST(Transpose3D, 6DView) { using layout_type = typename TestFixture::layout_type; - test_transpose_6d(); + test_transpose_3d_6dview(); } -TYPED_TEST(Transpose, 7DView) { +TYPED_TEST(Transpose3D, 7DView) { using layout_type = typename TestFixture::layout_type; - test_transpose_7d(); + test_transpose_3d_7dview(); } -TYPED_TEST(Transpose, 8DView) { +TYPED_TEST(Transpose3D, 8DView) { using layout_type = typename TestFixture::layout_type; - test_transpose_8d(); + test_transpose_3d_8dview(); } \ No newline at end of file diff --git a/fft/unit_test/Test_Transform.cpp b/fft/unit_test/Test_Transform.cpp index 08fbe72a..665856c8 100644 --- a/fft/unit_test/Test_Transform.cpp +++ b/fft/unit_test/Test_Transform.cpp @@ -1,4 +1,6 @@ #include +#include +#include #include #include "KokkosFFT_Transform.hpp" #include "Test_Types.hpp" @@ -1162,6 +1164,7 @@ void test_fft1_1dfft_8dview(T atol = 1.e-12) { } } +/* // Identity tests on 1D Views TYPED_TEST(FFT1D, Identity_1DView) { using float_type = typename TestFixture::float_type; @@ -1274,6 +1277,7 @@ TYPED_TEST(FFT1D, FFT_batched_8DView) { float_type atol = std::is_same_v ? 1.0e-6 : 1.0e-12; test_fft1_1dfft_8dview(atol); } +*/ // Tests for FFT2 template @@ -1337,6 +1341,45 @@ void test_fft2_2dfft_2dview() { EXPECT_TRUE(allclose(out_b, out2, 1.e-5, 1.e-6)); EXPECT_TRUE(allclose(out_o, out2, 1.e-5, 1.e-6)); EXPECT_TRUE(allclose(out_f, out2, 1.e-5, 1.e-6)); + + // np.fft2(axes=(-1, -2)) is identical to np.fft(np.fft(x, axis=0), axis=1) + axes_type axes10 = {-1, -2}; + + KokkosFFT::fft(execution_space(), x, out1, KokkosFFT::Normalization::backward, + /*axis=*/0); + KokkosFFT::fft(execution_space(), out1, out2, + KokkosFFT::Normalization::backward, /*axis=*/1); + + KokkosFFT::fft2(execution_space(), x, out_b, + KokkosFFT::Normalization::backward, axes10); + KokkosFFT::fft2(execution_space(), x, out_o, KokkosFFT::Normalization::ortho, + axes10); + KokkosFFT::fft2(execution_space(), x, out_f, + KokkosFFT::Normalization::forward, axes10); + + multiply(out_o, sqrt(static_cast(n0 * n1))); + multiply(out_f, static_cast(n0 * n1)); + + EXPECT_TRUE(allclose(out_b, out2, 1.e-5, 1.e-6)); + EXPECT_TRUE(allclose(out_o, out2, 1.e-5, 1.e-6)); + EXPECT_TRUE(allclose(out_f, out2, 1.e-5, 1.e-6)); + + // Reuse plans np.fft2(axes=(-1, -2)) + KokkosFFT::Impl::Plan fft2_plan_axes10(execution_space(), x, out, + KokkosFFT::Direction::forward, axes10); + KokkosFFT::fft2(execution_space(), x, out_b, fft2_plan_axes10, + KokkosFFT::Normalization::backward, axes10); + KokkosFFT::fft2(execution_space(), x, out_o, fft2_plan_axes10, + KokkosFFT::Normalization::ortho, axes10); + KokkosFFT::fft2(execution_space(), x, out_f, fft2_plan_axes10, + KokkosFFT::Normalization::forward, axes10); + + multiply(out_o, sqrt(static_cast(n0 * n1))); + multiply(out_f, static_cast(n0 * n1)); + + EXPECT_TRUE(allclose(out_b, out2, 1.e-5, 1.e-6)); + EXPECT_TRUE(allclose(out_o, out2, 1.e-5, 1.e-6)); + EXPECT_TRUE(allclose(out_f, out2, 1.e-5, 1.e-6)); } template @@ -1402,6 +1445,44 @@ void test_fft2_2difft_2dview() { EXPECT_TRUE(allclose(out_b, out2, 1.e-5, 1.e-6)); EXPECT_TRUE(allclose(out_o, out2, 1.e-5, 1.e-6)); EXPECT_TRUE(allclose(out_f, out2, 1.e-5, 1.e-6)); + + // np.ifft2(axes=(-1, -2)) is identical to np.ifft(np.ifft(x, axis=0), axis=1) + axes_type axes10 = {-1, -2}; + KokkosFFT::ifft(execution_space(), x, out1, + KokkosFFT::Normalization::backward, /*axis=*/0); + KokkosFFT::ifft(execution_space(), out1, out2, + KokkosFFT::Normalization::backward, /*axis=*/1); + + KokkosFFT::ifft2(execution_space(), x, out_b, + KokkosFFT::Normalization::backward, axes10); + KokkosFFT::ifft2(execution_space(), x, out_o, KokkosFFT::Normalization::ortho, + axes10); + KokkosFFT::ifft2(execution_space(), x, out_f, + KokkosFFT::Normalization::forward, axes10); + + multiply(out_o, 1.0 / sqrt(static_cast(n0 * n1))); + multiply(out_f, 1.0 / static_cast(n0 * n1)); + + EXPECT_TRUE(allclose(out_b, out2, 1.e-5, 1.e-6)); + EXPECT_TRUE(allclose(out_o, out2, 1.e-5, 1.e-6)); + EXPECT_TRUE(allclose(out_f, out2, 1.e-5, 1.e-6)); + + KokkosFFT::Impl::Plan ifft2_plan_axes10( + execution_space(), x, out, KokkosFFT::Direction::backward, axes10); + + KokkosFFT::ifft2(execution_space(), x, out_b, ifft2_plan_axes10, + KokkosFFT::Normalization::backward, axes10); + KokkosFFT::ifft2(execution_space(), x, out_o, ifft2_plan_axes10, + KokkosFFT::Normalization::ortho, axes10); + KokkosFFT::ifft2(execution_space(), x, out_f, ifft2_plan_axes10, + KokkosFFT::Normalization::forward, axes10); + + multiply(out_o, 1.0 / sqrt(static_cast(n0 * n1))); + multiply(out_f, 1.0 / static_cast(n0 * n1)); + + EXPECT_TRUE(allclose(out_b, out2, 1.e-5, 1.e-6)); + EXPECT_TRUE(allclose(out_o, out2, 1.e-5, 1.e-6)); + EXPECT_TRUE(allclose(out_f, out2, 1.e-5, 1.e-6)); } template @@ -1563,6 +1644,397 @@ void test_fft2_2dirfft_2dview() { EXPECT_TRUE(allclose(out_f, out2, 1.e-5, 1.e-6)); } +template +void test_fft2_2dfft_3dview(T atol = 1.e-12) { + const int n0 = 10, n1 = 6, n2 = 8; + using RealView3DType = Kokkos::View; + using ComplexView3DType = + Kokkos::View***, LayoutType, execution_space>; + + constexpr int DIM = 3; + std::array shape = {n0, n1, n2}; + ComplexView3DType x("x", n0, n1, n2), ref_x("ref_x", n0, n1, n2); + + using axes_type = KokkosFFT::axis_type<2>; + + for (int axis0 = 0; axis0 < DIM; axis0++) { + for (int axis1 = 0; axis1 < DIM; axis1++) { + // make all the combinations of axes = {axis0, axis1} + // axis0 and axis1 must be different + if (axis0 == axis1) continue; + + axes_type axes = {axis0, axis1}; + + std::array shape_c2r = shape; + shape_c2r.at(axis1) = shape_c2r.at(axis1) / 2 + 1; + + auto [_n0, _n1, _n2] = shape_c2r; + + std::cout << axis0 << ", " << axis1 << std::endl; + std::cout << "_n0, _n1, _n2: " << _n0 << ", " << _n1 << ", " << _n2 + << std::endl; + ComplexView3DType _x("_x", n0, n1, n2), out("out", n0, n1, n2), + ref_out("ref_out", n0, n1, n2); + RealView3DType xr("xr", n0, n1, n2), ref_xr("ref_xr", n0, n1, n2), + _xr("_xr", n0, n1, n2); + ComplexView3DType outr("outr", _n0, _n1, _n2); + + const Kokkos::complex I(1.0, 1.0); + Kokkos::Random_XorShift64_Pool<> random_pool(12345); + Kokkos::fill_random(x, random_pool, I); + Kokkos::fill_random(xr, random_pool, 1); + + Kokkos::deep_copy(ref_x, x); + Kokkos::deep_copy(ref_xr, xr); + + Kokkos::fence(); + + // Along one axis + // Simple identity tests + KokkosFFT::fft2(execution_space(), x, out, + KokkosFFT::Normalization::backward, axes); + + KokkosFFT::ifft2(execution_space(), out, _x, + KokkosFFT::Normalization::backward, axes); + + EXPECT_TRUE(allclose(_x, ref_x, 1.e-5, atol)); + + // Simple identity tests for r2c and c2r transforms + KokkosFFT::rfft2(execution_space(), xr, outr, + KokkosFFT::Normalization::backward, axes); + + KokkosFFT::irfft2(execution_space(), outr, _xr, + KokkosFFT::Normalization::backward, axes); + + EXPECT_TRUE(allclose(_xr, ref_xr, 1.e-5, atol)); + } + } +} + +template +void test_fft2_2dfft_4dview(T atol = 1.e-12) { + const int n0 = 10, n1 = 6, n2 = 8, n3 = 5; + using RealView4DType = Kokkos::View; + using ComplexView4DType = + Kokkos::View****, LayoutType, execution_space>; + + constexpr int DIM = 4; + std::array shape = {n0, n1, n2, n3}; + ComplexView4DType x("x", n0, n1, n2, n3), ref_x("ref_x", n0, n1, n2, n3); + + using axes_type = KokkosFFT::axis_type<2>; + + for (int axis0 = 0; axis0 < DIM; axis0++) { + for (int axis1 = 0; axis1 < DIM; axis1++) { + // make all the combinations of axes = {axis0, axis1} + // axis0 and axis1 must be different + if (axis0 == axis1) continue; + + axes_type axes = {axis0, axis1}; + + std::array shape_c2r = shape; + shape_c2r.at(axis1) = shape_c2r.at(axis1) / 2 + 1; + + auto [_n0, _n1, _n2, _n3] = shape_c2r; + ComplexView4DType _x("_x", n0, n1, n2, n3), out("out", n0, n1, n2, n3), + ref_out("ref_out", n0, n1, n2, n3); + RealView4DType xr("xr", n0, n1, n2, n3), ref_xr("ref_xr", n0, n1, n2, n3), + _xr("_xr", n0, n1, n2, n3); + ComplexView4DType outr("outr", _n0, _n1, _n2, _n3); + + const Kokkos::complex I(1.0, 1.0); + Kokkos::Random_XorShift64_Pool<> random_pool(12345); + Kokkos::fill_random(x, random_pool, I); + Kokkos::fill_random(xr, random_pool, 1); + + Kokkos::deep_copy(ref_x, x); + Kokkos::deep_copy(ref_xr, xr); + + Kokkos::fence(); + + // Along one axis + // Simple identity tests + KokkosFFT::fft2(execution_space(), x, out, + KokkosFFT::Normalization::backward, axes); + + KokkosFFT::ifft2(execution_space(), out, _x, + KokkosFFT::Normalization::backward, axes); + + EXPECT_TRUE(allclose(_x, ref_x, 1.e-5, atol)); + + // Simple identity tests for r2c and c2r transforms + KokkosFFT::rfft2(execution_space(), xr, outr, + KokkosFFT::Normalization::backward, axes); + + KokkosFFT::irfft2(execution_space(), outr, _xr, + KokkosFFT::Normalization::backward, axes); + + EXPECT_TRUE(allclose(_xr, ref_xr, 1.e-5, atol)); + } + } +} + +template +void test_fft2_2dfft_5dview(T atol = 1.e-12) { + const int n0 = 10, n1 = 6, n2 = 8, n3 = 5, n4 = 4; + using RealView5DType = Kokkos::View; + using ComplexView5DType = + Kokkos::View*****, LayoutType, execution_space>; + + constexpr int DIM = 5; + std::array shape = {n0, n1, n2, n3, n4}; + ComplexView5DType x("x", n0, n1, n2, n3, n4), + ref_x("ref_x", n0, n1, n2, n3, n4); + + using axes_type = KokkosFFT::axis_type<2>; + + for (int axis0 = 0; axis0 < DIM; axis0++) { + for (int axis1 = 0; axis1 < DIM; axis1++) { + // make all the combinations of axes = {axis0, axis1} + // axis0 and axis1 must be different + if (axis0 == axis1) continue; + + axes_type axes = {axis0, axis1}; + + std::array shape_c2r = shape; + shape_c2r.at(axis1) = shape_c2r.at(axis1) / 2 + 1; + + auto [_n0, _n1, _n2, _n3, _n4] = shape_c2r; + ComplexView5DType _x("_x", n0, n1, n2, n3, n4), + out("out", n0, n1, n2, n3, n4), + ref_out("ref_out", n0, n1, n2, n3, n4); + RealView5DType xr("xr", n0, n1, n2, n3, n4), + ref_xr("ref_xr", n0, n1, n2, n3, n4), _xr("_xr", n0, n1, n2, n3, n4); + ComplexView5DType outr("outr", _n0, _n1, _n2, _n3, _n4); + + const Kokkos::complex I(1.0, 1.0); + Kokkos::Random_XorShift64_Pool<> random_pool(12345); + Kokkos::fill_random(x, random_pool, I); + Kokkos::fill_random(xr, random_pool, 1); + + Kokkos::deep_copy(ref_x, x); + Kokkos::deep_copy(ref_xr, xr); + + Kokkos::fence(); + + // Along one axis + // Simple identity tests + KokkosFFT::fft2(execution_space(), x, out, + KokkosFFT::Normalization::backward, axes); + + KokkosFFT::ifft2(execution_space(), out, _x, + KokkosFFT::Normalization::backward, axes); + + EXPECT_TRUE(allclose(_x, ref_x, 1.e-5, atol)); + + // Simple identity tests for r2c and c2r transforms + KokkosFFT::rfft2(execution_space(), xr, outr, + KokkosFFT::Normalization::backward, axes); + + KokkosFFT::irfft2(execution_space(), outr, _xr, + KokkosFFT::Normalization::backward, axes); + + EXPECT_TRUE(allclose(_xr, ref_xr, 1.e-5, atol)); + } + } +} + +template +void test_fft2_2dfft_6dview(T atol = 1.e-12) { + const int n0 = 10, n1 = 6, n2 = 8, n3 = 5, n4 = 4, n5 = 3; + using RealView6DType = Kokkos::View; + using ComplexView6DType = + Kokkos::View******, LayoutType, execution_space>; + + constexpr int DIM = 6; + std::array shape = {n0, n1, n2, n3, n4, n5}; + ComplexView6DType x("x", n0, n1, n2, n3, n4, n5), + ref_x("ref_x", n0, n1, n2, n3, n4, n5); + + using axes_type = KokkosFFT::axis_type<2>; + + for (int axis0 = 0; axis0 < DIM; axis0++) { + for (int axis1 = 0; axis1 < DIM; axis1++) { + // make all the combinations of axes = {axis0, axis1} + // axis0 and axis1 must be different + if (axis0 == axis1) continue; + + axes_type axes = {axis0, axis1}; + + std::array shape_c2r = shape; + shape_c2r.at(axis1) = shape_c2r.at(axis1) / 2 + 1; + + auto [_n0, _n1, _n2, _n3, _n4, _n5] = shape_c2r; + ComplexView6DType _x("_x", n0, n1, n2, n3, n4, n5), + out("out", n0, n1, n2, n3, n4, n5), + ref_out("ref_out", n0, n1, n2, n3, n4, n5); + RealView6DType xr("xr", n0, n1, n2, n3, n4, n5), + ref_xr("ref_xr", n0, n1, n2, n3, n4, n5), + _xr("_xr", n0, n1, n2, n3, n4, n5); + ComplexView6DType outr("outr", _n0, _n1, _n2, _n3, _n4, _n5); + + const Kokkos::complex I(1.0, 1.0); + Kokkos::Random_XorShift64_Pool<> random_pool(12345); + Kokkos::fill_random(x, random_pool, I); + Kokkos::fill_random(xr, random_pool, 1); + + Kokkos::deep_copy(ref_x, x); + Kokkos::deep_copy(ref_xr, xr); + + Kokkos::fence(); + + // Along one axis + // Simple identity tests + KokkosFFT::fft2(execution_space(), x, out, + KokkosFFT::Normalization::backward, axes); + + KokkosFFT::ifft2(execution_space(), out, _x, + KokkosFFT::Normalization::backward, axes); + + EXPECT_TRUE(allclose(_x, ref_x, 1.e-5, atol)); + + // Simple identity tests for r2c and c2r transforms + KokkosFFT::rfft2(execution_space(), xr, outr, + KokkosFFT::Normalization::backward, axes); + + KokkosFFT::irfft2(execution_space(), outr, _xr, + KokkosFFT::Normalization::backward, axes); + + EXPECT_TRUE(allclose(_xr, ref_xr, 1.e-5, atol)); + } + } +} + +template +void test_fft2_2dfft_7dview(T atol = 1.e-12) { + const int n0 = 2, n1 = 6, n2 = 8, n3 = 5, n4 = 4, n5 = 3, n6 = 4; + using RealView7DType = Kokkos::View; + using ComplexView7DType = + Kokkos::View*******, LayoutType, execution_space>; + + constexpr int DIM = 7; + std::array shape = {n0, n1, n2, n3, n4, n5, n6}; + ComplexView7DType x("x", n0, n1, n2, n3, n4, n5, n6), + ref_x("ref_x", n0, n1, n2, n3, n4, n5, n6); + + using axes_type = KokkosFFT::axis_type<2>; + for (int axis0 = 0; axis0 < DIM; axis0++) { + for (int axis1 = 0; axis1 < DIM; axis1++) { + // make all the combinations of axes = {axis0, axis1} + // axis0 and axis1 must be different + if (axis0 == axis1) continue; + + axes_type axes = {axis0, axis1}; + + std::array shape_c2r = shape; + shape_c2r.at(axis1) = shape_c2r.at(axis1) / 2 + 1; + + auto [_n0, _n1, _n2, _n3, _n4, _n5, _n6] = shape_c2r; + ComplexView7DType _x("_x", n0, n1, n2, n3, n4, n5, n6), + out("out", n0, n1, n2, n3, n4, n5, n6), + ref_out("ref_out", n0, n1, n2, n3, n4, n5, n6); + RealView7DType xr("xr", n0, n1, n2, n3, n4, n5, n6), + ref_xr("ref_xr", n0, n1, n2, n3, n4, n5, n6), + _xr("_xr", n0, n1, n2, n3, n4, n5, n6); + ComplexView7DType outr("outr", _n0, _n1, _n2, _n3, _n4, _n5, _n6); + + const Kokkos::complex I(1.0, 1.0); + Kokkos::Random_XorShift64_Pool<> random_pool(12345); + Kokkos::fill_random(x, random_pool, I); + Kokkos::fill_random(xr, random_pool, 1); + + Kokkos::deep_copy(ref_x, x); + Kokkos::deep_copy(ref_xr, xr); + + Kokkos::fence(); + + // Along one axis + // Simple identity tests + KokkosFFT::fft2(execution_space(), x, out, + KokkosFFT::Normalization::backward, axes); + + KokkosFFT::ifft2(execution_space(), out, _x, + KokkosFFT::Normalization::backward, axes); + + EXPECT_TRUE(allclose(_x, ref_x, 1.e-5, atol)); + + // Simple identity tests for r2c and c2r transforms + KokkosFFT::rfft2(execution_space(), xr, outr, + KokkosFFT::Normalization::backward, axes); + + KokkosFFT::irfft2(execution_space(), outr, _xr, + KokkosFFT::Normalization::backward, axes); + + EXPECT_TRUE(allclose(_xr, ref_xr, 1.e-5, atol)); + } + } +} + +template +void test_fft2_2dfft_8dview(T atol = 1.e-12) { + const int n0 = 2, n1 = 6, n2 = 8, n3 = 5, n4 = 4, n5 = 3, n6 = 4, n7 = 3; + using RealView8DType = Kokkos::View; + using ComplexView8DType = + Kokkos::View********, LayoutType, execution_space>; + + constexpr int DIM = 8; + std::array shape = {n0, n1, n2, n3, n4, n5, n6, n7}; + ComplexView8DType x("x", n0, n1, n2, n3, n4, n5, n6, n7), + ref_x("ref_x", n0, n1, n2, n3, n4, n5, n6, n7); + + using axes_type = KokkosFFT::axis_type<2>; + for (int axis0 = 0; axis0 < DIM; axis0++) { + for (int axis1 = 0; axis1 < DIM; axis1++) { + // make all the combinations of axes = {axis0, axis1} + // axis0 and axis1 must be different + if (axis0 == axis1) continue; + + axes_type axes = {axis0, axis1}; + + std::array shape_c2r = shape; + shape_c2r.at(axis1) = shape_c2r.at(axis1) / 2 + 1; + + auto [_n0, _n1, _n2, _n3, _n4, _n5, _n6, _n7] = shape_c2r; + ComplexView8DType _x("_x", n0, n1, n2, n3, n4, n5, n6, n7), + out("out", n0, n1, n2, n3, n4, n5, n6, n7), + ref_out("ref_out", n0, n1, n2, n3, n4, n5, n6, n7); + RealView8DType xr("xr", n0, n1, n2, n3, n4, n5, n6, n7), + ref_xr("ref_xr", n0, n1, n2, n3, n4, n5, n6, n7), + _xr("_xr", n0, n1, n2, n3, n4, n5, n6, n7); + ComplexView8DType outr("outr", _n0, _n1, _n2, _n3, _n4, _n5, _n6, _n7); + + const Kokkos::complex I(1.0, 1.0); + Kokkos::Random_XorShift64_Pool<> random_pool(12345); + Kokkos::fill_random(x, random_pool, I); + Kokkos::fill_random(xr, random_pool, 1); + + Kokkos::deep_copy(ref_x, x); + Kokkos::deep_copy(ref_xr, xr); + + Kokkos::fence(); + + // Along one axis + // Simple identity tests + KokkosFFT::fft2(execution_space(), x, out, + KokkosFFT::Normalization::backward, axes); + + KokkosFFT::ifft2(execution_space(), out, _x, + KokkosFFT::Normalization::backward, axes); + + EXPECT_TRUE(allclose(_x, ref_x, 1.e-5, atol)); + + // Simple identity tests for r2c and c2r transforms + KokkosFFT::rfft2(execution_space(), xr, outr, + KokkosFFT::Normalization::backward, axes); + + KokkosFFT::irfft2(execution_space(), outr, _xr, + KokkosFFT::Normalization::backward, axes); + + EXPECT_TRUE(allclose(_xr, ref_xr, 1.e-5, atol)); + } + } +} + // fft2 on 2D Views TYPED_TEST(FFT2D, FFT2_2DView) { using float_type = typename TestFixture::float_type; @@ -1595,6 +2067,60 @@ TYPED_TEST(FFT2D, IRFFT2_2DView) { test_fft2_2dirfft_2dview(); } +// batced fft2 on 3D Views +TYPED_TEST(FFT2D, FFT_batched_3DView) { + using float_type = typename TestFixture::float_type; + using layout_type = typename TestFixture::layout_type; + + float_type atol = std::is_same_v ? 1.0e-6 : 1.0e-12; + test_fft2_2dfft_3dview(atol); +} + +// batced fft2 on 4D Views +TYPED_TEST(FFT2D, FFT_batched_4DView) { + using float_type = typename TestFixture::float_type; + using layout_type = typename TestFixture::layout_type; + + float_type atol = std::is_same_v ? 1.0e-6 : 1.0e-12; + test_fft2_2dfft_4dview(atol); +} + +// batced fft2 on 5D Views +TYPED_TEST(FFT2D, FFT_batched_5DView) { + using float_type = typename TestFixture::float_type; + using layout_type = typename TestFixture::layout_type; + + float_type atol = std::is_same_v ? 1.0e-6 : 1.0e-12; + test_fft2_2dfft_5dview(atol); +} + +// batced fft2 on 6D Views +TYPED_TEST(FFT2D, FFT_batched_6DView) { + using float_type = typename TestFixture::float_type; + using layout_type = typename TestFixture::layout_type; + + float_type atol = std::is_same_v ? 1.0e-6 : 1.0e-12; + test_fft2_2dfft_6dview(atol); +} + +// batced fft2 on 7D Views +TYPED_TEST(FFT2D, FFT_batched_7DView) { + using float_type = typename TestFixture::float_type; + using layout_type = typename TestFixture::layout_type; + + float_type atol = std::is_same_v ? 1.0e-6 : 1.0e-12; + test_fft2_2dfft_7dview(atol); +} + +// batced fft2 on 8D Views +TYPED_TEST(FFT2D, FFT_batched_8DView) { + using float_type = typename TestFixture::float_type; + using layout_type = typename TestFixture::layout_type; + + float_type atol = std::is_same_v ? 1.0e-6 : 1.0e-12; + test_fft2_2dfft_8dview(atol); +} + // Tests for FFTN template void test_fftn_2dfft_2dview() {