//@HEADER // ************************************************************************ // // Kokkos v. 4.0 // Copyright (2022) National Technology & Engineering // Solutions of Sandia, LLC (NTESS). // // Under the terms of Contract DE-NA0003525 with NTESS, // the U.S. Government retains certain rights in this software. // // Part of Kokkos, under the Apache License v2.0 with LLVM Exceptions. // See https://kokkos.org/LICENSE for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //@HEADER #include namespace KE = Kokkos::Experimental; namespace Test { namespace stdalgos { struct std_algorithms_min_max_element_test : std_algorithms_test { const int m_number_of_filling_cases = 5; void fillFixtureViews(int case_number) { static_view_t tmpView("tmpView"); auto tmp_view_h = Kokkos::create_mirror_view(Kokkos::HostSpace(), tmpView); if (case_number == 1) { tmp_view_h(0) = 0; tmp_view_h(1) = 0; tmp_view_h(2) = 0; tmp_view_h(3) = 2; tmp_view_h(4) = 2; tmp_view_h(5) = 1; tmp_view_h(6) = 1; tmp_view_h(7) = 1; tmp_view_h(8) = 1; tmp_view_h(9) = 0; } else if (case_number == 2) { tmp_view_h(0) = 1; tmp_view_h(1) = 2; tmp_view_h(2) = 3; tmp_view_h(3) = 4; tmp_view_h(4) = 5; tmp_view_h(5) = 6; tmp_view_h(6) = 7; tmp_view_h(7) = 8; tmp_view_h(8) = 9; tmp_view_h(9) = 10; } else if (case_number == 3) { tmp_view_h(0) = 8; tmp_view_h(1) = 8; tmp_view_h(2) = -1; tmp_view_h(3) = -1; tmp_view_h(4) = 5; tmp_view_h(5) = 5; tmp_view_h(6) = 5; tmp_view_h(7) = 8; tmp_view_h(8) = 2; tmp_view_h(9) = 1; } else if (case_number == 4) { tmp_view_h(0) = 2; tmp_view_h(1) = 2; tmp_view_h(2) = 2; tmp_view_h(3) = 2; tmp_view_h(4) = 2; tmp_view_h(5) = 2; tmp_view_h(6) = 2; tmp_view_h(7) = 2; tmp_view_h(8) = 2; tmp_view_h(9) = 2; } else if (case_number == 5) { tmp_view_h(0) = 1; tmp_view_h(1) = 2; tmp_view_h(2) = 3; tmp_view_h(3) = 4; tmp_view_h(4) = 5; tmp_view_h(5) = 12; tmp_view_h(6) = 5; tmp_view_h(7) = 4; tmp_view_h(8) = 3; tmp_view_h(9) = 2; } else { } Kokkos::deep_copy(tmpView, tmp_view_h); copyInputViewToFixtureViews(tmpView); } Kokkos::pair goldSolutionMaxElement(int caseNumber) { // returns {indexOfMaxElem, maxValue} if (caseNumber == 1) { return {3, 2}; } else if (caseNumber == 2) { return {9, 10}; } else if (caseNumber == 3) { return {0, 8}; } else if (caseNumber == 4) { return {0, 2}; } else if (caseNumber == 5) { return {5, 12}; } else { return {}; } } Kokkos::pair goldSolutionMinElement(int caseNumber) { // returns {indexOfMinElem, minValue} if (caseNumber == 1) { return {0, 0}; } else if (caseNumber == 2) { return {0, 1}; } else if (caseNumber == 3) { return {2, -1}; } else if (caseNumber == 4) { return {0, 2}; } else if (caseNumber == 5) { return {0, 1}; } else { return {}; } } Kokkos::pair, Kokkos::pair> goldSolutionMinMaxElement(int caseNumber) { // returns {{indexOfMinElem, minValue}, {indexOfMaxElem, maxValue}} // remember that for min it finds the first smallest element // remember that for max it finds the last biggest element if (caseNumber == 1) { return {{0, 0}, {4, 2}}; } else if (caseNumber == 2) { return {{0, 1}, {9, 10}}; } else if (caseNumber == 3) { return {{2, -1}, {7, 8}}; } else if (caseNumber == 4) { return {{0, 2}, {9, 2}}; } else if (caseNumber == 5) { return {{0, 1}, {5, 12}}; } else { return {}; } } template void test_max_element_non_trivial_data(ViewType view); template void test_min_element_non_trivial_data(ViewType view); template void test_minmax_element_non_trivial_data(ViewType view); template void test_max_element_non_trivial_data_custom_comp(ViewType view); template void test_min_element_non_trivial_data_custom_comp(ViewType view); template void test_minmax_element_non_trivial_data_custom_comp(ViewType view); }; template void std_algo_min_max_test_verify(Kokkos::pair goldPair, const ItType result, TestedViewType testedView) { // check that iterator is pointing to right element ASSERT_EQ(result - KE::begin(testedView), goldPair.first); // create a view for the result to copy into it the iterator's value using result_view_t = Kokkos::View; result_view_t resultView("result"); CopyFromIteratorFunctor cf(result, resultView); Kokkos::parallel_for("_std_algo_copy", 1, cf); auto result_v_h = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), resultView); // use the host mirror of the result view to check that the values match ASSERT_EQ(result_v_h(), goldPair.second); } template void std_algo_min_max_test_verify(const GoldSolutionType& goldSolution, const ItType itMin, const ItType itMax, TestedViewType testedView) { std_algo_min_max_test_verify(goldSolution.first, itMin, testedView); std_algo_min_max_test_verify(goldSolution.second, itMax, testedView); } template void test_max_element_trivial_data(ViewType view) { /* if we pass empty range, should return last */ auto result = KE::max_element(exespace(), KE::cbegin(view), KE::cbegin(view)); ASSERT_EQ(result, KE::cbegin(view)); /* if we pass empty range, should return last */ auto it0 = KE::cbegin(view) + 3; auto it1 = it0; auto result2 = KE::max_element(exespace(), it0, it1); ASSERT_EQ(result2, it1); } template void test_min_element_trivial_data(ViewType view) { /* if we pass empty range, should return last */ auto result = KE::min_element(exespace(), KE::cbegin(view), KE::cbegin(view)); ASSERT_EQ(result, KE::cbegin(view)); /* if we pass empty range, should return last */ auto it0 = KE::cbegin(view) + 3; auto it1 = it0; auto result2 = KE::min_element(exespace(), it0, it1); ASSERT_EQ(result2, it1); } template void test_minmax_element_empty_range(ViewType view) { auto result = KE::minmax_element(exespace(), KE::cbegin(view), KE::cbegin(view)); ASSERT_EQ(result.first, KE::cbegin(view)); ASSERT_EQ(result.second, KE::cbegin(view)); auto it0 = KE::cbegin(view) + 3; auto it1 = it0; auto result2 = KE::minmax_element(exespace(), it0, it1); ASSERT_EQ(result2.first, it1); ASSERT_EQ(result2.second, it1); } template void std_algorithms_min_max_element_test::test_max_element_non_trivial_data( ViewType view) { for (int id = 1; id <= m_number_of_filling_cases; ++id) { fillFixtureViews(id); const auto gold_solution = goldSolutionMaxElement(id); // API accepting view { const auto result = KE::max_element(exespace(), view); std_algo_min_max_test_verify(gold_solution, result, view); const auto result2 = KE::max_element("MYCUSTOMLABEL1", exespace(), view); std_algo_min_max_test_verify(gold_solution, result2, view); } // API accepting iterators { const auto result = KE::max_element(exespace(), KE::begin(view), KE::end(view)); std_algo_min_max_test_verify(gold_solution, result, view); const auto result2 = KE::max_element("MYCUSTOMLABEL2", exespace(), KE::begin(view), KE::end(view)); std_algo_min_max_test_verify(gold_solution, result2, view); } } } template void std_algorithms_min_max_element_test::test_min_element_non_trivial_data( ViewType view) { for (int id = 1; id <= m_number_of_filling_cases; ++id) { fillFixtureViews(id); const auto goldPair = goldSolutionMinElement(id); // API accepting view { const auto result = KE::min_element(exespace(), view); std_algo_min_max_test_verify(goldPair, result, view); const auto result2 = KE::min_element("MYCUSTOMLABEL1", exespace(), view); std_algo_min_max_test_verify(goldPair, result2, view); } // API accepting iterators { const auto result = KE::min_element(exespace(), KE::begin(view), KE::end(view)); std_algo_min_max_test_verify(goldPair, result, view); const auto result2 = KE::min_element("MYCUSTOMLABEL2", exespace(), KE::begin(view), KE::end(view)); std_algo_min_max_test_verify(goldPair, result2, view); } } } template void std_algorithms_min_max_element_test::test_minmax_element_non_trivial_data( ViewType view) { for (int id = 1; id <= m_number_of_filling_cases; ++id) { fillFixtureViews(id); const auto gold = goldSolutionMinMaxElement(id); { auto result = KE::minmax_element(exespace(), view); std_algo_min_max_test_verify(gold, result.first, result.second, view); const auto result2 = KE::minmax_element("MYCUSTOMLABEL1", exespace(), view); std_algo_min_max_test_verify(gold, result2.first, result2.second, view); } { const auto result = KE::minmax_element(exespace(), KE::begin(view), KE::end(view)); std_algo_min_max_test_verify(gold, result.first, result.second, view); const auto result2 = KE::minmax_element("MYCUSTOMLABEL2", exespace(), KE::begin(view), KE::end(view)); std_algo_min_max_test_verify(gold, result2.first, result2.second, view); } } } #if !defined KOKKOS_ENABLE_OPENMPTARGET template void std_algorithms_min_max_element_test:: test_max_element_non_trivial_data_custom_comp(ViewType view) { for (int id = 1; id <= m_number_of_filling_cases; ++id) { fillFixtureViews(id); const auto goldPair = goldSolutionMaxElement(id); CustomLessThanComparator comp; // API accepting view { const auto result = KE::max_element(exespace(), view, comp); std_algo_min_max_test_verify(goldPair, result, view); const auto result2 = KE::max_element("MYCUSTOMLABEL3", exespace(), view, comp); std_algo_min_max_test_verify(goldPair, result2, view); } // API accepting iterators { const auto result = KE::max_element(exespace(), KE::begin(view), KE::end(view), comp); std_algo_min_max_test_verify(goldPair, result, view); const auto result2 = KE::max_element( "MYCUSTOMLABEL4", exespace(), KE::begin(view), KE::end(view), comp); std_algo_min_max_test_verify(goldPair, result2, view); } } } template void std_algorithms_min_max_element_test:: test_min_element_non_trivial_data_custom_comp(ViewType view) { for (int id = 1; id <= m_number_of_filling_cases; ++id) { fillFixtureViews(id); const auto goldPair = goldSolutionMinElement(id); CustomLessThanComparator comp; // API accepting view { const auto result = KE::min_element(exespace(), view, comp); std_algo_min_max_test_verify(goldPair, result, view); const auto result2 = KE::min_element("MYCUSTOMLABEL3", exespace(), view, comp); std_algo_min_max_test_verify(goldPair, result2, view); } // API accepting iterators { const auto result = KE::min_element(exespace(), KE::begin(view), KE::end(view), comp); std_algo_min_max_test_verify(goldPair, result, view); const auto result2 = KE::min_element( "MYCUSTOMLABEL4", exespace(), KE::begin(view), KE::end(view), comp); std_algo_min_max_test_verify(goldPair, result2, view); } } } template void std_algorithms_min_max_element_test:: test_minmax_element_non_trivial_data_custom_comp(ViewType view) { for (int id = 1; id <= m_number_of_filling_cases; ++id) { fillFixtureViews(id); const auto goldPair = goldSolutionMinMaxElement(id); CustomLessThanComparator comp; { const auto result = KE::minmax_element(exespace(), view, comp); std_algo_min_max_test_verify(goldPair, result.first, result.second, view); const auto result2 = KE::minmax_element("MYCUSTOMLABEL3", exespace(), view, comp); std_algo_min_max_test_verify(goldPair, result2.first, result2.second, view); } { const auto result = KE::minmax_element(exespace(), KE::begin(view), KE::end(view), comp); std_algo_min_max_test_verify(goldPair, result.first, result.second, view); const auto result2 = KE::minmax_element( "MYCUSTOMLABEL4", exespace(), KE::begin(view), KE::end(view), comp); std_algo_min_max_test_verify(goldPair, result2.first, result2.second, view); } } } #endif // trivial case TEST_F(std_algorithms_min_max_element_test, min_element_empty_range) { test_min_element_trivial_data(m_static_view); test_min_element_trivial_data(m_dynamic_view); test_min_element_trivial_data(m_strided_view); } TEST_F(std_algorithms_min_max_element_test, max_element_empty_range) { test_max_element_trivial_data(m_static_view); test_max_element_trivial_data(m_dynamic_view); test_max_element_trivial_data(m_strided_view); } // non-trivial data TEST_F(std_algorithms_min_max_element_test, min_element_non_trivial_data) { test_min_element_non_trivial_data(m_static_view); test_min_element_non_trivial_data(m_dynamic_view); test_min_element_non_trivial_data(m_strided_view); } TEST_F(std_algorithms_min_max_element_test, max_element_non_trivial_data) { test_max_element_non_trivial_data(m_static_view); test_max_element_non_trivial_data(m_dynamic_view); test_max_element_non_trivial_data(m_strided_view); } #if !defined KOKKOS_ENABLE_OPENMPTARGET // non-trivial data, custom comp TEST_F(std_algorithms_min_max_element_test, min_element_non_trivial_data_custom_comp) { test_min_element_non_trivial_data_custom_comp(m_static_view); test_min_element_non_trivial_data_custom_comp(m_dynamic_view); test_min_element_non_trivial_data_custom_comp(m_strided_view); } TEST_F(std_algorithms_min_max_element_test, max_element_non_trivial_data_custom_comp) { test_max_element_non_trivial_data_custom_comp(m_static_view); test_max_element_non_trivial_data_custom_comp(m_dynamic_view); test_max_element_non_trivial_data_custom_comp(m_strided_view); } #endif #if defined(KOKKOS_ENABLE_OPENMPTARGET) && defined(KOKKOS_COMPILER_CLANG) && \ (KOKKOS_COMPILER_CLANG >= 1300) TEST_F(std_algorithms_min_max_element_test, minmax_element_empty_range) { test_minmax_element_empty_range(m_static_view); test_minmax_element_empty_range(m_dynamic_view); test_minmax_element_empty_range(m_strided_view); } TEST_F(std_algorithms_min_max_element_test, minmax_element_non_trivial_data) { test_minmax_element_non_trivial_data(m_static_view); test_minmax_element_non_trivial_data(m_dynamic_view); test_minmax_element_non_trivial_data(m_strided_view); } #endif #if !defined KOKKOS_ENABLE_OPENMPTARGET // OpenMPTarget does not yet support custom comparator TEST_F(std_algorithms_min_max_element_test, minmax_element_non_trivial_data_custom_comp) { test_minmax_element_non_trivial_data_custom_comp(m_static_view); test_minmax_element_non_trivial_data_custom_comp(m_dynamic_view); test_minmax_element_non_trivial_data_custom_comp(m_strided_view); } #endif } // namespace stdalgos } // namespace Test