Update Kokkos library in LAMMPS to v3.6.0

This commit is contained in:
Stan Gerald Moore
2022-05-05 11:44:47 -06:00
parent bd4bbbddbe
commit b79c0bc7b4
380 changed files with 41928 additions and 8786 deletions

View File

@ -6,70 +6,153 @@ KOKKOS_INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR}/../src )
KOKKOS_INCLUDE_DIRECTORIES(${KOKKOS_SOURCE_DIR}/core/unit_test/category_files)
SET(GTEST_SOURCE_DIR ${${PARENT_PACKAGE_NAME}_SOURCE_DIR}/tpls/gtest)
KOKKOS_INCLUDE_DIRECTORIES(${GTEST_SOURCE_DIR})
# mfh 03 Nov 2017: The gtest library used here must have a different
# name than that of the gtest library built in KokkosCore. We can't
# just refer to the library in KokkosCore's tests, because it's
# possible to build only (e.g.,) KokkosAlgorithms tests, without
# building KokkosCore tests.
KOKKOS_ADD_TEST_LIBRARY(
kokkosalgorithms_gtest
HEADERS ${GTEST_SOURCE_DIR}/gtest/gtest.h
SOURCES ${GTEST_SOURCE_DIR}/gtest/gtest-all.cc
)
# avoid deprecation warnings from MSVC
TARGET_COMPILE_DEFINITIONS(kokkosalgorithms_gtest PUBLIC GTEST_HAS_TR1_TUPLE=0 GTEST_HAS_PTHREAD=0)
IF((NOT (Kokkos_ENABLE_CUDA AND WIN32)) AND (NOT ("${KOKKOS_CXX_COMPILER_ID}" STREQUAL "Fujitsu")))
TARGET_COMPILE_FEATURES(kokkosalgorithms_gtest PUBLIC cxx_std_14)
ENDIF()
# Suppress clang-tidy diagnostics on code that we do not have control over
IF(CMAKE_CXX_CLANG_TIDY)
SET_TARGET_PROPERTIES(kokkosalgorithms_gtest PROPERTIES CXX_CLANG_TIDY "")
ENDIF()
SET(ALGORITHM UnitTestMain.cpp)
IF(Kokkos_ENABLE_OPENMP)
LIST(APPEND ALGORITHM_SOURCES
TestOpenMP_Sort1D.cpp
TestOpenMP_Sort3D.cpp
TestOpenMP_SortDynamicView.cpp
)
ENDIF()
foreach(Tag Threads;Serial;OpenMP;Cuda;HPX;HIP;SYCL;OpenMPTarget)
# Because there is always an exception to the rule
if(Tag STREQUAL "Threads")
set(DEVICE "PTHREAD")
else()
string(TOUPPER ${Tag} DEVICE)
endif()
string(TOUPPER ${Tag} DEVICE)
string(TOLOWER ${Tag} dir)
if(Kokkos_ENABLE_${DEVICE})
set(dir ${CMAKE_CURRENT_BINARY_DIR})
set(file ${dir}/Test${Tag}.cpp)
# Write to a temporary intermediate file and call configure_file to avoid
# updating timestamps triggering unnecessary rebuilds on subsequent cmake runs.
file(WRITE ${dir}/dummy.cpp
"#include <Test${Tag}_Category.hpp>\n"
"#include <TestRandomCommon.hpp>\n"
"#include <TestSortCommon.hpp>\n"
set(dir ${CMAKE_CURRENT_BINARY_DIR}/${dir})
file(MAKE_DIRECTORY ${dir})
# -------------------------
# Sort1d,3d, Random
# -------------------------
set(SOURCES_A)
if(Tag STREQUAL "OpenMP")
LIST(APPEND SOURCES_A
TestOpenMP_Sort1D.cpp
TestOpenMP_Sort3D.cpp
TestOpenMP_SortDynamicView.cpp
)
endif()
set(file ${dir}/TestRandomAndSort.cpp)
# Write to a temporary intermediate file and call configure_file to avoid
# updating timestamps triggering unnecessary rebuilds on subsequent cmake runs.
file(WRITE ${dir}/dummy.cpp
"#include <Test${Tag}_Category.hpp>\n"
"#include <TestRandomCommon.hpp>\n"
"#include <TestSortCommon.hpp>\n"
)
configure_file(${dir}/dummy.cpp ${file})
list(APPEND ALGORITHM_SOURCES ${file})
configure_file(${dir}/dummy.cpp ${file})
list(APPEND SOURCES_A ${file})
# ------------------------------------------
# std set A
# ------------------------------------------
set(STDALGO_SOURCES_A)
foreach(Name
StdReducers
StdAlgorithmsConstraints
RandomAccessIterator
)
list(APPEND STDALGO_SOURCES_A Test${Name}.cpp)
endforeach()
# ------------------------------------------
# std set B
# ------------------------------------------
set(STDALGO_SOURCES_B)
foreach(Name
StdAlgorithmsCommon
StdAlgorithmsMinMaxElementOps
)
list(APPEND STDALGO_SOURCES_B Test${Name}.cpp)
endforeach()
# ------------------------------------------
# std set C
# ------------------------------------------
set(STDALGO_SOURCES_C)
foreach(Name
StdAlgorithmsCommon
StdAlgorithmsLexicographicalCompare
StdAlgorithmsForEach
StdAlgorithmsFind
StdAlgorithmsFindFirstOf
StdAlgorithmsFindEnd
StdAlgorithmsCount
StdAlgorithmsEqual
StdAlgorithmsAllAnyNoneOf
StdAlgorithmsAdjacentFind
StdAlgorithmsSearch
StdAlgorithmsSearch_n
StdAlgorithmsMismatch
)
list(APPEND STDALGO_SOURCES_C Test${Name}.cpp)
endforeach()
# ------------------------------------------
# std set D
# ------------------------------------------
set(STDALGO_SOURCES_D)
foreach(Name
StdAlgorithmsCommon
StdAlgorithmsModOps
StdAlgorithmsModSeqOps
StdAlgorithmsReplace
StdAlgorithmsReplaceIf
StdAlgorithmsReplaceCopy
StdAlgorithmsReplaceCopyIf
StdAlgorithmsCopyIf
StdAlgorithmsUnique
StdAlgorithmsUniqueCopy
StdAlgorithmsRemove
StdAlgorithmsRemoveIf
StdAlgorithmsRemoveCopy
StdAlgorithmsRemoveCopyIf
StdAlgorithmsRotate
StdAlgorithmsRotateCopy
StdAlgorithmsReverse
StdAlgorithmsShiftLeft
StdAlgorithmsShiftRight
)
list(APPEND STDALGO_SOURCES_D Test${Name}.cpp)
endforeach()
# ------------------------------------------
# std set E
# ------------------------------------------
set(STDALGO_SOURCES_E)
foreach(Name
StdAlgorithmsCommon
StdAlgorithmsIsSorted
StdAlgorithmsIsSortedUntil
StdAlgorithmsPartitioningOps
StdAlgorithmsPartitionCopy
StdAlgorithmsNumerics
StdAlgorithmsAdjacentDifference
StdAlgorithmsExclusiveScan
StdAlgorithmsInclusiveScan
StdAlgorithmsTransformUnaryOp
StdAlgorithmsTransformExclusiveScan
StdAlgorithmsTransformInclusiveScan
)
list(APPEND STDALGO_SOURCES_E Test${Name}.cpp)
endforeach()
endif()
endforeach()
KOKKOS_ADD_EXECUTABLE_AND_TEST(
UnitTest
UnitTest_RandomAndSort
SOURCES
UnitTestMain.cpp
${ALGORITHM_SOURCES}
${SOURCES_A}
)
foreach(ID A;B;C;D;E)
KOKKOS_ADD_EXECUTABLE_AND_TEST(
UnitTest_StdSet_${ID}
SOURCES
UnitTestMain.cpp
${STDALGO_SOURCES_${ID}}
)
endforeach()
KOKKOS_ADD_EXECUTABLE(
UnitTest_StdAlgoCompileOnly
SOURCES TestStdAlgorithmsCompileOnly.cpp
)

View File

@ -45,7 +45,7 @@ ifeq ($(KOKKOS_INTERNAL_USE_HIP), 1)
TEST_TARGETS += test-hip
endif
ifeq ($(KOKKOS_INTERNAL_USE_PTHREADS), 1)
ifeq ($(KOKKOS_INTERNAL_USE_THREADS), 1)
OBJ_THREADS = TestThreads.o UnitTestMain.o gtest-all.o
TARGETS += KokkosAlgorithms_UnitTest_Threads
TEST_TARGETS += test-threads

View File

@ -47,6 +47,7 @@
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <Kokkos_DynRankView.hpp>
#include <Kokkos_Timer.hpp>
#include <Kokkos_Core.hpp>
#include <Kokkos_Random.hpp>
@ -327,10 +328,6 @@ template <class RandomGenerator, class Scalar>
struct test_random_scalar {
using rnd_type = typename RandomGenerator::generator_type;
int pass_mean, pass_var, pass_covar;
int pass_hist1d_mean, pass_hist1d_var, pass_hist1d_covar;
int pass_hist3d_mean, pass_hist3d_var, pass_hist3d_covar;
test_random_scalar(
typename test_random_functor<RandomGenerator, int>::type_1d& density_1d,
typename test_random_functor<RandomGenerator, int>::type_3d& density_3d,
@ -357,18 +354,15 @@ struct test_random_scalar {
variance_expect / (result.variance / num_draws / 3) - 1.0;
double covariance_eps =
result.covariance / num_draws / 2 / variance_expect;
pass_mean = ((-tolerance < mean_eps) && (tolerance > mean_eps)) ? 1 : 0;
pass_var = ((-1.5 * tolerance < variance_eps) &&
(1.5 * tolerance > variance_eps))
? 1
: 0;
pass_covar = ((-2.0 * tolerance < covariance_eps) &&
(2.0 * tolerance > covariance_eps))
? 1
: 0;
cout << "Pass: " << pass_mean << " " << pass_var << " " << mean_eps << " "
<< variance_eps << " " << covariance_eps << " || " << tolerance
<< endl;
#if defined(KOKKOS_BHALF_T_IS_FLOAT) && !KOKKOS_BHALF_T_IS_FLOAT
if (!std::is_same<Scalar, Kokkos::Experimental::bhalf_t>::value) {
#endif
EXPECT_LT(std::abs(mean_eps), tolerance);
EXPECT_LT(std::abs(variance_eps), 1.5 * tolerance);
EXPECT_LT(std::abs(covariance_eps), 2.0 * tolerance);
#if defined(KOKKOS_BHALF_T_IS_FLOAT) && !KOKKOS_BHALF_T_IS_FLOAT
}
#endif
}
{
cout << " -- Testing 1-D histogram" << endl;
@ -399,17 +393,15 @@ struct test_random_scalar {
}
#endif
pass_hist1d_mean =
((-mean_eps_expect < mean_eps) && (mean_eps_expect > mean_eps)) ? 1
: 0;
pass_hist1d_var = ((-variance_eps_expect < variance_eps) &&
(variance_eps_expect > variance_eps))
? 1
: 0;
pass_hist1d_covar = ((-covariance_eps_expect < covariance_eps) &&
(covariance_eps_expect > covariance_eps))
? 1
: 0;
#if defined(KOKKOS_BHALF_T_IS_FLOAT) && !KOKKOS_BHALF_T_IS_FLOAT
if (!std::is_same<Scalar, Kokkos::Experimental::bhalf_t>::value) {
#endif
EXPECT_LT(std::abs(mean_eps), mean_eps_expect);
EXPECT_LT(std::abs(variance_eps), variance_eps_expect);
EXPECT_LT(std::abs(covariance_eps), covariance_eps_expect);
#if defined(KOKKOS_BHALF_T_IS_FLOAT) && !KOKKOS_BHALF_T_IS_FLOAT
}
#endif
cout << "Density 1D: " << mean_eps << " " << variance_eps << " "
<< (result.covariance / HIST_DIM1D / HIST_DIM1D) << " || "
@ -445,16 +437,15 @@ struct test_random_scalar {
}
#endif
pass_hist3d_mean =
((-tolerance < mean_eps) && (tolerance > mean_eps)) ? 1 : 0;
pass_hist3d_var = ((-variance_factor * tolerance < variance_eps) &&
(variance_factor * tolerance > variance_eps))
? 1
: 0;
pass_hist3d_covar = ((-variance_factor * tolerance < covariance_eps) &&
(variance_factor * tolerance > covariance_eps))
? 1
: 0;
#if defined(KOKKOS_BHALF_T_IS_FLOAT) && !KOKKOS_BHALF_T_IS_FLOAT
if (!std::is_same<Scalar, Kokkos::Experimental::bhalf_t>::value) {
#endif
EXPECT_LT(std::abs(mean_eps), tolerance);
EXPECT_LT(std::abs(variance_eps), variance_factor);
EXPECT_LT(std::abs(covariance_eps), variance_factor);
#if defined(KOKKOS_BHALF_T_IS_FLOAT) && !KOKKOS_BHALF_T_IS_FLOAT
}
#endif
cout << "Density 3D: " << mean_eps << " " << variance_eps << " "
<< result.covariance / HIST_DIM1D / HIST_DIM1D << " || " << tolerance
@ -479,106 +470,79 @@ void test_random(unsigned int num_draws) {
cout << "Test Scalar=int" << endl;
test_random_scalar<RandomGenerator, int> test_int(density_1d, density_3d,
pool, num_draws);
ASSERT_EQ(test_int.pass_mean, 1);
ASSERT_EQ(test_int.pass_var, 1);
ASSERT_EQ(test_int.pass_covar, 1);
ASSERT_EQ(test_int.pass_hist1d_mean, 1);
ASSERT_EQ(test_int.pass_hist1d_var, 1);
ASSERT_EQ(test_int.pass_hist1d_covar, 1);
ASSERT_EQ(test_int.pass_hist3d_mean, 1);
ASSERT_EQ(test_int.pass_hist3d_var, 1);
ASSERT_EQ(test_int.pass_hist3d_covar, 1);
deep_copy(density_1d, 0);
deep_copy(density_3d, 0);
cout << "Test Scalar=unsigned int" << endl;
test_random_scalar<RandomGenerator, unsigned int> test_uint(
density_1d, density_3d, pool, num_draws);
ASSERT_EQ(test_uint.pass_mean, 1);
ASSERT_EQ(test_uint.pass_var, 1);
ASSERT_EQ(test_uint.pass_covar, 1);
ASSERT_EQ(test_uint.pass_hist1d_mean, 1);
ASSERT_EQ(test_uint.pass_hist1d_var, 1);
ASSERT_EQ(test_uint.pass_hist1d_covar, 1);
ASSERT_EQ(test_uint.pass_hist3d_mean, 1);
ASSERT_EQ(test_uint.pass_hist3d_var, 1);
ASSERT_EQ(test_uint.pass_hist3d_covar, 1);
deep_copy(density_1d, 0);
deep_copy(density_3d, 0);
cout << "Test Scalar=int64_t" << endl;
test_random_scalar<RandomGenerator, int64_t> test_int64(
density_1d, density_3d, pool, num_draws);
ASSERT_EQ(test_int64.pass_mean, 1);
ASSERT_EQ(test_int64.pass_var, 1);
ASSERT_EQ(test_int64.pass_covar, 1);
ASSERT_EQ(test_int64.pass_hist1d_mean, 1);
ASSERT_EQ(test_int64.pass_hist1d_var, 1);
ASSERT_EQ(test_int64.pass_hist1d_covar, 1);
ASSERT_EQ(test_int64.pass_hist3d_mean, 1);
ASSERT_EQ(test_int64.pass_hist3d_var, 1);
ASSERT_EQ(test_int64.pass_hist3d_covar, 1);
deep_copy(density_1d, 0);
deep_copy(density_3d, 0);
cout << "Test Scalar=uint64_t" << endl;
test_random_scalar<RandomGenerator, uint64_t> test_uint64(
density_1d, density_3d, pool, num_draws);
ASSERT_EQ(test_uint64.pass_mean, 1);
ASSERT_EQ(test_uint64.pass_var, 1);
ASSERT_EQ(test_uint64.pass_covar, 1);
ASSERT_EQ(test_uint64.pass_hist1d_mean, 1);
ASSERT_EQ(test_uint64.pass_hist1d_var, 1);
ASSERT_EQ(test_uint64.pass_hist1d_covar, 1);
ASSERT_EQ(test_uint64.pass_hist3d_mean, 1);
ASSERT_EQ(test_uint64.pass_hist3d_var, 1);
ASSERT_EQ(test_uint64.pass_hist3d_covar, 1);
deep_copy(density_1d, 0);
deep_copy(density_3d, 0);
cout << "Test Scalar=half" << endl;
test_random_scalar<RandomGenerator, Kokkos::Experimental::half_t> test_half(
density_1d, density_3d, pool, num_draws);
ASSERT_EQ(test_half.pass_mean, 1);
ASSERT_EQ(test_half.pass_var, 1);
ASSERT_EQ(test_half.pass_covar, 1);
ASSERT_EQ(test_half.pass_hist1d_mean, 1);
ASSERT_EQ(test_half.pass_hist1d_var, 1);
ASSERT_EQ(test_half.pass_hist1d_covar, 1);
ASSERT_EQ(test_half.pass_hist3d_mean, 1);
ASSERT_EQ(test_half.pass_hist3d_var, 1);
ASSERT_EQ(test_half.pass_hist3d_covar, 1);
deep_copy(density_1d, 0);
deep_copy(density_3d, 0);
cout << "Test Scalar=bhalf" << endl;
test_random_scalar<RandomGenerator, Kokkos::Experimental::bhalf_t> test_bhalf(
density_1d, density_3d, pool, num_draws);
deep_copy(density_1d, 0);
deep_copy(density_3d, 0);
cout << "Test Scalar=float" << endl;
test_random_scalar<RandomGenerator, float> test_float(density_1d, density_3d,
pool, num_draws);
ASSERT_EQ(test_float.pass_mean, 1);
ASSERT_EQ(test_float.pass_var, 1);
ASSERT_EQ(test_float.pass_covar, 1);
ASSERT_EQ(test_float.pass_hist1d_mean, 1);
ASSERT_EQ(test_float.pass_hist1d_var, 1);
ASSERT_EQ(test_float.pass_hist1d_covar, 1);
ASSERT_EQ(test_float.pass_hist3d_mean, 1);
ASSERT_EQ(test_float.pass_hist3d_var, 1);
ASSERT_EQ(test_float.pass_hist3d_covar, 1);
deep_copy(density_1d, 0);
deep_copy(density_3d, 0);
cout << "Test Scalar=double" << endl;
test_random_scalar<RandomGenerator, double> test_double(
density_1d, density_3d, pool, num_draws);
ASSERT_EQ(test_double.pass_mean, 1);
ASSERT_EQ(test_double.pass_var, 1);
ASSERT_EQ(test_double.pass_covar, 1);
ASSERT_EQ(test_double.pass_hist1d_mean, 1);
ASSERT_EQ(test_double.pass_hist1d_var, 1);
ASSERT_EQ(test_double.pass_hist1d_covar, 1);
ASSERT_EQ(test_double.pass_hist3d_mean, 1);
ASSERT_EQ(test_double.pass_hist3d_var, 1);
ASSERT_EQ(test_double.pass_hist3d_covar, 1);
}
template <class ExecutionSpace, class Pool>
struct TestDynRankView {
using ReducerType = Kokkos::MinMax<double, Kokkos::HostSpace>;
using ReducerValueType = typename ReducerType::value_type;
Kokkos::DynRankView<double, ExecutionSpace> A;
TestDynRankView(int n) : A("a", n) {}
KOKKOS_FUNCTION void operator()(int i, ReducerValueType& update) const {
if (A(i) < update.min_val) update.min_val = A(i);
if (A(i) > update.max_val) update.max_val = A(i);
}
void run() {
Pool random(13);
double min = 10.;
double max = 100.;
Kokkos::fill_random(A, random, min, max);
ReducerValueType val;
Kokkos::parallel_reduce(Kokkos::RangePolicy<ExecutionSpace>(0, A.size()),
*this, ReducerType(val));
Kokkos::fence();
ASSERT_GE(val.min_val, min);
ASSERT_LE(val.max_val, max);
}
};
} // namespace Impl
template <typename ExecutionSpace>
@ -593,6 +557,9 @@ void test_random_xorshift64() {
Impl::test_random<Kokkos::Random_XorShift64_Pool<
Kokkos::Device<ExecutionSpace, typename ExecutionSpace::memory_space>>>(
num_draws);
Impl::TestDynRankView<ExecutionSpace,
Kokkos::Random_XorShift64_Pool<ExecutionSpace>>(10000)
.run();
}
template <typename ExecutionSpace>
@ -608,6 +575,9 @@ void test_random_xorshift1024() {
Impl::test_random<Kokkos::Random_XorShift1024_Pool<
Kokkos::Device<ExecutionSpace, typename ExecutionSpace::memory_space>>>(
num_draws);
Impl::TestDynRankView<ExecutionSpace,
Kokkos::Random_XorShift1024_Pool<ExecutionSpace>>(10000)
.run();
}
} // namespace Test

View File

@ -0,0 +1,252 @@
/*
//@HEADER
// ************************************************************************
//
// Kokkos v. 3.0
// Copyright (2020) 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.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the Corporation nor the names of the
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Questions? Contact Christian R. Trott (crtrott@sandia.gov)
//
// ************************************************************************
//@HEADER
*/
#include <TestStdAlgorithmsCommon.hpp>
#include <std_algorithms/Kokkos_BeginEnd.hpp>
#include <std_algorithms/Kokkos_RandomAccessIterator.hpp>
#include <std_algorithms/Kokkos_Distance.hpp>
namespace KE = Kokkos::Experimental;
namespace Test {
namespace stdalgos {
struct random_access_iterator_test : std_algorithms_test {
public:
virtual void SetUp() {
Kokkos::parallel_for(m_static_view.extent(0),
AssignIndexFunctor<static_view_t>(m_static_view));
Kokkos::parallel_for(m_static_view.extent(0),
AssignIndexFunctor<dyn_view_t>(m_dynamic_view));
Kokkos::parallel_for(m_static_view.extent(0),
AssignIndexFunctor<strided_view_t>(m_strided_view));
}
};
TEST_F(random_access_iterator_test, constructor) {
// just tests that constructor works
auto it1 = KE::Impl::RandomAccessIterator<static_view_t>(m_static_view);
auto it2 = KE::Impl::RandomAccessIterator<dyn_view_t>(m_dynamic_view);
auto it3 = KE::Impl::RandomAccessIterator<strided_view_t>(m_strided_view);
auto it4 = KE::Impl::RandomAccessIterator<static_view_t>(m_static_view, 3);
auto it5 = KE::Impl::RandomAccessIterator<dyn_view_t>(m_dynamic_view, 3);
auto it6 = KE::Impl::RandomAccessIterator<strided_view_t>(m_strided_view, 3);
EXPECT_TRUE(true);
}
template <class IteratorType, class ValueType>
void test_random_access_it_verify(IteratorType it, ValueType gold_value) {
using view_t = Kokkos::View<typename IteratorType::value_type>;
view_t checkView("checkView");
CopyFromIteratorFunctor<IteratorType, view_t> cf(it, checkView);
Kokkos::parallel_for("_std_algo_copy", 1, cf);
auto v_h =
Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), checkView);
EXPECT_EQ(v_h(), gold_value);
}
TEST_F(random_access_iterator_test, dereference) {
auto it1 = KE::Impl::RandomAccessIterator<static_view_t>(m_static_view);
auto it2 = KE::Impl::RandomAccessIterator<dyn_view_t>(m_dynamic_view);
auto it3 = KE::Impl::RandomAccessIterator<strided_view_t>(m_strided_view);
test_random_access_it_verify(it1, (value_type)0);
test_random_access_it_verify(it2, (value_type)0);
test_random_access_it_verify(it3, (value_type)0);
auto it4 = KE::Impl::RandomAccessIterator<static_view_t>(m_static_view, 3);
auto it5 = KE::Impl::RandomAccessIterator<dyn_view_t>(m_dynamic_view, 4);
auto it6 = KE::Impl::RandomAccessIterator<strided_view_t>(m_strided_view, 5);
test_random_access_it_verify(it4, (value_type)3);
test_random_access_it_verify(it5, (value_type)4);
test_random_access_it_verify(it6, (value_type)5);
}
template <class ItTypeFrom, class ViewTypeTo>
struct CopyFromIteratorUsingSubscriptFunctor {
ItTypeFrom m_itFrom;
ViewTypeTo m_viewTo;
CopyFromIteratorUsingSubscriptFunctor(const ItTypeFrom itFromIn,
const ViewTypeTo viewToIn)
: m_itFrom(itFromIn), m_viewTo(viewToIn) {}
KOKKOS_INLINE_FUNCTION
void operator()(int i) const { m_viewTo(i) = m_itFrom[i]; }
};
template <class IteratorType>
void test_random_access_it_subscript_op_verify(IteratorType it) {
using value_t = typename IteratorType::value_type;
using view_t = Kokkos::View<value_t*>;
view_t checkView("checkView", 3);
CopyFromIteratorUsingSubscriptFunctor<IteratorType, view_t> cf(it, checkView);
Kokkos::parallel_for("_std_algo_copy", 3, cf);
auto v_h =
Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), checkView);
EXPECT_EQ(v_h(0), (value_t)0);
EXPECT_EQ(v_h(1), (value_t)1);
EXPECT_EQ(v_h(2), (value_t)2);
}
TEST_F(random_access_iterator_test, subscript_operator) {
auto it1 = KE::Impl::RandomAccessIterator<static_view_t>(m_static_view);
auto it2 = KE::Impl::RandomAccessIterator<dyn_view_t>(m_dynamic_view);
auto it3 = KE::Impl::RandomAccessIterator<strided_view_t>(m_strided_view);
test_random_access_it_subscript_op_verify(it1);
test_random_access_it_subscript_op_verify(it2);
test_random_access_it_subscript_op_verify(it3);
}
TEST_F(random_access_iterator_test, operatorsSet1) {
auto it1 = KE::Impl::RandomAccessIterator<static_view_t>(m_static_view, 3);
auto it2 = KE::Impl::RandomAccessIterator<dyn_view_t>(m_dynamic_view, 3);
auto it3 = KE::Impl::RandomAccessIterator<strided_view_t>(m_strided_view, 3);
++it1;
++it2;
++it3;
test_random_access_it_verify(it1, (value_type)4);
test_random_access_it_verify(it2, (value_type)4);
test_random_access_it_verify(it3, (value_type)4);
--it1;
--it2;
--it3;
test_random_access_it_verify(it1, (value_type)3);
test_random_access_it_verify(it2, (value_type)3);
test_random_access_it_verify(it3, (value_type)3);
}
TEST_F(random_access_iterator_test, operatorsSet2) {
auto it1 = KE::Impl::RandomAccessIterator<static_view_t>(m_static_view, 3);
auto it2 = KE::Impl::RandomAccessIterator<dyn_view_t>(m_dynamic_view, 3);
auto it3 = KE::Impl::RandomAccessIterator<strided_view_t>(m_strided_view, 3);
auto it11 = it1 + 3;
auto it21 = it2 + 3;
auto it31 = it3 + 3;
test_random_access_it_verify(it11, (value_type)6);
test_random_access_it_verify(it21, (value_type)6);
test_random_access_it_verify(it31, (value_type)6);
auto it12 = it11 - 4;
auto it22 = it21 - 4;
auto it32 = it31 - 4;
test_random_access_it_verify(it12, (value_type)2);
test_random_access_it_verify(it22, (value_type)2);
test_random_access_it_verify(it32, (value_type)2);
}
TEST_F(random_access_iterator_test, operatorsSet3) {
auto it1 = KE::Impl::RandomAccessIterator<static_view_t>(m_static_view, 3);
auto it2 = KE::Impl::RandomAccessIterator<dyn_view_t>(m_dynamic_view, 3);
auto it3 = KE::Impl::RandomAccessIterator<strided_view_t>(m_strided_view, 3);
it1 += 3;
it2 += 3;
it3 += 3;
test_random_access_it_verify(it1, (value_type)6);
test_random_access_it_verify(it2, (value_type)6);
test_random_access_it_verify(it3, (value_type)6);
it1 -= 4;
it2 -= 4;
it3 -= 4;
test_random_access_it_verify(it1, (value_type)2);
test_random_access_it_verify(it2, (value_type)2);
test_random_access_it_verify(it3, (value_type)2);
}
TEST_F(random_access_iterator_test, operatorsSet4) {
auto it1 = KE::Impl::RandomAccessIterator<static_view_t>(m_static_view, 3);
auto it2 = KE::Impl::RandomAccessIterator<dyn_view_t>(m_dynamic_view, 3);
auto it3 = KE::Impl::RandomAccessIterator<strided_view_t>(m_strided_view, 3);
auto it4 = KE::Impl::RandomAccessIterator<static_view_t>(m_static_view, 4);
auto it5 = KE::Impl::RandomAccessIterator<dyn_view_t>(m_dynamic_view, 4);
auto it6 = KE::Impl::RandomAccessIterator<strided_view_t>(m_strided_view, 4);
EXPECT_TRUE(it1 != it4);
EXPECT_TRUE(it2 != it5);
EXPECT_TRUE(it3 != it6);
EXPECT_TRUE(it1 < it4);
EXPECT_TRUE(it2 < it5);
EXPECT_TRUE(it3 < it6);
EXPECT_TRUE(it1 <= it4);
EXPECT_TRUE(it2 <= it5);
EXPECT_TRUE(it3 <= it6);
auto it7 = KE::Impl::RandomAccessIterator<static_view_t>(m_static_view, 3);
auto it8 = KE::Impl::RandomAccessIterator<dyn_view_t>(m_dynamic_view, 3);
auto it9 = KE::Impl::RandomAccessIterator<strided_view_t>(m_strided_view, 3);
EXPECT_TRUE(it1 == it7);
EXPECT_TRUE(it2 == it8);
EXPECT_TRUE(it3 == it9);
EXPECT_TRUE(it1 >= it7);
EXPECT_TRUE(it2 >= it8);
EXPECT_TRUE(it3 >= it9);
EXPECT_TRUE(it4 > it7);
EXPECT_TRUE(it5 > it8);
EXPECT_TRUE(it6 > it9);
}
TEST_F(random_access_iterator_test, assignment_operator) {
auto it1 = KE::Impl::RandomAccessIterator<static_view_t>(m_static_view, 3);
auto it2 = KE::Impl::RandomAccessIterator<static_view_t>(m_static_view, 5);
EXPECT_NE(it1, it2);
it2 = it1;
EXPECT_EQ(it1, it2);
}
TEST_F(random_access_iterator_test, distance) {
auto first = KE::begin(m_dynamic_view);
auto last = KE::end(m_dynamic_view);
EXPECT_EQ(0, KE::distance(first, first));
EXPECT_EQ(1, KE::distance(first, first + 1));
EXPECT_EQ(m_dynamic_view.extent(0), size_t(KE::distance(first, last)));
}
} // namespace stdalgos
} // namespace Test

View File

@ -164,8 +164,8 @@ void test_1D_sort_impl(unsigned int n, bool force_kokkos) {
unsigned int equal_sum =
(ratio > (1.0 - epsilon)) && (ratio < (1.0 + epsilon)) ? 1 : 0;
ASSERT_EQ(sort_fails, 0);
ASSERT_EQ(equal_sum, 1);
ASSERT_EQ(sort_fails, 0u);
ASSERT_EQ(equal_sum, 1u);
}
template <class ExecutionSpace, typename KeyType>
@ -215,8 +215,8 @@ void test_3D_sort_impl(unsigned int n) {
if (sort_fails)
printf("3D Sort Sum: %f %f Fails: %u\n", sum_before, sum_after, sort_fails);
ASSERT_EQ(sort_fails, 0);
ASSERT_EQ(equal_sum, 1);
ASSERT_EQ(sort_fails, 0u);
ASSERT_EQ(equal_sum, 1u);
}
//----------------------------------------------------------------------------
@ -279,8 +279,8 @@ void test_dynamic_view_sort_impl(unsigned int n) {
<< std::endl;
}
ASSERT_EQ(sort_fails, 0);
ASSERT_EQ(equal_sum, 1);
ASSERT_EQ(sort_fails, 0u);
ASSERT_EQ(equal_sum, 1u);
}
//----------------------------------------------------------------------------

View File

@ -0,0 +1,293 @@
/*
//@HEADER
// ************************************************************************
//
// Kokkos v. 3.0
// Copyright (2020) 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.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the Corporation nor the names of the
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Questions? Contact Christian R. Trott (crtrott@sandia.gov)
//
// ************************************************************************
//@HEADER
*/
#include <TestStdAlgorithmsCommon.hpp>
#include <std_algorithms/Kokkos_BeginEnd.hpp>
#include <std_algorithms/Kokkos_Numeric.hpp>
#include <utility>
#include <numeric>
namespace Test {
namespace stdalgos {
namespace AdjacentDifference {
namespace KE = Kokkos::Experimental;
template <class DestViewType>
void fill_view(DestViewType dest_view, const std::string& name) {
// we need to be careful because dest_view might not be deep copyable
// for instance strided layout
using value_type = typename DestViewType::value_type;
const std::size_t ext = dest_view.extent(0);
auto aux_view =
create_deep_copyable_compatible_view_with_same_extent(dest_view);
auto aux_v_h = create_mirror_view(Kokkos::HostSpace(), aux_view);
if (name == "empty") {
// no op
}
else if (name == "one-element") {
aux_v_h(0) = static_cast<value_type>(1);
}
else if (name == "two-elements-a") {
aux_v_h(0) = static_cast<value_type>(1);
aux_v_h(1) = static_cast<value_type>(2);
}
else if (name == "two-elements-b") {
aux_v_h(0) = static_cast<value_type>(2);
aux_v_h(1) = static_cast<value_type>(-1);
}
else if (name == "small-a") {
for (std::size_t i = 0; i < ext; ++i) {
aux_v_h(i) = static_cast<value_type>(i) * 2;
}
}
else if (name == "small-b") {
for (std::size_t i = 0; i < ext; ++i) {
aux_v_h(i) = static_cast<value_type>(i) * 3;
}
aux_v_h(5) = static_cast<value_type>(-15);
}
else if (name == "medium-a") {
for (std::size_t i = 0; i < ext; ++i) {
aux_v_h(i) = static_cast<value_type>(i) * 2;
}
}
else if (name == "medium-b") {
for (std::size_t i = 0; i < ext; ++i) {
aux_v_h(i) = static_cast<value_type>(i) * 2;
}
aux_v_h(4) = static_cast<value_type>(-1);
}
else if (name == "large-a") {
for (std::size_t i = 0; i < ext; ++i) {
aux_v_h(i) = static_cast<value_type>(-100) + static_cast<value_type>(i);
}
}
else if (name == "large-b") {
for (std::size_t i = 0; i < ext; ++i) {
aux_v_h(i) = static_cast<value_type>(-100) + static_cast<value_type>(i);
}
aux_v_h(156) = static_cast<value_type>(-250);
}
else {
throw std::runtime_error("invalid choice");
}
Kokkos::deep_copy(aux_view, aux_v_h);
CopyFunctor<decltype(aux_view), DestViewType> F1(aux_view, dest_view);
Kokkos::parallel_for("copy", dest_view.extent(0), F1);
}
template <class TestViewType, class... Args>
auto compute_gold(TestViewType test_view, const std::string& name,
Args... args /* copy on purpose */) {
// we need to be careful because test_view might not be deep copyable
// for instance strided layout
const std::size_t ext = test_view.extent(0);
// create a deep copyable clone of test_view
auto test_view_dc = create_deep_copyable_compatible_clone(test_view);
auto test_view_dc_h =
create_mirror_view_and_copy(Kokkos::HostSpace(), test_view_dc);
// create gold deep copyable view
auto gold_view =
create_deep_copyable_compatible_view_with_same_extent(test_view);
auto gold_view_h = create_mirror_view(Kokkos::HostSpace(), gold_view);
// compute gold solution on host and deep copy to device
if (name == "empty") {
return gold_view;
} else {
using value_type = typename TestViewType::value_type;
std::vector<value_type> tmp(ext);
for (std::size_t i = 0; i < ext; ++i) {
tmp[i] = test_view_dc_h(i);
}
// run adj-diff on tmp directly
std::adjacent_difference(tmp.begin(), tmp.end(), tmp.begin(),
std::forward<Args>(args)...);
// copy from tmp to gold_h
for (std::size_t i = 0; i < ext; ++i) {
gold_view_h(i) = tmp[i];
}
// deep_copy to device
Kokkos::deep_copy(gold_view, gold_view_h);
return gold_view;
}
}
template <class TestViewType, class GoldViewType>
void verify_data(TestViewType test_view, GoldViewType gold) {
// we need to be careful because test_view might not be deep copyable
// for instance strided layout
auto test_view_dc = create_deep_copyable_compatible_clone(test_view);
auto test_view_dc_h =
create_mirror_view_and_copy(Kokkos::HostSpace(), test_view_dc);
// gold is deep_copyable for sure
const auto gold_h = create_mirror_view_and_copy(Kokkos::HostSpace(), gold);
for (std::size_t i = 0; i < test_view.extent(0); ++i) {
EXPECT_TRUE(gold_h(i) == test_view_dc_h(i));
}
}
template <class ValueType1, class ValueType2 = ValueType1,
class RetType = ValueType2>
struct CustomBinaryOpFunctor {
KOKKOS_INLINE_FUNCTION
RetType operator()(const ValueType1& a, const ValueType2& b) const {
return a * b;
}
};
template <class ValueType1, class ValueType2 = ValueType1,
class RetType = ValueType2>
struct DefaultBinaryOpFunctor {
KOKKOS_INLINE_FUNCTION
RetType operator()(const ValueType1& a, const ValueType2& b) const {
return a - b;
}
};
template <class Tag, class ValueType, class InfoType, class... Args>
void run_single_scenario(const InfoType& scenario_info,
Args... args /* copy on purpose */) {
const auto name = std::get<0>(scenario_info);
const std::size_t view_ext = std::get<1>(scenario_info);
auto view_from =
create_view<ValueType>(Tag{}, view_ext, "adj_diff_from_view");
fill_view(view_from, name);
const auto gold = compute_gold(view_from, name, args...);
{
auto view_dest =
create_view<ValueType>(Tag{}, view_ext, "adj_diff_dest_view");
auto res1 = KE::adjacent_difference(exespace(), KE::cbegin(view_from),
KE::cend(view_from),
KE::begin(view_dest), args...);
EXPECT_TRUE(res1 == KE::end(view_dest));
verify_data(view_dest, gold);
}
{
auto view_dest =
create_view<ValueType>(Tag{}, view_ext, "adj_diff_dest_view");
auto res2 = KE::adjacent_difference(
"label", exespace(), KE::cbegin(view_from), KE::cend(view_from),
KE::begin(view_dest), args...);
EXPECT_TRUE(res2 == KE::end(view_dest));
verify_data(view_dest, gold);
}
{
auto view_dest =
create_view<ValueType>(Tag{}, view_ext, "adj_diff_dest_view");
auto res3 =
KE::adjacent_difference(exespace(), view_from, view_dest, args...);
EXPECT_TRUE(res3 == KE::end(view_dest));
verify_data(view_dest, gold);
}
{
auto view_dest =
create_view<ValueType>(Tag{}, view_ext, "adj_diff_dest_view");
auto res4 = KE::adjacent_difference("label", exespace(), view_from,
view_dest, args...);
EXPECT_TRUE(res4 == KE::end(view_dest));
verify_data(view_dest, gold);
}
Kokkos::fence();
}
template <class Tag, class ValueType, class... Args>
void run_all_scenarios(Args... args /* copy on purpose */) {
// if (0 < sizeof...(args)) {
// std::cout << "adjacent_difference: " << view_tag_to_string(Tag{})
// << ", custom binary op, all overloads \n";
// } else {
// std::cout << "adjacent_difference: " << view_tag_to_string(Tag{})
// << ", default binary op, all overloads \n";
// }
for (const auto& it : default_scenarios) {
run_single_scenario<Tag, ValueType>(it, args...);
}
}
TEST(std_algorithms_numerics_ops_test, adjecent_difference) {
using value_type = double;
run_all_scenarios<DynamicTag, value_type>();
run_all_scenarios<StridedTwoTag, value_type>();
run_all_scenarios<StridedThreeTag, value_type>();
using custom_binary_op = CustomBinaryOpFunctor<value_type>;
run_all_scenarios<DynamicTag, value_type>(custom_binary_op{});
run_all_scenarios<StridedTwoTag, value_type>(custom_binary_op{});
run_all_scenarios<StridedThreeTag, value_type>(custom_binary_op{});
}
} // namespace AdjacentDifference
} // namespace stdalgos
} // namespace Test

View File

@ -0,0 +1,325 @@
/*
//@HEADER
// ************************************************************************
//
// Kokkos v. 3.0
// Copyright (2020) 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.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the Corporation nor the names of the
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Questions? Contact Christian R. Trott (crtrott@sandia.gov)
//
// ************************************************************************
//@HEADER
*/
#include <TestStdAlgorithmsCommon.hpp>
#include <std_algorithms/Kokkos_BeginEnd.hpp>
#include <std_algorithms/Kokkos_NonModifyingSequenceOperations.hpp>
#include <utility>
namespace Test {
namespace stdalgos {
namespace AdjacentFind {
namespace KE = Kokkos::Experimental;
// impl is here for std because it is only avail from c++>=17
template <class InputIterator, class OutputIterator, class BinaryPredicate>
auto my_unique_copy(InputIterator first, InputIterator last,
OutputIterator result, BinaryPredicate pred) {
if (first != last) {
typename OutputIterator::value_type t(*first);
*result = t;
++result;
while (++first != last) {
if (!pred(t, *first)) {
t = *first;
*result = t;
++result;
}
}
}
return result;
}
template <class InputIterator, class OutputIterator>
auto my_unique_copy(InputIterator first, InputIterator last,
OutputIterator result) {
using value_type = typename OutputIterator::value_type;
using func_t = IsEqualFunctor<value_type>;
return my_unique_copy(first, last, result, func_t());
}
template <class ValueType>
struct UnifDist;
template <>
struct UnifDist<int> {
using dist_type = std::uniform_int_distribution<int>;
std::mt19937 m_gen;
dist_type m_dist;
// make bounds tight so that it is likely we get
// consecutive equal elements
UnifDist() : m_dist(2, 8) { m_gen.seed(345823); }
int operator()() { return m_dist(m_gen); }
};
template <>
struct UnifDist<double> {
using dist_type = std::uniform_real_distribution<double>;
std::mt19937 m_gen;
dist_type m_dist;
// make bounds tight so that it is likely we get
// consecutive equal elements
UnifDist() : m_dist(2, 8) { m_gen.seed(345823); }
double operator()() { return m_dist(m_gen); }
};
template <class ViewType>
void fill_view(ViewType dest_view, const std::string& name) {
using value_type = typename ViewType::value_type;
using exe_space = typename ViewType::execution_space;
const std::size_t ext = dest_view.extent(0);
using aux_view_t = Kokkos::View<value_type*, exe_space>;
aux_view_t aux_view("aux_view", ext);
auto v_h = create_mirror_view(Kokkos::HostSpace(), aux_view);
if (name == "empty") {
// no op
}
else if (name == "one-element-a") {
v_h(0) = static_cast<value_type>(1);
}
else if (name == "one-element-b") {
v_h(0) = static_cast<value_type>(2);
}
else if (name == "two-elements-a") {
v_h(0) = static_cast<value_type>(1);
v_h(1) = static_cast<value_type>(2);
}
else if (name == "two-elements-b") {
v_h(0) = static_cast<value_type>(2);
v_h(1) = static_cast<value_type>(-1);
}
else if (name == "small-a") {
v_h(0) = static_cast<value_type>(0);
v_h(1) = static_cast<value_type>(1);
v_h(2) = static_cast<value_type>(2);
v_h(3) = static_cast<value_type>(3);
v_h(4) = static_cast<value_type>(2);
v_h(5) = static_cast<value_type>(5);
v_h(6) = static_cast<value_type>(4);
v_h(7) = static_cast<value_type>(4);
v_h(8) = static_cast<value_type>(5);
v_h(9) = static_cast<value_type>(6);
v_h(10) = static_cast<value_type>(6);
}
else if (name == "small-b") {
v_h(0) = static_cast<value_type>(1);
v_h(1) = static_cast<value_type>(1);
v_h(2) = static_cast<value_type>(1);
v_h(3) = static_cast<value_type>(2);
v_h(4) = static_cast<value_type>(3);
v_h(5) = static_cast<value_type>(4);
v_h(6) = static_cast<value_type>(4);
v_h(7) = static_cast<value_type>(4);
v_h(8) = static_cast<value_type>(5);
v_h(9) = static_cast<value_type>(6);
v_h(10) = static_cast<value_type>(8);
v_h(11) = static_cast<value_type>(9);
v_h(12) = static_cast<value_type>(8);
}
else if (name == "medium") {
// beginning just contains increasing values
for (std::size_t i = 0; i < 1000; ++i) {
v_h(i) = static_cast<value_type>(i);
}
// then use random
UnifDist<value_type> randObj;
for (std::size_t i = 1000; i < ext; ++i) {
v_h(i) = randObj();
}
}
else if (name == "large-a") {
// put equal elements at the end
for (std::size_t i = 0; i < ext; ++i) {
v_h(i) = static_cast<value_type>(i);
}
v_h(ext - 3) = static_cast<value_type>(44);
v_h(ext - 2) = static_cast<value_type>(44);
v_h(ext - 1) = static_cast<value_type>(44);
}
else if (name == "large-b") {
UnifDist<value_type> randObj;
for (std::size_t i = 0; i < ext; ++i) {
v_h(i) = randObj();
}
}
else {
throw std::runtime_error("invalid choice");
}
Kokkos::deep_copy(aux_view, v_h);
CopyFunctor<aux_view_t, ViewType> F1(aux_view, dest_view);
Kokkos::parallel_for("copy", dest_view.extent(0), F1);
}
template <class IteratorType, class BinaryPredicate>
IteratorType my_std_adjacent_find(IteratorType first, IteratorType last,
BinaryPredicate p) {
if (first == last) {
return last;
}
IteratorType next = first;
++next;
for (; next != last; ++next, ++first) {
if (p(*first, *next)) {
return first;
}
}
return last;
}
template <class IteratorType>
IteratorType my_std_adjacent_find(IteratorType first, IteratorType last) {
using value_type = typename IteratorType::value_type;
return my_std_adjacent_find(first, last, IsEqualFunctor<value_type>());
}
std::string value_type_to_string(int) { return "int"; }
std::string value_type_to_string(double) { return "double"; }
template <class Tag, class ValueType>
void print_scenario_details(const std::string& name) {
std::cout << "adjacent_find: default predicate: " << name << ", "
<< view_tag_to_string(Tag{}) << " "
<< value_type_to_string(ValueType()) << '\n';
}
template <class Tag, class ValueType, class Predicate>
void print_scenario_details(const std::string& name, Predicate pred) {
(void)pred;
std::cout << "adjacent_find: custom predicate: " << name << ", "
<< view_tag_to_string(Tag{}) << " "
<< value_type_to_string(ValueType()) << '\n';
}
template <class DiffType, class ViewType, class... Args>
void verify(DiffType my_diff, ViewType view, Args... args) {
auto view_dc = create_deep_copyable_compatible_clone(view);
auto view_h = create_mirror_view_and_copy(Kokkos::HostSpace(), view_dc);
auto std_r =
my_std_adjacent_find(KE::cbegin(view_h), KE::cend(view_h), args...);
const auto std_diff = std_r - KE::cbegin(view_h);
EXPECT_TRUE(my_diff == std_diff);
}
template <class Tag, class ValueType, class InfoType, class... Args>
void run_single_scenario(const InfoType& scenario_info, Args... args) {
const auto name = std::get<0>(scenario_info);
const std::size_t view_ext = std::get<1>(scenario_info);
// print_scenario_details<Tag, ValueType>(name, args...);
auto view = create_view<ValueType>(Tag{}, view_ext, "adjacent_find_view");
fill_view(view, name);
{
auto res_it = KE::adjacent_find(exespace(), KE::cbegin(view),
KE::cend(view), args...);
const auto my_diff = res_it - KE::cbegin(view);
verify(my_diff, view, args...);
}
{
auto res_it = KE::adjacent_find("label", exespace(), KE::cbegin(view),
KE::cend(view), args...);
const auto my_diff = res_it - KE::cbegin(view);
verify(my_diff, view, args...);
}
{
auto res_it = KE::adjacent_find(exespace(), view, args...);
const auto my_diff = res_it - KE::begin(view);
verify(my_diff, view, args...);
}
{
auto res_it = KE::adjacent_find("label", exespace(), view, args...);
const auto my_diff = res_it - KE::begin(view);
verify(my_diff, view, args...);
}
Kokkos::fence();
}
template <class Tag, class ValueType>
void run_all_scenarios() {
const std::map<std::string, std::size_t> scenarios = {
{"empty", 0}, {"one-element-a", 1}, {"one-element-b", 1},
{"two-elements-a", 2}, {"two-elements-b", 2}, {"small-a", 11},
{"small-b", 13}, {"medium", 21103}, {"large-a", 101513},
{"large-b", 100111}};
for (const auto& it : scenarios) {
run_single_scenario<Tag, ValueType>(it);
using func_t = IsEqualFunctor<ValueType>;
run_single_scenario<Tag, ValueType>(it, func_t());
}
}
TEST(std_algorithms_nonmod_seq_ops, adjacent_find) {
run_all_scenarios<DynamicTag, int>();
run_all_scenarios<DynamicTag, double>();
run_all_scenarios<StridedThreeTag, int>();
}
} // namespace AdjacentFind
} // namespace stdalgos
} // namespace Test

View File

@ -0,0 +1,183 @@
/*
//@HEADER
// ************************************************************************
//
// Kokkos v. 3.0
// Copyright (2020) 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.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the Corporation nor the names of the
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Questions? Contact Christian R. Trott (crtrott@sandia.gov)
//
// ************************************************************************
//@HEADER
*/
#include <TestStdAlgorithmsCommon.hpp>
#include <std_algorithms/Kokkos_BeginEnd.hpp>
#include <std_algorithms/Kokkos_NonModifyingSequenceOperations.hpp>
#include <algorithm>
namespace Test {
namespace stdalgos {
namespace AllAnyNoneOf {
namespace KE = Kokkos::Experimental;
template <class ViewType>
void test_all_of(const ViewType view) {
using value_t = typename ViewType::value_type;
using view_host_space_t = Kokkos::View<value_t*, Kokkos::HostSpace>;
const auto equals_zero = EqualsValFunctor<value_t>(0);
view_host_space_t expected("all_of_expected", view.extent(0));
compare_views(expected, view);
// reference result
EXPECT_TRUE(std::all_of(KE::begin(expected), KE::end(expected), equals_zero));
// pass iterators
EXPECT_TRUE(
KE::all_of(exespace(), KE::begin(view), KE::end(view), equals_zero));
// pass view
EXPECT_TRUE(KE::all_of(exespace(), view, equals_zero));
fill_views_inc(view, expected);
if (view.extent(0) > 1) {
// reference result
EXPECT_FALSE(
std::all_of(KE::begin(expected), KE::end(expected), equals_zero));
// pass const iterators
EXPECT_FALSE(
KE::all_of(exespace(), KE::cbegin(view), KE::cend(view), equals_zero));
// pass view
EXPECT_FALSE(KE::all_of("label", exespace(), view, equals_zero));
}
}
template <class ViewType>
void test_any_of(const ViewType view) {
using value_t = typename ViewType::value_type;
using view_host_space_t = Kokkos::View<value_t*, Kokkos::HostSpace>;
const auto not_equals_zero = NotEqualsZeroFunctor<value_t>();
view_host_space_t expected("any_of_expected", view.extent(0));
compare_views(expected, view);
// reference result
EXPECT_FALSE(
std::any_of(KE::begin(expected), KE::end(expected), not_equals_zero));
// pass iterators
EXPECT_FALSE(
KE::any_of(exespace(), KE::begin(view), KE::end(view), not_equals_zero));
// pass view
EXPECT_FALSE(KE::any_of(exespace(), view, not_equals_zero));
fill_views_inc(view, expected);
if (view.extent(0) > 1) {
// reference result
EXPECT_TRUE(
std::any_of(KE::begin(expected), KE::end(expected), not_equals_zero));
// pass const iterators
EXPECT_TRUE(KE::any_of(exespace(), KE::cbegin(view), KE::cend(view),
not_equals_zero));
// pass view
EXPECT_TRUE(KE::any_of("label", exespace(), view, not_equals_zero));
}
}
template <class ViewType>
void test_none_of(const ViewType view) {
using value_t = typename ViewType::value_type;
using view_host_space_t = Kokkos::View<value_t*, Kokkos::HostSpace>;
const auto is_positive = IsPositiveFunctor<value_t>();
view_host_space_t expected("none_of_expected", view.extent(0));
compare_views(expected, view);
// reference result
EXPECT_TRUE(
std::none_of(KE::begin(expected), KE::end(expected), is_positive));
// pass iterators
EXPECT_TRUE(
KE::none_of(exespace(), KE::begin(view), KE::end(view), is_positive));
// pass view
EXPECT_TRUE(KE::none_of(exespace(), view, is_positive));
fill_views_inc(view, expected);
if (view.extent(0) > 1) {
// reference result
EXPECT_FALSE(
std::none_of(KE::begin(expected), KE::end(expected), is_positive));
// pass const iterators
EXPECT_FALSE(
KE::none_of(exespace(), KE::cbegin(view), KE::cend(view), is_positive));
// pass view
EXPECT_FALSE(KE::none_of("label", exespace(), view, is_positive));
}
}
template <class Tag, class ValueType>
void run_all_scenarios() {
for (const auto& scenario : default_scenarios) {
{
auto view = create_view<ValueType>(Tag{}, scenario.second, "all_of");
test_all_of(view);
}
{
auto view = create_view<ValueType>(Tag{}, scenario.second, "any_of");
test_any_of(view);
}
{
auto view = create_view<ValueType>(Tag{}, scenario.second, "none_of");
test_none_of(view);
}
}
}
TEST(std_algorithms_all_any_none_of_test, test) {
run_all_scenarios<DynamicTag, double>();
run_all_scenarios<StridedTwoTag, int>();
run_all_scenarios<StridedThreeTag, unsigned>();
}
} // namespace AllAnyNoneOf
} // namespace stdalgos
} // namespace Test

View File

@ -0,0 +1,57 @@
/*
//@HEADER
// ************************************************************************
//
// Kokkos v. 3.0
// Copyright (2020) 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.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the Corporation nor the names of the
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Questions? Contact Christian R. Trott (crtrott@sandia.gov)
//
// ************************************************************************
//@HEADER
*/
#include <TestStdAlgorithmsCommon.hpp>
namespace Test {
namespace stdalgos {
std::string view_tag_to_string(DynamicTag) { return "dynamic_view"; }
std::string view_tag_to_string(StridedTwoTag) { return "stride2_view"; }
std::string view_tag_to_string(StridedThreeTag) { return "stride3_view"; }
} // namespace stdalgos
} // namespace Test

View File

@ -0,0 +1,255 @@
/*
//@HEADER
// ************************************************************************
//
// Kokkos v. 3.0
// Copyright (2020) 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.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the Corporation nor the names of the
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Questions? Contact Christian R. Trott (crtrott@sandia.gov)
//
// ************************************************************************
//@HEADER
*/
#ifndef KOKKOS_ALGORITHMS_UNITTESTS_TEST_STD_ALGOS_COMMON_HPP
#define KOKKOS_ALGORITHMS_UNITTESTS_TEST_STD_ALGOS_COMMON_HPP
#include <gtest/gtest.h>
#include <TestStdAlgorithmsHelperFunctors.hpp>
#include <std_algorithms/Kokkos_BeginEnd.hpp>
#include <numeric>
#include <random>
namespace Test {
namespace stdalgos {
using exespace = Kokkos::DefaultExecutionSpace;
struct DynamicTag {};
struct StridedTwoTag {};
struct StridedThreeTag {};
const std::map<std::string, std::size_t> default_scenarios = {
{"empty", 0}, {"one-element", 1}, {"two-elements-a", 2},
{"two-elements-b", 2}, {"small-a", 9}, {"small-b", 13},
{"medium-a", 1003}, {"medium-b", 1003}, {"large-a", 101513},
{"large-b", 101513}};
// see cpp file for these functions
std::string view_tag_to_string(DynamicTag);
std::string view_tag_to_string(StridedTwoTag);
std::string view_tag_to_string(StridedThreeTag);
template <class ValueType>
auto create_view(DynamicTag, std::size_t ext, const std::string label) {
using view_t = Kokkos::View<ValueType*>;
view_t view{label + "_" + view_tag_to_string(DynamicTag{}), ext};
return view;
}
template <class ValueType>
auto create_view(StridedTwoTag, std::size_t ext, const std::string label) {
using view_t = Kokkos::View<ValueType*, Kokkos::LayoutStride>;
Kokkos::LayoutStride layout{ext, 2};
view_t view{label + "_" + view_tag_to_string(DynamicTag{}), layout};
return view;
}
template <class ValueType>
auto create_view(StridedThreeTag, std::size_t ext, const std::string label) {
using view_t = Kokkos::View<ValueType*, Kokkos::LayoutStride>;
Kokkos::LayoutStride layout{ext, 3};
view_t view{label + "_" + view_tag_to_string(DynamicTag{}), layout};
return view;
}
template <class ViewType>
auto create_deep_copyable_compatible_view_with_same_extent(ViewType view) {
const std::size_t ext = view.extent(0);
using view_value_type = typename ViewType::value_type;
using view_exespace = typename ViewType::execution_space;
using view_deep_copyable_t = Kokkos::View<view_value_type*, view_exespace>;
view_deep_copyable_t view_dc("view_dc", ext);
return view_dc;
}
template <class ViewType>
auto create_deep_copyable_compatible_clone(ViewType view) {
auto view_dc = create_deep_copyable_compatible_view_with_same_extent(view);
using view_dc_t = decltype(view_dc);
CopyFunctor<ViewType, view_dc_t> F1(view, view_dc);
Kokkos::parallel_for("copy", view.extent(0), F1);
return view_dc;
}
template <class ViewType>
auto create_host_space_copy(ViewType view) {
auto view_dc = create_deep_copyable_compatible_clone(view);
return create_mirror_view_and_copy(Kokkos::HostSpace(), view_dc);
}
// fill the views with sequentially increasing values
template <class ViewType, class ViewHostType>
void fill_views_inc(ViewType view, ViewHostType host_view) {
namespace KE = Kokkos::Experimental;
Kokkos::parallel_for(view.extent(0), AssignIndexFunctor<ViewType>(view));
std::iota(KE::begin(host_view), KE::end(host_view), 0);
// compare_views(expected, view);
}
template <class ValueType, class ViewType>
std::enable_if_t<!std::is_same<typename ViewType::traits::array_layout,
Kokkos::LayoutStride>::value>
verify_values(ValueType expected, const ViewType view) {
static_assert(std::is_same<ValueType, typename ViewType::value_type>::value,
"Non-matching value types of view and reference value");
auto view_h = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), view);
for (std::size_t i = 0; i < view_h.extent(0); i++) {
EXPECT_EQ(expected, view_h(i));
}
}
template <class ValueType, class ViewType>
std::enable_if_t<std::is_same<typename ViewType::traits::array_layout,
Kokkos::LayoutStride>::value>
verify_values(ValueType expected, const ViewType view) {
static_assert(std::is_same<ValueType, typename ViewType::value_type>::value,
"Non-matching value types of view and reference value");
using non_strided_view_t = Kokkos::View<typename ViewType::value_type*>;
non_strided_view_t tmpView("tmpView", view.extent(0));
Kokkos::parallel_for(
"_std_algo_copy", view.extent(0),
CopyFunctor<ViewType, non_strided_view_t>(view, tmpView));
auto view_h =
Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), tmpView);
for (std::size_t i = 0; i < view_h.extent(0); i++) {
EXPECT_EQ(expected, view_h(i));
}
}
template <class ViewType1, class ViewType2>
std::enable_if_t<!std::is_same<typename ViewType2::traits::array_layout,
Kokkos::LayoutStride>::value>
compare_views(ViewType1 expected, const ViewType2 actual) {
static_assert(std::is_same<typename ViewType1::value_type,
typename ViewType2::value_type>::value,
"Non-matching value types of expected and actual view");
auto expected_h =
Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), expected);
auto actual_h =
Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), actual);
for (std::size_t i = 0; i < expected_h.extent(0); i++) {
EXPECT_EQ(expected_h(i), actual_h(i));
}
}
template <class ViewType1, class ViewType2>
std::enable_if_t<std::is_same<typename ViewType2::traits::array_layout,
Kokkos::LayoutStride>::value>
compare_views(ViewType1 expected, const ViewType2 actual) {
static_assert(std::is_same<typename ViewType1::value_type,
typename ViewType2::value_type>::value,
"Non-matching value types of expected and actual view");
using non_strided_view_t = Kokkos::View<typename ViewType2::value_type*>;
non_strided_view_t tmp_view("tmp_view", actual.extent(0));
Kokkos::parallel_for(
"_std_algo_copy", actual.extent(0),
CopyFunctor<ViewType2, non_strided_view_t>(actual, tmp_view));
auto actual_h =
Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), tmp_view);
auto expected_h =
Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), expected);
for (std::size_t i = 0; i < expected_h.extent(0); i++) {
EXPECT_EQ(expected_h(i), actual_h(i));
}
}
template <class ViewType>
void fill_zero(ViewType a) {
const auto functor = FillZeroFunctor<ViewType>(a);
::Kokkos::parallel_for(a.extent(0), std::move(functor));
}
template <class ViewType1, class ViewType2>
void fill_zero(ViewType1 a, ViewType2 b) {
fill_zero(a);
fill_zero(b);
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
// helpers for testing small views (extent = 10)
// prefer `default_scenarios` map for creating new tests
using value_type = double;
struct std_algorithms_test : public ::testing::Test {
static constexpr size_t extent = 10;
using static_view_t = Kokkos::View<value_type[extent]>;
static_view_t m_static_view{"std-algo-test-1D-contiguous-view-static"};
using dyn_view_t = Kokkos::View<value_type*>;
dyn_view_t m_dynamic_view{"std-algo-test-1D-contiguous-view-dynamic", extent};
using strided_view_t = Kokkos::View<value_type*, Kokkos::LayoutStride>;
Kokkos::LayoutStride layout{extent, 2};
strided_view_t m_strided_view{"std-algo-test-1D-strided-view", layout};
using view_host_space_t = Kokkos::View<value_type[10], Kokkos::HostSpace>;
template <class ViewFromType>
void copyInputViewToFixtureViews(ViewFromType view) {
CopyFunctor<ViewFromType, static_view_t> F1(view, m_static_view);
Kokkos::parallel_for("_std_algo_copy1", view.extent(0), F1);
CopyFunctor<ViewFromType, dyn_view_t> F2(view, m_dynamic_view);
Kokkos::parallel_for("_std_algo_copy2", view.extent(0), F2);
CopyFunctor<ViewFromType, strided_view_t> F3(view, m_strided_view);
Kokkos::parallel_for("_std_algo_copy3", view.extent(0), F3);
}
};
} // namespace stdalgos
} // namespace Test
#endif

View File

@ -0,0 +1,553 @@
/*
//@HEADER
// ************************************************************************
//
// Kokkos v. 3.0
// Copyright (2020) 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.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the Corporation nor the names of the
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Questions? Contact Christian R. Trott (crtrott@sandia.gov)
//
// ************************************************************************
//@HEADER
*/
#include <std_algorithms/Kokkos_BeginEnd.hpp>
#include <Kokkos_StdAlgorithms.hpp>
namespace Test {
namespace stdalgos {
namespace compileonly {
template <class ValueType>
struct TrivialUnaryFunctor {
KOKKOS_INLINE_FUNCTION
ValueType operator()(const ValueType a) const { return a; }
};
template <class ValueType>
struct TrivialBinaryFunctor {
KOKKOS_INLINE_FUNCTION
ValueType operator()(const ValueType &a, const ValueType &b) const {
return (a + b);
}
KOKKOS_INLINE_FUNCTION
ValueType operator()(const volatile ValueType &a,
const volatile ValueType &b) const {
return (a + b);
}
};
template <class ValueType>
struct TrivialUnaryPredicate {
KOKKOS_INLINE_FUNCTION
bool operator()(const ValueType val) const {
(void)val;
return true;
}
};
template <class ValueType>
struct TrivialBinaryPredicate {
KOKKOS_INLINE_FUNCTION
bool operator()(const ValueType val, const ValueType val2) const {
(void)val;
(void)val2;
return true;
}
};
template <class ValueType>
struct TimesTwoFunctor {
KOKKOS_INLINE_FUNCTION
void operator()(ValueType &val) const { val *= (ValueType)2; }
};
template <class ValueType>
struct TrivialComparator {
KOKKOS_INLINE_FUNCTION
bool operator()(const ValueType &a, const ValueType &b) const {
return a > b;
}
KOKKOS_INLINE_FUNCTION
bool operator()(const volatile ValueType &a,
const volatile ValueType &b) const {
return a > b;
}
};
template <class ValueType>
struct TrivialGenerator {
KOKKOS_INLINE_FUNCTION
ValueType operator()() const { return ValueType{}; }
};
template <class ValueType>
struct TrivialReduceJoinFunctor {
KOKKOS_FUNCTION
ValueType operator()(const ValueType &a, const ValueType &b) const {
return a + b;
}
KOKKOS_FUNCTION
ValueType operator()(const volatile ValueType &a,
const volatile ValueType &b) const {
return a + b;
}
};
template <class ValueType>
struct TrivialTransformReduceUnaryTransformer {
KOKKOS_FUNCTION
ValueType operator()(const ValueType &a) const { return a; }
};
template <class ValueType>
struct TrivialTransformReduceBinaryTransformer {
KOKKOS_FUNCTION
ValueType operator()(const ValueType &a, const ValueType &b) const {
return (a * b);
}
};
// put all code here and don't call from main
// so that even if one runs the executable,
// nothing is run anyway
namespace KE = Kokkos::Experimental;
using count_type = std::size_t;
using T = double;
Kokkos::View<T *> in1("in1", 10);
Kokkos::View<T *> in2("in2", 10);
Kokkos::View<T *> in3("in3", 10);
Kokkos::DefaultExecutionSpace exe_space;
std::string const label = "trivial";
//
// just iterators
//
#define TEST_ALGO_MACRO_B1E1(ALGO) \
(void)KE::ALGO(exe_space, /*--*/ KE::begin(in1), KE::end(in1)); \
(void)KE::ALGO(label, exe_space, KE::begin(in1), KE::end(in1));
#define TEST_ALGO_MACRO_B1E1B2(ALGO) \
(void)KE::ALGO(exe_space, /*--*/ KE::begin(in1), KE::end(in1), \
KE::begin(in2)); \
(void)KE::ALGO(label, exe_space, KE::begin(in1), KE::end(in1), \
KE::begin(in2));
#define TEST_ALGO_MACRO_B1E1B2E2(ALGO) \
(void)KE::ALGO(exe_space, /*--*/ KE::begin(in1), KE::end(in1), \
KE::begin(in2), KE::end(in2)); \
(void)KE::ALGO(label, exe_space, KE::begin(in1), KE::end(in1), \
KE::begin(in2), KE::end(in2));
#define TEST_ALGO_MACRO_B1E1E2(ALGO) \
(void)KE::ALGO(exe_space, /*--*/ KE::begin(in1), KE::end(in1), \
KE::end(in2)); \
(void)KE::ALGO(label, exe_space, KE::begin(in1), KE::end(in1), KE::end(in2));
#define TEST_ALGO_MACRO_B1E1E2B3(ALGO) \
(void)KE::ALGO(exe_space, /*--*/ KE::begin(in1), KE::end(in1), KE::end(in2), \
KE::begin(in3)); \
(void)KE::ALGO(label, exe_space, KE::begin(in1), KE::end(in1), KE::end(in2), \
KE::begin(in3));
#define TEST_ALGO_MACRO_B1E1E1B2(ALGO) \
(void)KE::ALGO(exe_space, /*--*/ KE::begin(in1), KE::end(in1), KE::end(in1), \
KE::begin(in2)); \
(void)KE::ALGO(label, exe_space, KE::begin(in1), KE::end(in1), KE::end(in1), \
KE::begin(in2));
//
// iterators and params
//
#define TEST_ALGO_MACRO_B1_VARIAD(ALGO, ...) \
(void)KE::ALGO(exe_space, /*--*/ KE::begin(in1), __VA_ARGS__); \
(void)KE::ALGO(label, exe_space, KE::begin(in1), __VA_ARGS__);
#define TEST_ALGO_MACRO_B1E1_VARIAD(ALGO, ...) \
(void)KE::ALGO(exe_space, /*--*/ KE::begin(in1), KE::end(in1), __VA_ARGS__); \
(void)KE::ALGO(label, exe_space, KE::begin(in1), KE::end(in1), __VA_ARGS__);
#define TEST_ALGO_MACRO_B1E1B2_VARIAD(ALGO, ...) \
(void)KE::ALGO(exe_space, /*--*/ KE::begin(in1), KE::end(in1), \
KE::begin(in2), __VA_ARGS__); \
(void)KE::ALGO(label, exe_space, KE::begin(in1), KE::end(in1), \
KE::begin(in2), __VA_ARGS__);
#define TEST_ALGO_MACRO_B1_ARG_B2(ALGO, ARG) \
(void)KE::ALGO(exe_space, /*--*/ KE::begin(in1), ARG, KE::begin(in2)); \
(void)KE::ALGO(label, exe_space, KE::begin(in1), ARG, KE::begin(in2));
#define TEST_ALGO_MACRO_B1E1B2B3_VARIAD(ALGO, ...) \
(void)KE::ALGO(exe_space, /*--*/ KE::begin(in1), KE::end(in1), \
KE::begin(in2), KE::begin(in3), __VA_ARGS__); \
(void)KE::ALGO(label, exe_space, KE::begin(in1), KE::end(in1), \
KE::begin(in2), KE::begin(in3), __VA_ARGS__);
#define TEST_ALGO_MACRO_B1E1B2E2_VARIAD(ALGO, ARG) \
(void)KE::ALGO(exe_space, /*--*/ KE::begin(in1), KE::end(in1), \
KE::begin(in2), KE::end(in2), ARG); \
(void)KE::ALGO(label, exe_space, KE::begin(in1), KE::end(in1), \
KE::begin(in2), KE::end(in2), ARG);
//
// views only
//
#define TEST_ALGO_MACRO_V1(ALGO) \
(void)KE::ALGO(exe_space, /*--*/ in1); \
(void)KE::ALGO(label, exe_space, in1);
#define TEST_ALGO_MACRO_V1V2(ALGO) \
(void)KE::ALGO(exe_space, /*--*/ in1, in2); \
(void)KE::ALGO(label, exe_space, in1, in2);
#define TEST_ALGO_MACRO_V1V2V3(ALGO) \
(void)KE::ALGO(exe_space, /*--*/ in1, in2, in3); \
(void)KE::ALGO(label, exe_space, in1, in2, in3);
//
// views and params
//
#define TEST_ALGO_MACRO_V1_VARIAD(ALGO, ...) \
(void)KE::ALGO(exe_space, /*--*/ in1, __VA_ARGS__); \
(void)KE::ALGO(label, exe_space, in1, __VA_ARGS__);
#define TEST_ALGO_MACRO_V1V2_VARIAD(ALGO, ...) \
(void)KE::ALGO(exe_space, /*--*/ in1, in2, __VA_ARGS__); \
(void)KE::ALGO(label, exe_space, in1, in2, __VA_ARGS__);
#define TEST_ALGO_MACRO_V1V2V3_VARIAD(ALGO, ...) \
(void)KE::ALGO(exe_space, /*--*/ in1, in2, in3, __VA_ARGS__); \
(void)KE::ALGO(label, exe_space, in1, in2, in3, __VA_ARGS__);
#define TEST_ALGO_MACRO_V1_ARG_V2(ALGO, ARG) \
(void)KE::ALGO(exe_space, /*--*/ in1, ARG, in2); \
(void)KE::ALGO(label, exe_space, in1, ARG, in2);
void non_modifying_seq_ops() {
TEST_ALGO_MACRO_B1E1_VARIAD(find, T{});
TEST_ALGO_MACRO_V1_VARIAD(find, T{});
TEST_ALGO_MACRO_B1E1_VARIAD(find_if, TrivialUnaryPredicate<T>());
TEST_ALGO_MACRO_V1_VARIAD(find_if, TrivialUnaryPredicate<T>());
TEST_ALGO_MACRO_B1E1_VARIAD(find_if_not, TrivialUnaryPredicate<T>());
TEST_ALGO_MACRO_V1_VARIAD(find_if_not, TrivialUnaryPredicate<T>());
TEST_ALGO_MACRO_B1E1_VARIAD(for_each, TimesTwoFunctor<T>());
TEST_ALGO_MACRO_V1_VARIAD(for_each, TimesTwoFunctor<T>());
TEST_ALGO_MACRO_B1_VARIAD(for_each_n, count_type{}, TimesTwoFunctor<T>());
TEST_ALGO_MACRO_V1_VARIAD(for_each_n, count_type{}, TimesTwoFunctor<T>());
TEST_ALGO_MACRO_B1E1_VARIAD(count_if, TrivialUnaryPredicate<T>());
TEST_ALGO_MACRO_V1_VARIAD(count_if, TrivialUnaryPredicate<T>());
TEST_ALGO_MACRO_B1E1_VARIAD(count, T{});
TEST_ALGO_MACRO_V1_VARIAD(count, T{});
TEST_ALGO_MACRO_B1E1B2E2(mismatch);
TEST_ALGO_MACRO_B1E1B2E2_VARIAD(mismatch, TrivialBinaryPredicate<T>());
TEST_ALGO_MACRO_V1V2(mismatch);
TEST_ALGO_MACRO_V1V2_VARIAD(mismatch, TrivialBinaryPredicate<T>());
TEST_ALGO_MACRO_B1E1_VARIAD(all_of, TrivialUnaryPredicate<T>());
TEST_ALGO_MACRO_V1_VARIAD(all_of, TrivialUnaryPredicate<T>());
TEST_ALGO_MACRO_B1E1_VARIAD(any_of, TrivialUnaryPredicate<T>());
TEST_ALGO_MACRO_V1_VARIAD(any_of, TrivialUnaryPredicate<T>());
TEST_ALGO_MACRO_B1E1_VARIAD(none_of, TrivialUnaryPredicate<T>());
TEST_ALGO_MACRO_V1_VARIAD(none_of, TrivialUnaryPredicate<T>());
TEST_ALGO_MACRO_B1E1B2(equal);
TEST_ALGO_MACRO_B1E1B2_VARIAD(equal, TrivialBinaryPredicate<T>());
TEST_ALGO_MACRO_V1V2(equal);
TEST_ALGO_MACRO_V1V2_VARIAD(equal, TrivialBinaryPredicate<T>());
TEST_ALGO_MACRO_B1E1B2E2(equal);
TEST_ALGO_MACRO_B1E1B2E2_VARIAD(equal, TrivialBinaryPredicate<T>());
TEST_ALGO_MACRO_B1E1B2E2(lexicographical_compare);
TEST_ALGO_MACRO_B1E1B2E2_VARIAD(lexicographical_compare,
TrivialComparator<T>());
TEST_ALGO_MACRO_V1V2(lexicographical_compare);
TEST_ALGO_MACRO_V1V2_VARIAD(lexicographical_compare, TrivialComparator<T>());
TEST_ALGO_MACRO_B1E1(adjacent_find);
TEST_ALGO_MACRO_V1(adjacent_find);
TEST_ALGO_MACRO_B1E1_VARIAD(adjacent_find, TrivialBinaryFunctor<T>());
TEST_ALGO_MACRO_V1_VARIAD(adjacent_find, TrivialBinaryFunctor<T>());
TEST_ALGO_MACRO_B1E1B2E2(search);
TEST_ALGO_MACRO_V1V2(search);
TEST_ALGO_MACRO_B1E1B2E2_VARIAD(search, TrivialBinaryFunctor<T>());
TEST_ALGO_MACRO_V1V2_VARIAD(search, TrivialBinaryFunctor<T>());
TEST_ALGO_MACRO_B1E1B2E2(find_first_of);
TEST_ALGO_MACRO_V1V2(find_first_of);
TEST_ALGO_MACRO_B1E1B2E2_VARIAD(find_first_of, TrivialBinaryFunctor<T>());
TEST_ALGO_MACRO_V1V2_VARIAD(find_first_of, TrivialBinaryFunctor<T>());
TEST_ALGO_MACRO_B1E1_VARIAD(search_n, count_type{}, T{});
TEST_ALGO_MACRO_V1_VARIAD(search_n, count_type{}, T{});
TEST_ALGO_MACRO_B1E1_VARIAD(search_n, count_type{}, T{},
TrivialBinaryPredicate<T>());
TEST_ALGO_MACRO_V1_VARIAD(search_n, count_type{}, T{},
TrivialBinaryPredicate<T>());
TEST_ALGO_MACRO_B1E1B2E2(find_end);
TEST_ALGO_MACRO_V1V2(find_end);
TEST_ALGO_MACRO_B1E1B2E2_VARIAD(find_end, TrivialBinaryFunctor<T>());
TEST_ALGO_MACRO_V1V2_VARIAD(find_end, TrivialBinaryFunctor<T>());
}
void modifying_seq_ops() {
TEST_ALGO_MACRO_B1E1B2_VARIAD(replace_copy, T{}, T{});
TEST_ALGO_MACRO_V1V2_VARIAD(replace_copy, T{}, T{});
TEST_ALGO_MACRO_B1E1B2_VARIAD(replace_copy_if, TrivialUnaryPredicate<T>(),
T{});
TEST_ALGO_MACRO_V1V2_VARIAD(replace_copy_if, TrivialUnaryPredicate<T>(), T{});
TEST_ALGO_MACRO_B1E1_VARIAD(replace, T{}, T{});
TEST_ALGO_MACRO_V1_VARIAD(replace, T{}, T{});
TEST_ALGO_MACRO_B1E1_VARIAD(replace_if, TrivialUnaryPredicate<T>(), T{});
TEST_ALGO_MACRO_V1_VARIAD(replace_if, TrivialUnaryPredicate<T>(), T{});
TEST_ALGO_MACRO_B1E1B2(copy);
TEST_ALGO_MACRO_V1V2(copy);
TEST_ALGO_MACRO_B1_ARG_B2(copy_n, count_type{});
TEST_ALGO_MACRO_V1_ARG_V2(copy_n, count_type{});
TEST_ALGO_MACRO_B1E1B2(copy_backward);
TEST_ALGO_MACRO_V1V2(copy_backward);
TEST_ALGO_MACRO_B1E1B2_VARIAD(copy_if, TrivialUnaryPredicate<T>());
TEST_ALGO_MACRO_V1V2_VARIAD(copy_if, TrivialUnaryPredicate<T>());
TEST_ALGO_MACRO_B1E1_VARIAD(fill, T{});
TEST_ALGO_MACRO_V1_VARIAD(fill, T{});
TEST_ALGO_MACRO_B1_VARIAD(fill_n, count_type{}, T{});
TEST_ALGO_MACRO_V1_VARIAD(fill_n, count_type{}, T{});
TEST_ALGO_MACRO_B1E1B2_VARIAD(transform, TrivialUnaryFunctor<T>{});
TEST_ALGO_MACRO_V1V2_VARIAD(transform, TrivialUnaryFunctor<T>{});
TEST_ALGO_MACRO_B1E1B2_VARIAD(transform, TrivialUnaryFunctor<T>{});
TEST_ALGO_MACRO_B1E1B2B3_VARIAD(transform, TrivialBinaryFunctor<T>{});
TEST_ALGO_MACRO_V1V2_VARIAD(transform, TrivialUnaryFunctor<T>{});
TEST_ALGO_MACRO_V1V2V3_VARIAD(transform, TrivialBinaryFunctor<T>{});
TEST_ALGO_MACRO_B1E1_VARIAD(generate, TrivialGenerator<T>{});
TEST_ALGO_MACRO_V1_VARIAD(generate, TrivialGenerator<T>{});
TEST_ALGO_MACRO_B1_VARIAD(generate_n, count_type{}, TrivialGenerator<T>{});
TEST_ALGO_MACRO_V1_VARIAD(generate_n, count_type{}, TrivialGenerator<T>{});
TEST_ALGO_MACRO_B1E1B2(reverse_copy);
TEST_ALGO_MACRO_V1V2(reverse_copy);
TEST_ALGO_MACRO_B1E1(reverse);
TEST_ALGO_MACRO_V1(reverse);
TEST_ALGO_MACRO_B1E1B2(move);
TEST_ALGO_MACRO_V1V2(move);
TEST_ALGO_MACRO_B1E1E2(move_backward);
TEST_ALGO_MACRO_V1V2(move_backward);
TEST_ALGO_MACRO_B1E1B2(swap_ranges);
TEST_ALGO_MACRO_V1V2(swap_ranges);
TEST_ALGO_MACRO_B1E1(unique);
TEST_ALGO_MACRO_V1(unique);
TEST_ALGO_MACRO_B1E1_VARIAD(unique, TrivialBinaryPredicate<T>{});
TEST_ALGO_MACRO_V1_VARIAD(unique, TrivialBinaryPredicate<T>{});
TEST_ALGO_MACRO_B1E1B2(unique_copy);
TEST_ALGO_MACRO_V1V2(unique_copy);
TEST_ALGO_MACRO_B1E1B2_VARIAD(unique_copy, TrivialBinaryPredicate<T>{});
TEST_ALGO_MACRO_V1V2_VARIAD(unique_copy, TrivialBinaryPredicate<T>{});
TEST_ALGO_MACRO_B1E1E2(rotate);
TEST_ALGO_MACRO_V1_VARIAD(rotate, count_type{});
TEST_ALGO_MACRO_B1E1E1B2(rotate_copy);
TEST_ALGO_MACRO_V1_ARG_V2(rotate_copy, count_type{});
TEST_ALGO_MACRO_B1E1_VARIAD(remove_if, TrivialUnaryPredicate<T>{});
TEST_ALGO_MACRO_V1_VARIAD(remove_if, TrivialUnaryPredicate<T>{});
TEST_ALGO_MACRO_B1E1_VARIAD(remove, T{});
TEST_ALGO_MACRO_V1_VARIAD(remove, T{});
TEST_ALGO_MACRO_B1E1B2_VARIAD(remove_copy, T{});
TEST_ALGO_MACRO_V1V2_VARIAD(remove_copy, T{});
TEST_ALGO_MACRO_B1E1B2_VARIAD(remove_copy_if, TrivialUnaryPredicate<T>());
TEST_ALGO_MACRO_V1V2_VARIAD(remove_copy_if, TrivialUnaryPredicate<T>());
TEST_ALGO_MACRO_B1E1_VARIAD(shift_left, count_type{});
TEST_ALGO_MACRO_V1_VARIAD(shift_left, count_type{});
TEST_ALGO_MACRO_B1E1_VARIAD(shift_right, count_type{});
TEST_ALGO_MACRO_V1_VARIAD(shift_right, count_type{});
}
void sorting_ops() {
TEST_ALGO_MACRO_B1E1(is_sorted_until);
TEST_ALGO_MACRO_V1(is_sorted_until);
#ifndef KOKKOS_ENABLE_OPENMPTARGET
TEST_ALGO_MACRO_B1E1_VARIAD(is_sorted_until, TrivialComparator<T>());
TEST_ALGO_MACRO_V1_VARIAD(is_sorted_until, TrivialComparator<T>());
#endif
TEST_ALGO_MACRO_B1E1(is_sorted);
TEST_ALGO_MACRO_V1(is_sorted);
#ifndef KOKKOS_ENABLE_OPENMPTARGET
TEST_ALGO_MACRO_B1E1_VARIAD(is_sorted, TrivialComparator<T>());
TEST_ALGO_MACRO_V1_VARIAD(is_sorted, TrivialComparator<T>());
#endif
}
void minmax_ops() {
TEST_ALGO_MACRO_B1E1(min_element);
TEST_ALGO_MACRO_V1(min_element);
TEST_ALGO_MACRO_B1E1(max_element);
TEST_ALGO_MACRO_V1(max_element);
TEST_ALGO_MACRO_B1E1(minmax_element);
TEST_ALGO_MACRO_V1(minmax_element);
#ifndef KOKKOS_ENABLE_OPENMPTARGET
TEST_ALGO_MACRO_B1E1_VARIAD(min_element, TrivialComparator<T>());
TEST_ALGO_MACRO_V1_VARIAD(min_element, TrivialComparator<T>());
TEST_ALGO_MACRO_B1E1_VARIAD(max_element, TrivialComparator<T>());
TEST_ALGO_MACRO_V1_VARIAD(max_element, TrivialComparator<T>());
TEST_ALGO_MACRO_B1E1_VARIAD(minmax_element, TrivialComparator<T>());
TEST_ALGO_MACRO_V1_VARIAD(minmax_element, TrivialComparator<T>());
#endif
}
void partitionig_ops() {
TEST_ALGO_MACRO_B1E1_VARIAD(is_partitioned, TrivialUnaryPredicate<T>());
TEST_ALGO_MACRO_V1_VARIAD(is_partitioned, TrivialUnaryPredicate<T>());
TEST_ALGO_MACRO_B1E1B2B3_VARIAD(partition_copy, TrivialUnaryPredicate<T>());
TEST_ALGO_MACRO_V1V2V3_VARIAD(partition_copy, TrivialUnaryPredicate<T>());
TEST_ALGO_MACRO_B1E1_VARIAD(partition_point, TrivialUnaryPredicate<T>());
TEST_ALGO_MACRO_V1_VARIAD(partition_point, TrivialUnaryPredicate<T>());
}
void numeric() {
TEST_ALGO_MACRO_B1E1B2(adjacent_difference);
TEST_ALGO_MACRO_B1E1B2_VARIAD(adjacent_difference, TrivialBinaryFunctor<T>());
TEST_ALGO_MACRO_V1V2(adjacent_difference);
TEST_ALGO_MACRO_V1V2_VARIAD(adjacent_difference, TrivialBinaryFunctor<T>());
TEST_ALGO_MACRO_B1E1B2_VARIAD(exclusive_scan, T{});
TEST_ALGO_MACRO_V1V2_VARIAD(exclusive_scan, T{});
#ifndef KOKKOS_ENABLE_OPENMPTARGET
TEST_ALGO_MACRO_B1E1B2_VARIAD(exclusive_scan, T{}, TrivialBinaryFunctor<T>());
TEST_ALGO_MACRO_V1V2_VARIAD(exclusive_scan, T{}, TrivialBinaryFunctor<T>());
TEST_ALGO_MACRO_B1E1B2_VARIAD(transform_exclusive_scan, T{},
TrivialBinaryFunctor<T>(),
TrivialUnaryFunctor<T>());
TEST_ALGO_MACRO_V1V2_VARIAD(transform_exclusive_scan, T{},
TrivialBinaryFunctor<T>(),
TrivialUnaryFunctor<T>());
#endif
TEST_ALGO_MACRO_B1E1B2(inclusive_scan);
TEST_ALGO_MACRO_V1V2(inclusive_scan);
#ifndef KOKKOS_ENABLE_OPENMPTARGET
TEST_ALGO_MACRO_B1E1B2_VARIAD(inclusive_scan, TrivialBinaryFunctor<T>());
TEST_ALGO_MACRO_V1V2_VARIAD(inclusive_scan, TrivialBinaryFunctor<T>());
TEST_ALGO_MACRO_B1E1B2_VARIAD(inclusive_scan, TrivialBinaryFunctor<T>(), T{});
TEST_ALGO_MACRO_V1V2_VARIAD(inclusive_scan, TrivialBinaryFunctor<T>(), T{});
TEST_ALGO_MACRO_B1E1B2_VARIAD(transform_inclusive_scan,
TrivialBinaryFunctor<T>(),
TrivialUnaryFunctor<T>());
TEST_ALGO_MACRO_V1V2_VARIAD(transform_inclusive_scan,
TrivialBinaryFunctor<T>(),
TrivialUnaryFunctor<T>());
TEST_ALGO_MACRO_B1E1B2_VARIAD(transform_inclusive_scan,
TrivialBinaryFunctor<T>(),
TrivialUnaryFunctor<T>(), T{});
TEST_ALGO_MACRO_V1V2_VARIAD(transform_inclusive_scan,
TrivialBinaryFunctor<T>(),
TrivialUnaryFunctor<T>(), T{});
#endif
#ifndef KOKKOS_ENABLE_OPENMPTARGET
TEST_ALGO_MACRO_B1E1(reduce);
TEST_ALGO_MACRO_V1(reduce);
TEST_ALGO_MACRO_B1E1_VARIAD(reduce, T{});
TEST_ALGO_MACRO_V1_VARIAD(reduce, T{});
TEST_ALGO_MACRO_B1E1_VARIAD(reduce, T{}, TrivialReduceJoinFunctor<T>());
TEST_ALGO_MACRO_V1_VARIAD(reduce, T{}, TrivialReduceJoinFunctor<T>());
TEST_ALGO_MACRO_B1E1B2_VARIAD(transform_reduce, T{});
TEST_ALGO_MACRO_V1V2_VARIAD(transform_reduce, T{});
TEST_ALGO_MACRO_B1E1B2_VARIAD(transform_reduce, T{},
TrivialReduceJoinFunctor<T>(),
TrivialTransformReduceBinaryTransformer<T>());
TEST_ALGO_MACRO_V1V2_VARIAD(transform_reduce, T{},
TrivialReduceJoinFunctor<T>(),
TrivialTransformReduceBinaryTransformer<T>());
TEST_ALGO_MACRO_B1E1_VARIAD(transform_reduce, T{},
TrivialReduceJoinFunctor<T>(),
TrivialTransformReduceUnaryTransformer<T>());
TEST_ALGO_MACRO_V1_VARIAD(transform_reduce, T{},
TrivialReduceJoinFunctor<T>(),
TrivialTransformReduceUnaryTransformer<T>());
#endif
}
} // namespace compileonly
} // namespace stdalgos
} // namespace Test
int main() { return 0; }

View File

@ -0,0 +1,113 @@
/*
//@HEADER
// ************************************************************************
//
// Kokkos v. 3.0
// Copyright (2020) 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.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the Corporation nor the names of the
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Questions? Contact Christian R. Trott (crtrott@sandia.gov)
//
// ************************************************************************
//@HEADER
*/
#include <gtest/gtest.h>
#include <Kokkos_Core.hpp>
#include <std_algorithms/Kokkos_Constraints.hpp>
namespace Test {
namespace stdalgos {
TEST(std_algorithms, is_admissible_to_std_algorithms) {
namespace KE = Kokkos::Experimental;
using value_type = double;
static constexpr size_t extent0 = 13;
static constexpr size_t extent1 = 18;
static constexpr size_t extent2 = 18;
//-------------
// 1d views
//-------------
using static_view_1d_t = Kokkos::View<value_type[extent0]>;
static_view_1d_t static_view_1d{"std-algo-test-1d-contiguous-view-static"};
using dyn_view_1d_t = Kokkos::View<value_type*>;
dyn_view_1d_t dynamic_view_1d{"std-algo-test-1d-contiguous-view-dynamic",
extent0};
using strided_view_1d_t = Kokkos::View<value_type*, Kokkos::LayoutStride>;
Kokkos::LayoutStride layout1d{extent0, 2};
strided_view_1d_t strided_view_1d{"std-algo-test-1d-strided-view", layout1d};
EXPECT_EQ(layout1d.dimension[0], 13u);
EXPECT_EQ(layout1d.stride[0], 2u);
// they are admissible
KE::Impl::static_assert_is_admissible_to_kokkos_std_algorithms(
static_view_1d);
KE::Impl::static_assert_is_admissible_to_kokkos_std_algorithms(
dynamic_view_1d);
KE::Impl::static_assert_is_admissible_to_kokkos_std_algorithms(
strided_view_1d);
//-------------
// 2d views
//-------------
using static_view_2d_t = Kokkos::View<value_type[extent0][extent1]>;
using dyn_view_2d_t = Kokkos::View<value_type**>;
using strided_view_2d_t = Kokkos::View<value_type**, Kokkos::LayoutStride>;
// non admissible
EXPECT_FALSE(KE::Impl::is_admissible_to_kokkos_std_algorithms<
static_view_2d_t>::value);
EXPECT_FALSE(
KE::Impl::is_admissible_to_kokkos_std_algorithms<dyn_view_2d_t>::value);
EXPECT_FALSE(KE::Impl::is_admissible_to_kokkos_std_algorithms<
strided_view_2d_t>::value);
//-------------
// 3d views
//-------------
using static_view_3d_t = Kokkos::View<value_type[extent0][extent1][extent2]>;
using dyn_view_3d_t = Kokkos::View<value_type***>;
using strided_view_3d_t = Kokkos::View<value_type***, Kokkos::LayoutStride>;
// non admissible
EXPECT_FALSE(KE::Impl::is_admissible_to_kokkos_std_algorithms<
static_view_3d_t>::value);
EXPECT_FALSE(
KE::Impl::is_admissible_to_kokkos_std_algorithms<dyn_view_3d_t>::value);
EXPECT_FALSE(KE::Impl::is_admissible_to_kokkos_std_algorithms<
strided_view_3d_t>::value);
}
} // namespace stdalgos
} // namespace Test

View File

@ -0,0 +1,308 @@
/*
//@HEADER
// ************************************************************************
//
// Kokkos v. 3.0
// Copyright (2020) 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.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the Corporation nor the names of the
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Questions? Contact Christian R. Trott (crtrott@sandia.gov)
//
// ************************************************************************
//@HEADER
*/
#include <TestStdAlgorithmsCommon.hpp>
#include <std_algorithms/Kokkos_BeginEnd.hpp>
#include <std_algorithms/Kokkos_ModifyingSequenceOperations.hpp>
#include <utility>
namespace Test {
namespace stdalgos {
namespace CopyIf {
namespace KE = Kokkos::Experimental;
template <class ValueType>
struct UnifDist;
template <>
struct UnifDist<int> {
using dist_type = std::uniform_int_distribution<int>;
std::mt19937 m_gen;
dist_type m_dist;
UnifDist() : m_dist(-100, 100) { m_gen.seed(1034343); }
int operator()() { return m_dist(m_gen); }
};
template <class ViewType, class PredicateType>
std::size_t fill_view(ViewType dest_view, const std::string& name,
PredicateType pred) {
using value_type = typename ViewType::value_type;
using exe_space = typename ViewType::execution_space;
const std::size_t ext = dest_view.extent(0);
using aux_view_t = Kokkos::View<value_type*, exe_space>;
aux_view_t aux_view("aux_view", ext);
auto v_h = create_mirror_view(Kokkos::HostSpace(), aux_view);
std::size_t count = 0;
if (name == "empty") {
// no op
}
else if (name == "one-element-a") {
v_h(0) = static_cast<value_type>(1);
// 1 is not even, so count is not incremented
}
else if (name == "one-element-b") {
v_h(0) = static_cast<value_type>(2);
count++;
}
else if (name == "two-elements-a") {
v_h(0) = static_cast<value_type>(1);
v_h(1) = static_cast<value_type>(2);
count++;
}
else if (name == "two-elements-b") {
v_h(0) = static_cast<value_type>(2);
v_h(1) = static_cast<value_type>(-1);
count++;
}
else if (name == "small-a") {
for (std::size_t i = 0; i < ext; ++i) {
v_h(i) = value_type{-5} + static_cast<value_type>(i + 1);
if (pred(v_h(i))) {
count++;
}
}
}
else if (name == "small-b") {
for (std::size_t i = 0; i < ext; ++i) {
if (i % 2 == 0) {
v_h(i) = static_cast<value_type>(22);
} else {
v_h(i) = static_cast<value_type>(-12);
}
if (pred(v_h(i))) {
count++;
}
}
}
else if (name == "medium" || name == "large") {
UnifDist<value_type> randObj;
for (std::size_t i = 0; i < ext; ++i) {
v_h(i) = randObj();
if (pred(v_h(i))) {
count++;
}
}
}
else {
throw std::runtime_error("invalid choice");
}
Kokkos::deep_copy(aux_view, v_h);
CopyFunctor<aux_view_t, ViewType> F1(aux_view, dest_view);
Kokkos::parallel_for("copy", dest_view.extent(0), F1);
return count;
}
template <class ViewTypeFrom, class ViewTypeTest, class PredType>
void verify_data(const std::string& name, ViewTypeFrom view_from,
ViewTypeTest view_test, PredType pred) {
using value_type = typename ViewTypeTest::value_type;
//! always careful because views might not be deep copyable
auto view_test_dc = create_deep_copyable_compatible_clone(view_test);
auto view_test_h =
create_mirror_view_and_copy(Kokkos::HostSpace(), view_test_dc);
auto view_from_dc = create_deep_copyable_compatible_clone(view_from);
auto view_from_h =
create_mirror_view_and_copy(Kokkos::HostSpace(), view_from_dc);
if (name == "empty") {
// no op
}
else if (name == "one-element-a") {
EXPECT_TRUE(view_test_h(0) == static_cast<value_type>(0));
}
else if (name == "one-element-b") {
EXPECT_TRUE(view_test_h(0) == static_cast<value_type>(2));
}
else if (name == "two-elements-a") {
EXPECT_TRUE(view_test_h(0) == static_cast<value_type>(2));
EXPECT_TRUE(view_test_h(1) == static_cast<value_type>(0));
}
else if (name == "two-elements-b") {
EXPECT_TRUE(view_test_h(0) == static_cast<value_type>(2));
EXPECT_TRUE(view_test_h(1) == static_cast<value_type>(0));
}
else if (name == "small-a") {
EXPECT_TRUE(view_test_h(0) == static_cast<value_type>(-4));
EXPECT_TRUE(view_test_h(1) == static_cast<value_type>(-2));
EXPECT_TRUE(view_test_h(2) == static_cast<value_type>(0));
EXPECT_TRUE(view_test_h(3) == static_cast<value_type>(2));
EXPECT_TRUE(view_test_h(4) == static_cast<value_type>(4));
EXPECT_TRUE(view_test_h(5) == static_cast<value_type>(0));
EXPECT_TRUE(view_test_h(6) == static_cast<value_type>(0));
EXPECT_TRUE(view_test_h(7) == static_cast<value_type>(0));
EXPECT_TRUE(view_test_h(8) == static_cast<value_type>(0));
}
else if (name == "small-b") {
EXPECT_TRUE(view_test_h(0) == static_cast<value_type>(22));
EXPECT_TRUE(view_test_h(1) == static_cast<value_type>(-12));
EXPECT_TRUE(view_test_h(2) == static_cast<value_type>(22));
EXPECT_TRUE(view_test_h(3) == static_cast<value_type>(-12));
EXPECT_TRUE(view_test_h(4) == static_cast<value_type>(22));
EXPECT_TRUE(view_test_h(5) == static_cast<value_type>(-12));
EXPECT_TRUE(view_test_h(6) == static_cast<value_type>(22));
EXPECT_TRUE(view_test_h(7) == static_cast<value_type>(-12));
EXPECT_TRUE(view_test_h(8) == static_cast<value_type>(22));
EXPECT_TRUE(view_test_h(9) == static_cast<value_type>(-12));
EXPECT_TRUE(view_test_h(10) == static_cast<value_type>(22));
EXPECT_TRUE(view_test_h(11) == static_cast<value_type>(-12));
EXPECT_TRUE(view_test_h(12) == static_cast<value_type>(22));
}
else if (name == "medium" || name == "large") {
// for (std::size_t i = 0; i < view_from_h.extent(0); ++i){
// std::cout << "i= " << i << " "
// << " vf = " << view_from_h(i) << " "
// << " vt = " << view_test_h(i) << '\n';
// }
std::size_t count = 0;
for (std::size_t i = 0; i < view_from_h.extent(0); ++i) {
if (pred(view_from_h(i))) {
EXPECT_TRUE(view_test_h(count++) == view_from_h(i));
}
}
// all other entries of test view should be zero
for (; count < view_test_h.extent(0); ++count) {
// std::cout << count << '\n';
EXPECT_TRUE(view_test_h(count) == value_type(0));
}
}
else {
throw std::runtime_error("invalid choice");
}
}
std::string value_type_to_string(int) { return "int"; }
std::string value_type_to_string(double) { return "double"; }
template <class Tag, class ValueType, class InfoType>
void run_single_scenario(const InfoType& scenario_info) {
const auto name = std::get<0>(scenario_info);
const std::size_t view_ext = std::get<1>(scenario_info);
// std::cout << "copy_if: " << name << ", " << view_tag_to_string(Tag{}) << ",
// "
// << value_type_to_string(ValueType()) << std::endl;
auto view_from = create_view<ValueType>(Tag{}, view_ext, "copy_if_from");
IsEvenFunctor<ValueType> pred;
{
auto n = fill_view(view_from, name, pred);
auto view_dest = create_view<ValueType>(Tag{}, view_ext, "copy_if_dest");
auto rit = KE::copy_if(exespace(), KE::cbegin(view_from),
KE::cend(view_from), KE::begin(view_dest), pred);
verify_data(name, view_from, view_dest, pred);
EXPECT_TRUE(rit == (KE::begin(view_dest) + n));
}
{
auto n = fill_view(view_from, name, pred);
auto view_dest = create_view<ValueType>(Tag{}, view_ext, "copy_if_dest");
auto rit = KE::copy_if("label", exespace(), KE::cbegin(view_from),
KE::cend(view_from), KE::begin(view_dest), pred);
verify_data(name, view_from, view_dest, pred);
EXPECT_TRUE(rit == (KE::begin(view_dest) + n));
}
{
auto n = fill_view(view_from, name, pred);
auto view_dest = create_view<ValueType>(Tag{}, view_ext, "copy_if_dest");
auto rit = KE::copy_if(exespace(), view_from, view_dest, pred);
verify_data(name, view_from, view_dest, pred);
EXPECT_TRUE(rit == (KE::begin(view_dest) + n));
}
{
auto n = fill_view(view_from, name, pred);
auto view_dest = create_view<ValueType>(Tag{}, view_ext, "copy_if_dest");
auto rit = KE::copy_if("label", exespace(), view_from, view_dest, pred);
verify_data(name, view_from, view_dest, pred);
EXPECT_TRUE(rit == (KE::begin(view_dest) + n));
}
Kokkos::fence();
}
template <class Tag, class ValueType>
void run_all_scenarios() {
const std::map<std::string, std::size_t> scenarios = {
{"empty", 0}, {"one-element-a", 1}, {"one-element-b", 1},
{"two-elements-a", 2}, {"two-elements-b", 2}, {"small-a", 9},
{"small-b", 13}, {"medium", 1103}, {"large", 101513}};
for (const auto& it : scenarios) {
run_single_scenario<Tag, ValueType>(it);
}
}
TEST(std_algorithms_mod_seq_ops, copy_if) {
run_all_scenarios<DynamicTag, int>();
run_all_scenarios<StridedThreeTag, int>();
}
} // namespace CopyIf
} // namespace stdalgos
} // namespace Test

View File

@ -0,0 +1,142 @@
/*
//@HEADER
// ************************************************************************
//
// Kokkos v. 3.0
// Copyright (2020) 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.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the Corporation nor the names of the
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Questions? Contact Christian R. Trott (crtrott@sandia.gov)
//
// ************************************************************************
//@HEADER
*/
#include <TestStdAlgorithmsCommon.hpp>
#include <std_algorithms/Kokkos_BeginEnd.hpp>
#include <std_algorithms/Kokkos_NonModifyingSequenceOperations.hpp>
#include <algorithm>
namespace Test {
namespace stdalgos {
namespace Count {
namespace KE = Kokkos::Experimental;
template <class ViewType>
void test_count(const ViewType view) {
using value_t = typename ViewType::value_type;
using view_host_space_t = Kokkos::View<value_t*, Kokkos::HostSpace>;
view_host_space_t expected("count_expected", view.extent(0));
compare_views(expected, view);
{
const value_t count_value = 0;
const auto std_result =
std::count(KE::cbegin(expected), KE::cend(expected), count_value);
EXPECT_EQ(view.extent(0), size_t(std_result));
// pass const iterators
EXPECT_EQ(std_result, KE::count(exespace(), KE::cbegin(view),
KE::cend(view), count_value));
// pass view
EXPECT_EQ(std_result, KE::count(exespace(), view, count_value));
}
{
const value_t count_value = 13;
const auto std_result =
std::count(KE::cbegin(expected), KE::cend(expected), count_value);
// pass iterators
EXPECT_EQ(std_result, KE::count("label", exespace(), KE::begin(view),
KE::end(view), count_value));
// pass view
EXPECT_EQ(std_result, KE::count("label", exespace(), view, count_value));
}
}
template <class ViewType>
void test_count_if(const ViewType view) {
using value_t = typename ViewType::value_type;
using view_host_space_t = Kokkos::View<value_t*, Kokkos::HostSpace>;
view_host_space_t expected("count_expected", view.extent(0));
compare_views(expected, view);
// no positive elements (all zeroes)
const auto predicate = IsPositiveFunctor<value_type>();
EXPECT_EQ(0,
std::count_if(KE::begin(expected), KE::end(expected), predicate));
// pass iterators
EXPECT_EQ(
0, KE::count_if(exespace(), KE::begin(view), KE::end(view), predicate));
// pass view
EXPECT_EQ(0, KE::count_if(exespace(), view, predicate));
fill_views_inc(view, expected);
const auto std_result =
std::count_if(KE::begin(expected), KE::end(expected), predicate);
// pass const iterators
EXPECT_EQ(std_result, KE::count_if("label", exespace(), KE::cbegin(view),
KE::cend(view), predicate));
// pass view
EXPECT_EQ(std_result, KE::count_if("label", exespace(), view, predicate));
}
template <class Tag, class ValueType>
void run_all_scenarios() {
for (const auto& scenario : default_scenarios) {
{
auto view = create_view<ValueType>(Tag{}, scenario.second, "count");
test_count(view);
}
{
auto view = create_view<ValueType>(Tag{}, scenario.second, "count");
test_count_if(view);
}
}
}
TEST(std_algorithms_count_test, test) {
run_all_scenarios<DynamicTag, double>();
run_all_scenarios<StridedTwoTag, int>();
run_all_scenarios<StridedThreeTag, unsigned>();
}
} // namespace Count
} // namespace stdalgos
} // namespace Test

View File

@ -0,0 +1,150 @@
/*
//@HEADER
// ************************************************************************
//
// Kokkos v. 3.0
// Copyright (2020) 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.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the Corporation nor the names of the
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Questions? Contact Christian R. Trott (crtrott@sandia.gov)
//
// ************************************************************************
//@HEADER
*/
#include <TestStdAlgorithmsCommon.hpp>
#include <std_algorithms/Kokkos_BeginEnd.hpp>
#include <std_algorithms/Kokkos_NonModifyingSequenceOperations.hpp>
#include <std_algorithms/Kokkos_ModifyingSequenceOperations.hpp>
#include <algorithm>
namespace Test {
namespace stdalgos {
namespace Equal {
namespace KE = Kokkos::Experimental;
template <class ViewType>
void test_equal(const ViewType view) {
auto copy = create_deep_copyable_compatible_clone(view);
// pass iterators
EXPECT_TRUE(
KE::equal(exespace(), KE::begin(view), KE::end(view), KE::begin(copy)));
// pass views
EXPECT_TRUE(KE::equal(exespace(), view, copy));
// modify copy - make the last element different
const auto extent = view.extent(0);
if (extent > 0) {
KE::fill(exespace(), KE::end(copy) - 1, KE::end(copy), 1);
// pass const iterators
EXPECT_FALSE(KE::equal(exespace(), KE::cbegin(view), KE::cend(view),
KE::cbegin(copy)));
// pass views
EXPECT_FALSE(KE::equal("label", exespace(), view, copy));
}
}
template <class ViewType>
void test_equal_custom_comparator(const ViewType view) {
using value_t = typename ViewType::value_type;
const auto p = CustomEqualityComparator<value_t>();
auto copy = create_deep_copyable_compatible_clone(view);
// pass iterators
EXPECT_TRUE(KE::equal(exespace(), KE::begin(view), KE::end(view),
KE::begin(copy), p));
// pass views
EXPECT_TRUE(KE::equal(exespace(), view, copy, p));
// modify copy - make the last element different
const auto extent = view.extent(0);
if (extent > 0) {
KE::fill(exespace(), KE::end(copy) - 1, KE::end(copy), 1);
// pass const iterators
EXPECT_FALSE(KE::equal("label", exespace(), KE::cbegin(view),
KE::cend(view), KE::cbegin(copy), p));
// pass views
EXPECT_FALSE(KE::equal(exespace(), view, copy, p));
}
}
template <class ViewType>
void test_equal_4_iterators(const ViewType view) {
using value_t = typename ViewType::value_type;
const auto p = CustomEqualityComparator<value_t>();
auto copy = create_deep_copyable_compatible_clone(view);
// pass iterators
EXPECT_TRUE(KE::equal(exespace(), KE::begin(view), KE::end(view),
KE::begin(copy), KE::end(copy)));
// pass const and non-const iterators, custom comparator
EXPECT_TRUE(KE::equal("label", exespace(), KE::cbegin(view), KE::cend(view),
KE::begin(copy), KE::end(copy), p));
const auto extent = view.extent(0);
if (extent > 0) {
// use different length ranges, pass const iterators
EXPECT_FALSE(KE::equal(exespace(), KE::cbegin(view), KE::cend(view),
KE::cbegin(copy), KE::cend(copy) - 1));
// modify copy - make the last element different
KE::fill(exespace(), KE::end(copy) - 1, KE::end(copy), 1);
// pass const iterators
EXPECT_FALSE(KE::equal(exespace(), KE::cbegin(view), KE::cend(view),
KE::cbegin(copy), KE::cend(copy)));
}
}
template <class Tag, class ValueType>
void run_all_scenarios() {
for (const auto& scenario : default_scenarios) {
auto view = create_view<ValueType>(Tag{}, scenario.second, "equal");
test_equal(view);
test_equal_custom_comparator(view);
test_equal_4_iterators(view);
}
}
TEST(std_algorithms_equal_test, test) {
run_all_scenarios<DynamicTag, double>();
run_all_scenarios<StridedTwoTag, int>();
run_all_scenarios<StridedThreeTag, unsigned>();
}
} // namespace Equal
} // namespace stdalgos
} // namespace Test

View File

@ -0,0 +1,381 @@
/*
//@HEADER
// ************************************************************************
//
// Kokkos v. 3.0
// Copyright (2020) 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.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the Corporation nor the names of the
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Questions? Contact Christian R. Trott (crtrott@sandia.gov)
//
// ************************************************************************
//@HEADER
*/
#include <TestStdAlgorithmsCommon.hpp>
#include <std_algorithms/Kokkos_BeginEnd.hpp>
#include <std_algorithms/Kokkos_Numeric.hpp>
#include <utility>
namespace Test {
namespace stdalgos {
namespace EScan {
namespace KE = Kokkos::Experimental;
template <class ValueType>
struct UnifDist;
template <>
struct UnifDist<double> {
using dist_type = std::uniform_real_distribution<double>;
std::mt19937 m_gen;
dist_type m_dist;
UnifDist() : m_dist(0.05, 1.2) { m_gen.seed(1034343); }
double operator()() { return m_dist(m_gen); }
};
template <>
struct UnifDist<int> {
using dist_type = std::uniform_int_distribution<int>;
std::mt19937 m_gen;
dist_type m_dist;
UnifDist() : m_dist(1, 3) { m_gen.seed(1034343); }
int operator()() { return m_dist(m_gen); }
};
template <class ViewType>
void fill_zero(ViewType view) {
Kokkos::parallel_for(view.extent(0), FillZeroFunctor<ViewType>(view));
}
template <class ViewType>
void fill_view(ViewType dest_view, const std::string& name) {
using value_type = typename ViewType::value_type;
using exe_space = typename ViewType::execution_space;
const std::size_t ext = dest_view.extent(0);
using aux_view_t = Kokkos::View<value_type*, exe_space>;
aux_view_t aux_view("aux_view", ext);
auto v_h = create_mirror_view(Kokkos::HostSpace(), aux_view);
UnifDist<value_type> randObj;
if (name == "empty") {
// no op
}
else if (name == "one-element") {
v_h(0) = static_cast<value_type>(1);
}
else if (name == "two-elements-a") {
v_h(0) = static_cast<value_type>(1);
v_h(1) = static_cast<value_type>(2);
}
else if (name == "two-elements-b") {
v_h(0) = static_cast<value_type>(2);
v_h(1) = static_cast<value_type>(-1);
}
else if (name == "small-a") {
for (std::size_t i = 0; i < ext; ++i) {
v_h(i) = static_cast<value_type>(i + 1);
}
}
else if (name == "small-b") {
for (std::size_t i = 0; i < ext; ++i) {
v_h(i) = randObj();
}
v_h(5) = static_cast<value_type>(-2);
}
else if (name == "medium" || name == "large") {
for (std::size_t i = 0; i < ext; ++i) {
v_h(i) = randObj();
}
}
else {
throw std::runtime_error("invalid choice");
}
Kokkos::deep_copy(aux_view, v_h);
CopyFunctor<aux_view_t, ViewType> F1(aux_view, dest_view);
Kokkos::parallel_for("copy", dest_view.extent(0), F1);
}
// I had to write my own because std::exclusive_scan is ONLY found with
// std=c++17
template <class it1, class it2, class ValType, class BopType>
void my_host_exclusive_scan(it1 first, it1 last, it2 dest, ValType init,
BopType bop) {
const auto num_elements = last - first;
if (num_elements > 0) {
while (first < last - 1) {
*(dest++) = init;
init = bop(*first++, init);
}
*dest = init;
}
}
template <class ViewType1, class ViewType2, class ValueType, class BinaryOp>
void verify_data(ViewType1 data_view, // contains data
ViewType2 test_view, // the view to test
ValueType init_value, BinaryOp bop) {
//! always careful because views might not be deep copyable
auto data_view_dc = create_deep_copyable_compatible_clone(data_view);
auto data_view_h =
create_mirror_view_and_copy(Kokkos::HostSpace(), data_view_dc);
using gold_view_value_type = typename ViewType2::value_type;
Kokkos::View<gold_view_value_type*, Kokkos::HostSpace> gold_h(
"goldh", data_view.extent(0));
my_host_exclusive_scan(KE::cbegin(data_view_h), KE::cend(data_view_h),
KE::begin(gold_h), init_value, bop);
auto test_view_dc = create_deep_copyable_compatible_clone(test_view);
auto test_view_h =
create_mirror_view_and_copy(Kokkos::HostSpace(), test_view_dc);
if (test_view_h.extent(0) > 0) {
for (std::size_t i = 0; i < test_view_h.extent(0); ++i) {
// std::cout << i << " " << std::setprecision(15) << data_view_h(i) << " "
// << gold_h(i) << " " << test_view_h(i) << " "
// << std::abs(gold_h(i) - test_view_h(i)) << std::endl;
if (std::is_same<gold_view_value_type, int>::value) {
EXPECT_TRUE(gold_h(i) == test_view_h(i));
} else {
const auto error = std::abs(gold_h(i) - test_view_h(i));
if (error > 1e-10) {
std::cout << i << " " << std::setprecision(15) << data_view_h(i)
<< " " << gold_h(i) << " " << test_view_h(i) << " "
<< std::abs(gold_h(i) - test_view_h(i)) << std::endl;
}
EXPECT_TRUE(error < 1e-10);
}
}
}
}
template <class ValueType>
struct MultiplyFunctor {
KOKKOS_INLINE_FUNCTION
ValueType operator()(const ValueType& a, const ValueType& b) const {
return (a * b);
}
KOKKOS_INLINE_FUNCTION
ValueType operator()(const volatile ValueType& a,
const volatile ValueType& b) const {
return (a * b);
}
};
template <class ValueType>
struct SumFunctor {
KOKKOS_INLINE_FUNCTION
ValueType operator()(const ValueType& a, const ValueType& b) const {
return (a + b);
}
KOKKOS_INLINE_FUNCTION
ValueType operator()(const volatile ValueType& a,
const volatile ValueType& b) const {
return (a + b);
}
};
std::string value_type_to_string(int) { return "int"; }
std::string value_type_to_string(double) { return "double"; }
template <class Tag, class ValueType, class InfoType>
void run_single_scenario_default_op(const InfoType& scenario_info,
ValueType init_value) {
using default_op = SumFunctor<ValueType>;
const auto name = std::get<0>(scenario_info);
const std::size_t view_ext = std::get<1>(scenario_info);
// std::cout << "exclusive_scan default op: " << name << ", "
// << view_tag_to_string(Tag{}) << ", "
// << value_type_to_string(ValueType()) << ", "
// << "init = " << init_value << std::endl;
auto view_dest = create_view<ValueType>(Tag{}, view_ext, "exclusive_scan");
auto view_from = create_view<ValueType>(Tag{}, view_ext, "exclusive_scan");
fill_view(view_from, name);
{
fill_zero(view_dest);
auto r = KE::exclusive_scan(exespace(), KE::cbegin(view_from),
KE::cend(view_from), KE::begin(view_dest),
init_value);
EXPECT_TRUE(r == KE::end(view_dest));
verify_data(view_from, view_dest, init_value, default_op());
}
{
fill_zero(view_dest);
auto r = KE::exclusive_scan("label", exespace(), KE::cbegin(view_from),
KE::cend(view_from), KE::begin(view_dest),
init_value);
EXPECT_TRUE(r == KE::end(view_dest));
verify_data(view_from, view_dest, init_value, default_op());
}
{
fill_zero(view_dest);
auto r = KE::exclusive_scan(exespace(), view_from, view_dest, init_value);
EXPECT_TRUE(r == KE::end(view_dest));
verify_data(view_from, view_dest, init_value, default_op());
}
{
fill_zero(view_dest);
auto r = KE::exclusive_scan("label", exespace(), view_from, view_dest,
init_value);
EXPECT_TRUE(r == KE::end(view_dest));
verify_data(view_from, view_dest, init_value, default_op());
}
Kokkos::fence();
}
template <class Tag, class ValueType, class InfoType, class BinaryOp>
void run_single_scenario_custom_op(const InfoType& scenario_info,
ValueType init_value, BinaryOp bop) {
const auto name = std::get<0>(scenario_info);
const std::size_t view_ext = std::get<1>(scenario_info);
// std::cout << "exclusive_scan custom op: " << name << ", "
// << view_tag_to_string(Tag{}) << ", "
// << value_type_to_string(ValueType()) << ", "
// << "init = " << init_value << std::endl;
auto view_dest = create_view<ValueType>(Tag{}, view_ext, "exclusive_scan");
auto view_from = create_view<ValueType>(Tag{}, view_ext, "exclusive_scan");
fill_view(view_from, name);
{
fill_zero(view_dest);
auto r = KE::exclusive_scan(exespace(), KE::cbegin(view_from),
KE::cend(view_from), KE::begin(view_dest),
init_value, bop);
EXPECT_TRUE(r == KE::end(view_dest));
verify_data(view_from, view_dest, init_value, bop);
}
{
fill_zero(view_dest);
auto r = KE::exclusive_scan("label", exespace(), KE::cbegin(view_from),
KE::cend(view_from), KE::begin(view_dest),
init_value, bop);
EXPECT_TRUE(r == KE::end(view_dest));
verify_data(view_from, view_dest, init_value, bop);
}
{
fill_zero(view_dest);
auto r =
KE::exclusive_scan(exespace(), view_from, view_dest, init_value, bop);
EXPECT_TRUE(r == KE::end(view_dest));
verify_data(view_from, view_dest, init_value, bop);
}
{
fill_zero(view_dest);
auto r = KE::exclusive_scan("label", exespace(), view_from, view_dest,
init_value, bop);
EXPECT_TRUE(r == KE::end(view_dest));
verify_data(view_from, view_dest, init_value, bop);
}
Kokkos::fence();
}
template <class Tag, class ValueType>
void run_exclusive_scan_all_scenarios() {
const std::map<std::string, std::size_t> scenarios = {
{"empty", 0}, {"one-element", 1}, {"two-elements-a", 2},
{"two-elements-b", 2}, {"small-a", 9}, {"small-b", 13},
{"medium", 1103}, {"large", 10513}};
for (const auto& it : scenarios) {
run_single_scenario_default_op<Tag, ValueType>(it, ValueType{0});
run_single_scenario_default_op<Tag, ValueType>(it, ValueType{1});
run_single_scenario_default_op<Tag, ValueType>(it, ValueType{-2});
run_single_scenario_default_op<Tag, ValueType>(it, ValueType{3});
#if not defined KOKKOS_ENABLE_OPENMPTARGET
// custom multiply op is only run for small views otherwise it overflows
if (it.first == "small-a" || it.first == "small-b") {
using custom_bop_t = MultiplyFunctor<ValueType>;
run_single_scenario_custom_op<Tag, ValueType>(it, ValueType{0},
custom_bop_t());
run_single_scenario_custom_op<Tag, ValueType>(it, ValueType{1},
custom_bop_t());
run_single_scenario_custom_op<Tag, ValueType>(it, ValueType{-2},
custom_bop_t());
run_single_scenario_custom_op<Tag, ValueType>(it, ValueType{3},
custom_bop_t());
}
using custom_bop_t = SumFunctor<ValueType>;
run_single_scenario_custom_op<Tag, ValueType>(it, ValueType{0},
custom_bop_t());
run_single_scenario_custom_op<Tag, ValueType>(it, ValueType{1},
custom_bop_t());
run_single_scenario_custom_op<Tag, ValueType>(it, ValueType{-2},
custom_bop_t());
run_single_scenario_custom_op<Tag, ValueType>(it, ValueType{3},
custom_bop_t());
#endif
}
}
TEST(std_algorithms_numeric_ops_test, exclusive_scan) {
run_exclusive_scan_all_scenarios<DynamicTag, double>();
run_exclusive_scan_all_scenarios<StridedThreeTag, double>();
run_exclusive_scan_all_scenarios<DynamicTag, int>();
run_exclusive_scan_all_scenarios<StridedThreeTag, int>();
}
} // namespace EScan
} // namespace stdalgos
} // namespace Test

View File

@ -0,0 +1,191 @@
/*
//@HEADER
// ************************************************************************
//
// Kokkos v. 3.0
// Copyright (2020) 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.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the Corporation nor the names of the
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Questions? Contact Christian R. Trott (crtrott@sandia.gov)
//
// ************************************************************************
//@HEADER
*/
#include <TestStdAlgorithmsCommon.hpp>
#include <iterator>
#include <std_algorithms/Kokkos_BeginEnd.hpp>
#include <std_algorithms/Kokkos_NonModifyingSequenceOperations.hpp>
#include <algorithm>
namespace Test {
namespace stdalgos {
namespace Find {
namespace KE = Kokkos::Experimental;
template <class ViewType>
void test_find(const ViewType view) {
using value_t = typename ViewType::value_type;
using view_host_space_t = Kokkos::View<value_t*, Kokkos::HostSpace>;
view_host_space_t expected("count_expected", view.extent(0));
compare_views(expected, view);
constexpr value_t find_value = 13;
// value not found, return last
EXPECT_EQ(KE::end(expected),
std::find(KE::begin(expected), KE::end(expected), find_value));
// pass const iterators, returns const iterator
EXPECT_EQ(KE::cend(view),
KE::find(exespace(), KE::cbegin(view), KE::cend(view), find_value));
// pass view, returns iterator
EXPECT_EQ(KE::end(view), KE::find(exespace(), view, find_value));
fill_views_inc(view, expected);
auto std_result =
std::find(KE::begin(expected), KE::end(expected), find_value);
auto distance = std::distance(KE::begin(expected), std_result);
// pass iterators, returns iterator
EXPECT_EQ(KE::begin(view) + distance,
KE::find(exespace(), KE::begin(view), KE::end(view), find_value));
// pass view, returns iterator
EXPECT_EQ(KE::begin(view) + distance, KE::find(exespace(), view, find_value));
}
template <class ViewType>
void test_find_if(const ViewType view) {
using value_t = typename ViewType::value_type;
using view_host_space_t = Kokkos::View<value_t*, Kokkos::HostSpace>;
view_host_space_t expected("count_expected", view.extent(0));
compare_views(expected, view);
const auto not_equals_zero = NotEqualsZeroFunctor<value_type>();
// value not found, return last
EXPECT_EQ(
KE::end(expected),
std::find_if(KE::begin(expected), KE::end(expected), not_equals_zero));
// pass iterators, returns iterator
EXPECT_EQ(KE::end(view), KE::find_if(exespace(), KE::begin(view),
KE::end(view), not_equals_zero));
// pass view, returns iterator
EXPECT_EQ(KE::end(view), KE::find_if(exespace(), view, not_equals_zero));
fill_views_inc(view, expected);
constexpr value_t find_value = 13;
const auto equals_val = EqualsValFunctor<value_type>(find_value);
auto std_result =
std::find_if(KE::begin(expected), KE::end(expected), equals_val);
auto distance = std::distance(KE::begin(expected), std_result);
// pass const iterators, returns const iterator
EXPECT_EQ(
KE::cbegin(view) + distance,
KE::find_if(exespace(), KE::cbegin(view), KE::cend(view), equals_val));
// pass view, returns iterator
EXPECT_EQ(KE::begin(view) + distance,
KE::find_if(exespace(), view, equals_val));
}
template <class ViewType>
void test_find_if_not(const ViewType view) {
using value_t = typename ViewType::value_type;
using view_host_space_t = Kokkos::View<value_t*, Kokkos::HostSpace>;
view_host_space_t expected("count_expected", view.extent(0));
compare_views(expected, view);
const auto not_equals_zero = NotEqualsZeroFunctor<value_type>();
// first value matches
EXPECT_EQ(KE::begin(expected),
std::find_if_not(KE::begin(expected), KE::end(expected),
not_equals_zero));
// pass iterators, returns iterator
EXPECT_EQ(KE::begin(view), KE::find_if_not(exespace(), KE::begin(view),
KE::end(view), not_equals_zero));
// pass view, returns iterator
EXPECT_EQ(KE::begin(view),
KE::find_if_not(exespace(), view, not_equals_zero));
fill_views_inc(view, expected);
const auto equals_zero = EqualsValFunctor<value_type>(0);
auto std_result =
std::find_if_not(KE::begin(expected), KE::end(expected), equals_zero);
auto distance = std::distance(KE::begin(expected), std_result);
// pass const iterators, returns const iterator
EXPECT_EQ(KE::cbegin(view) + distance,
KE::find_if_not(exespace(), KE::cbegin(view), KE::cend(view),
equals_zero));
// pass view, returns const iterator
EXPECT_EQ(KE::begin(view) + distance,
KE::find_if_not(exespace(), view, equals_zero));
}
template <class Tag, class ValueType>
void run_all_scenarios() {
for (const auto& scenario : default_scenarios) {
{
auto view = create_view<ValueType>(Tag{}, scenario.second, "find");
test_find(view);
}
{
auto view = create_view<ValueType>(Tag{}, scenario.second, "find_if");
test_find_if(view);
}
{
auto view = create_view<ValueType>(Tag{}, scenario.second, "find_if_not");
test_find_if_not(view);
}
}
}
TEST(std_algorithms_find_test, test) {
run_all_scenarios<DynamicTag, double>();
run_all_scenarios<StridedTwoTag, int>();
run_all_scenarios<StridedThreeTag, unsigned>();
}
} // namespace Find
} // namespace stdalgos
} // namespace Test

View File

@ -0,0 +1,387 @@
/*
//@HEADER
// ************************************************************************
//
// Kokkos v. 3.0
// Copyright (2020) 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.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the Corporation nor the names of the
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Questions? Contact Christian R. Trott (crtrott@sandia.gov)
//
// ************************************************************************
//@HEADER
*/
#include <TestStdAlgorithmsCommon.hpp>
#include <std_algorithms/Kokkos_BeginEnd.hpp>
#include <std_algorithms/Kokkos_ModifyingSequenceOperations.hpp>
#include <utility>
namespace Test {
namespace stdalgos {
namespace FindEnd {
namespace KE = Kokkos::Experimental;
template <class ValueType>
struct UnifDist;
template <>
struct UnifDist<int> {
using dist_type = std::uniform_int_distribution<int>;
std::mt19937 m_gen;
dist_type m_dist;
UnifDist() : m_dist(0, 20) { m_gen.seed(1034343); }
UnifDist(int a, int b) : m_dist(a, b) { m_gen.seed(234343); }
int operator()() { return m_dist(m_gen); }
};
template <class ViewType>
void fill_view(ViewType dest_view, const std::string& name) {
using value_type = typename ViewType::value_type;
using exe_space = typename ViewType::execution_space;
const std::size_t ext = dest_view.extent(0);
using aux_view_t = Kokkos::View<value_type*, exe_space>;
aux_view_t aux_view("aux_view", ext);
auto v_h = create_mirror_view(Kokkos::HostSpace(), aux_view);
if (name == "empty") {
// no op
}
else if (name == "one-element-a") {
v_h(0) = static_cast<value_type>(1);
}
else if (name == "one-element-b") {
v_h(0) = static_cast<value_type>(2);
}
else if (name == "two-elements-a") {
v_h(0) = static_cast<value_type>(1);
v_h(1) = static_cast<value_type>(2);
}
else if (name == "two-elements-b") {
v_h(0) = static_cast<value_type>(2);
v_h(1) = static_cast<value_type>(-1);
}
else if (name == "three-elements-a") {
v_h(0) = static_cast<value_type>(-1);
v_h(1) = static_cast<value_type>(2);
v_h(2) = static_cast<value_type>(2);
}
else if (name == "three-elements-b") {
v_h(0) = static_cast<value_type>(3);
v_h(1) = static_cast<value_type>(1);
v_h(2) = static_cast<value_type>(3);
}
else if (name == "four-elements-a") {
v_h(0) = static_cast<value_type>(-1);
v_h(1) = static_cast<value_type>(2);
v_h(2) = static_cast<value_type>(2);
v_h(3) = static_cast<value_type>(4);
}
else if (name == "four-elements-b") {
v_h(0) = static_cast<value_type>(1);
v_h(1) = static_cast<value_type>(1);
v_h(2) = static_cast<value_type>(1);
v_h(3) = static_cast<value_type>(1);
}
else if (name == "small-a") {
v_h(0) = static_cast<value_type>(0);
v_h(1) = static_cast<value_type>(4);
v_h(2) = static_cast<value_type>(1);
v_h(3) = static_cast<value_type>(2);
v_h(4) = static_cast<value_type>(-1);
v_h(5) = static_cast<value_type>(4);
v_h(6) = static_cast<value_type>(1);
v_h(7) = static_cast<value_type>(2);
v_h(8) = static_cast<value_type>(2);
v_h(9) = static_cast<value_type>(4);
v_h(10) = static_cast<value_type>(1);
}
else if (name == "small-b") {
v_h(0) = static_cast<value_type>(1);
v_h(1) = static_cast<value_type>(2);
v_h(2) = static_cast<value_type>(3);
v_h(3) = static_cast<value_type>(1);
v_h(4) = static_cast<value_type>(-1);
v_h(5) = static_cast<value_type>(-2);
v_h(6) = static_cast<value_type>(0);
v_h(7) = static_cast<value_type>(1);
v_h(8) = static_cast<value_type>(2);
v_h(9) = static_cast<value_type>(2);
v_h(10) = static_cast<value_type>(5);
v_h(11) = static_cast<value_type>(9);
v_h(12) = static_cast<value_type>(8);
}
else {
UnifDist<value_type> randObj;
for (std::size_t i = 0; i < ext; ++i) {
v_h(i) = randObj();
}
}
Kokkos::deep_copy(aux_view, v_h);
CopyFunctor<aux_view_t, ViewType> F1(aux_view, dest_view);
Kokkos::parallel_for("copy", dest_view.extent(0), F1);
}
template <class ViewType>
auto create_seq(ViewType data_view, std::size_t seq_extent) {
// we need to specify a sequence that we search for
// within the original view/range.
// to do this, rather than doing something purely random,
// we use the view with the data, and select a subsequence.
auto data_view_h = create_host_space_copy(data_view);
const auto data_view_extent = data_view.extent(0);
using value_type = typename ViewType::value_type;
using exe_space = typename ViewType::execution_space;
using seq_view_t = Kokkos::View<value_type*, exe_space>;
seq_view_t seq_view("seq_view", seq_extent);
auto seq_view_h = create_mirror_view(Kokkos::HostSpace(), seq_view);
// when the target sequence is of same size as view, just fill
// sequeunce with all values of the view
if (seq_extent == data_view_extent) {
for (std::size_t i = 0; i < seq_extent; ++i) {
seq_view_h(i) = data_view_h(i);
}
} else {
// if target sequence to fill is smaller, then we need to pick
// a starting point to copy data from to make the the sequence.
// we pick randomly between 0 and data_view_extent - seq_extent.
// and fill the sequeunce data with the values copied from data view.
using dist_type = std::uniform_int_distribution<int>;
std::random_device r;
// from this:
// https://stackoverflow.com/questions/34490599/c11-how-to-set-seed-using-random
std::seed_seq seed{r(), r(), r(), r(), r(), r()};
std::mt19937 gen(seed);
dist_type dist(0, data_view_extent - seq_extent);
const auto start = dist(gen);
// std::cout << "start= " << start << "\n";
for (std::size_t i = 0; i < seq_extent; ++i) {
seq_view_h(i) = data_view_h(start + i);
// std::cout << "i= " << i << " " << seq_view_h(i) << "\n";
}
}
Kokkos::deep_copy(seq_view, seq_view_h);
return seq_view;
}
// search is only avai from c++17, so I have to put it here
template <class ForwardIt1, class ForwardIt2, class BinaryPredicate>
ForwardIt1 my_std_search(ForwardIt1 first, ForwardIt1 last, ForwardIt2 s_first,
ForwardIt2 s_last, BinaryPredicate p) {
for (;; ++first) {
ForwardIt1 it = first;
for (ForwardIt2 s_it = s_first;; ++it, ++s_it) {
if (s_it == s_last) {
return first;
}
if (it == last) {
return last;
}
if (!p(*it, *s_it)) {
break;
}
}
}
}
// only avai from c++17, so I have to put it here
template <class ForwardIt1, class ForwardIt2, class BinaryPredicate>
ForwardIt1 my_std_find_end(ForwardIt1 first, ForwardIt1 last,
ForwardIt2 s_first, ForwardIt2 s_last,
BinaryPredicate p) {
if (s_first == s_last) {
return last;
}
ForwardIt1 result = last;
while (true) {
ForwardIt1 new_result = my_std_search(first, last, s_first, s_last, p);
if (new_result == last) {
break;
} else {
result = new_result;
first = result;
++first;
}
}
return result;
}
template <class ForwardIt1, class ForwardIt2>
ForwardIt1 my_std_find_end(ForwardIt1 first, ForwardIt1 last,
ForwardIt2 s_first, ForwardIt2 s_last) {
using value_type1 = typename ForwardIt1::value_type;
using value_type2 = typename ForwardIt2::value_type;
using pred_t = IsEqualFunctor<value_type1, value_type2>;
return my_std_find_end(first, last, s_first, s_last, pred_t());
}
std::string value_type_to_string(int) { return "int"; }
std::string value_type_to_string(double) { return "double"; }
template <class Tag, class ValueType>
void print_scenario_details(const std::string& name, std::size_t seq_ext) {
std::cout << "find_end: default predicate: " << name << ", "
<< "find_end_seq_ext = " << seq_ext << ", "
<< view_tag_to_string(Tag{}) << " "
<< value_type_to_string(ValueType()) << std::endl;
}
template <class Tag, class ValueType, class Predicate>
void print_scenario_details(const std::string& name, std::size_t seq_ext,
Predicate pred) {
(void)pred;
std::cout << "find_end: custom predicate: " << name << ", "
<< "find_end_seq_ext = " << seq_ext << ", "
<< view_tag_to_string(Tag{}) << " "
<< value_type_to_string(ValueType()) << std::endl;
}
template <class Tag, class ValueType, class InfoType, class... Args>
void run_single_scenario(const InfoType& scenario_info, std::size_t seq_ext,
Args... args) {
const auto name = std::get<0>(scenario_info);
const std::size_t view_ext = std::get<1>(scenario_info);
// print_scenario_details<Tag, ValueType>(name, seq_ext, args...);
auto view = create_view<ValueType>(Tag{}, view_ext, "find_end_test_view");
fill_view(view, name);
auto s_view = create_seq(view, seq_ext);
// run std
auto view_h = create_host_space_copy(view);
auto s_view_h = create_host_space_copy(s_view);
auto stdrit =
my_std_find_end(KE::cbegin(view_h), KE::cend(view_h),
KE::cbegin(s_view_h), KE::cend(s_view_h), args...);
{
auto myrit = KE::find_end(exespace(), KE::cbegin(view), KE::cend(view),
KE::cbegin(s_view), KE::cend(s_view), args...);
const auto mydiff = myrit - KE::cbegin(view);
const auto stddiff = stdrit - KE::cbegin(view_h);
// std::cout << "result : " << mydiff << " " << stddiff << std::endl;
EXPECT_TRUE(mydiff == stddiff);
}
{
auto myrit =
KE::find_end("label", exespace(), KE::cbegin(view), KE::cend(view),
KE::cbegin(s_view), KE::cend(s_view), args...);
const auto mydiff = myrit - KE::cbegin(view);
const auto stddiff = stdrit - KE::cbegin(view_h);
EXPECT_TRUE(mydiff == stddiff);
}
{
auto myrit = KE::find_end(exespace(), view, s_view, args...);
const auto mydiff = myrit - KE::begin(view);
const auto stddiff = stdrit - KE::cbegin(view_h);
EXPECT_TRUE(mydiff == stddiff);
}
{
auto myrit = KE::find_end("label", exespace(), view, s_view, args...);
const auto mydiff = myrit - KE::begin(view);
const auto stddiff = stdrit - KE::cbegin(view_h);
EXPECT_TRUE(mydiff == stddiff);
}
Kokkos::fence();
}
template <class Tag, class ValueType>
void run_all_scenarios() {
const std::map<std::string, std::size_t> scenarios = {{"empty", 0},
{"one-element-a", 1},
{"one-element-b", 1},
{"two-elements-a", 2},
{"two-elements-b", 2},
{"three-elements-a", 3},
{"three-elements-b", 3},
{"four-elements-a", 4},
{"four-elements-b", 4},
{"small-a", 11},
{"small-b", 13},
{"medium-a", 11103},
{"medium-b", 21103},
{"large-a", 101513},
{"large-b", 100111}};
const std::vector<std::size_t> seq_extents = {
0, 1, 2, 3, 4, 5, 8, 11, 15, 31, 113, 523, 1035, 11103};
// for each scenario we want to run "find_end"
// for a set of sequences of various extents
for (const auto& it : scenarios) {
for (const auto& it2 : seq_extents) {
// only run if view is larger or equal than sequence
if (it.second >= it2) {
run_single_scenario<Tag, ValueType>(it, it2);
using func_t = IsEqualFunctor<ValueType>;
run_single_scenario<Tag, ValueType>(it, it2, func_t());
}
}
}
}
TEST(std_algorithms_non_mod_seq_ops, find_end) {
run_all_scenarios<DynamicTag, int>();
run_all_scenarios<StridedThreeTag, int>();
}
} // namespace FindEnd
} // namespace stdalgos
} // namespace Test

View File

@ -0,0 +1,303 @@
/*
//@HEADER
// ************************************************************************
//
// Kokkos v. 3.0
// Copyright (2020) 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.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the Corporation nor the names of the
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Questions? Contact Christian R. Trott (crtrott@sandia.gov)
//
// ************************************************************************
//@HEADER
*/
#include <TestStdAlgorithmsCommon.hpp>
#include <std_algorithms/Kokkos_BeginEnd.hpp>
#include <std_algorithms/Kokkos_ModifyingSequenceOperations.hpp>
#include <utility>
namespace Test {
namespace stdalgos {
namespace FindFirstOf {
namespace KE = Kokkos::Experimental;
template <class ValueType>
struct UnifDist;
template <>
struct UnifDist<int> {
using dist_type = std::uniform_int_distribution<int>;
std::mt19937 m_gen;
dist_type m_dist;
UnifDist() : m_dist(-100, 100) { m_gen.seed(1034343); }
UnifDist(int a, int b) : m_dist(a, b) { m_gen.seed(514343); }
int operator()() { return m_dist(m_gen); }
};
template <class ViewType>
void fill_view(ViewType dest_view, const std::string& name) {
using value_type = typename ViewType::value_type;
using exe_space = typename ViewType::execution_space;
const std::size_t ext = dest_view.extent(0);
using aux_view_t = Kokkos::View<value_type*, exe_space>;
aux_view_t aux_view("aux_view", ext);
auto v_h = create_mirror_view(Kokkos::HostSpace(), aux_view);
if (name == "empty") {
// no op
}
else if (name == "one-element-a") {
v_h(0) = static_cast<value_type>(1);
}
else if (name == "one-element-b") {
v_h(0) = static_cast<value_type>(2);
}
else if (name == "two-elements-a") {
v_h(0) = static_cast<value_type>(1);
v_h(1) = static_cast<value_type>(2);
}
else if (name == "two-elements-b") {
v_h(0) = static_cast<value_type>(2);
v_h(1) = static_cast<value_type>(-1);
}
else if (name == "three-elements-a") {
v_h(0) = static_cast<value_type>(-1);
v_h(1) = static_cast<value_type>(2);
v_h(2) = static_cast<value_type>(3);
}
else if (name == "three-elements-b") {
v_h(0) = static_cast<value_type>(3);
v_h(1) = static_cast<value_type>(1);
v_h(2) = static_cast<value_type>(-4);
}
else if (name == "four-elements-a") {
v_h(0) = static_cast<value_type>(-1);
v_h(1) = static_cast<value_type>(2);
v_h(2) = static_cast<value_type>(2);
v_h(3) = static_cast<value_type>(4);
}
else if (name == "four-elements-b") {
v_h(0) = static_cast<value_type>(1);
v_h(1) = static_cast<value_type>(1);
v_h(2) = static_cast<value_type>(1);
v_h(3) = static_cast<value_type>(1);
}
else if (name == "small-a") {
v_h(0) = static_cast<value_type>(0);
v_h(1) = static_cast<value_type>(4);
v_h(2) = static_cast<value_type>(1);
v_h(3) = static_cast<value_type>(2);
v_h(4) = static_cast<value_type>(-1);
v_h(5) = static_cast<value_type>(4);
v_h(6) = static_cast<value_type>(1);
v_h(7) = static_cast<value_type>(2);
v_h(8) = static_cast<value_type>(2);
v_h(9) = static_cast<value_type>(4);
v_h(10) = static_cast<value_type>(1);
}
else if (name == "small-b") {
v_h(0) = static_cast<value_type>(1);
v_h(1) = static_cast<value_type>(2);
v_h(2) = static_cast<value_type>(3);
v_h(3) = static_cast<value_type>(1);
v_h(4) = static_cast<value_type>(-1);
v_h(5) = static_cast<value_type>(-2);
v_h(6) = static_cast<value_type>(0);
v_h(7) = static_cast<value_type>(1);
v_h(8) = static_cast<value_type>(2);
v_h(9) = static_cast<value_type>(2);
v_h(10) = static_cast<value_type>(5);
v_h(11) = static_cast<value_type>(9);
v_h(12) = static_cast<value_type>(8);
}
else {
UnifDist<value_type> randObj;
for (std::size_t i = 0; i < ext; ++i) {
v_h(i) = randObj();
}
}
Kokkos::deep_copy(aux_view, v_h);
CopyFunctor<aux_view_t, ViewType> F1(aux_view, dest_view);
Kokkos::parallel_for("copy", dest_view.extent(0), F1);
}
template <class ViewType>
auto create_seq_for_find_first_of(ViewType data_view, std::size_t seq_extent) {
(void)data_view;
using value_type = typename ViewType::value_type;
using exe_space = typename ViewType::execution_space;
using seq_view_t = Kokkos::View<value_type*, exe_space>;
seq_view_t seq_view("seq_view", seq_extent);
auto seq_view_h = create_mirror_view(Kokkos::HostSpace(), seq_view);
UnifDist<value_type> randObj(-10, -10);
for (std::size_t i = 0; i < seq_extent; ++i) {
seq_view_h(i) = randObj();
}
Kokkos::deep_copy(seq_view, seq_view_h);
return seq_view;
}
std::string value_type_to_string(int) { return "int"; }
std::string value_type_to_string(double) { return "double"; }
template <class Tag, class ValueType>
void print_scenario_details(const std::string& name, std::size_t seq_ext) {
std::cout << "find_first_of: default predicate: " << name << ", "
<< "seach_seq_ext = " << seq_ext << ", "
<< view_tag_to_string(Tag{}) << " "
<< value_type_to_string(ValueType()) << std::endl;
}
template <class Tag, class ValueType, class Predicate>
void print_scenario_details(const std::string& name, std::size_t seq_ext,
Predicate pred) {
(void)pred;
std::cout << "find_first_of: custom predicate: " << name << ", "
<< "seach_seq_ext = " << seq_ext << ", "
<< view_tag_to_string(Tag{}) << " "
<< value_type_to_string(ValueType()) << std::endl;
}
template <class Tag, class ValueType, class InfoType, class... Args>
void run_single_scenario(const InfoType& scenario_info, std::size_t seq_ext,
Args... args) {
const auto name = std::get<0>(scenario_info);
const std::size_t view_ext = std::get<1>(scenario_info);
// print_scenario_details<Tag, ValueType>(name, seq_ext, args...);
auto view =
create_view<ValueType>(Tag{}, view_ext, "find_first_of_test_view");
fill_view(view, name);
auto s_view = create_seq_for_find_first_of(view, seq_ext);
// run std
auto view_h = create_host_space_copy(view);
auto s_view_h = create_host_space_copy(s_view);
auto stdrit =
std::find_first_of(KE::cbegin(view_h), KE::cend(view_h),
KE::cbegin(s_view_h), KE::cend(s_view_h), args...);
{
auto myrit =
KE::find_first_of(exespace(), KE::cbegin(view), KE::cend(view),
KE::cbegin(s_view), KE::cend(s_view), args...);
const auto mydiff = myrit - KE::cbegin(view);
const auto stddiff = stdrit - KE::cbegin(view_h);
EXPECT_TRUE(mydiff == stddiff);
}
{
auto myrit =
KE::find_first_of("label", exespace(), KE::cbegin(view), KE::cend(view),
KE::cbegin(s_view), KE::cend(s_view), args...);
const auto mydiff = myrit - KE::cbegin(view);
const auto stddiff = stdrit - KE::cbegin(view_h);
EXPECT_TRUE(mydiff == stddiff);
}
{
auto myrit = KE::find_first_of(exespace(), view, s_view, args...);
const auto mydiff = myrit - KE::begin(view);
const auto stddiff = stdrit - KE::cbegin(view_h);
EXPECT_TRUE(mydiff == stddiff);
}
{
auto myrit = KE::find_first_of("label", exespace(), view, s_view, args...);
const auto mydiff = myrit - KE::begin(view);
const auto stddiff = stdrit - KE::cbegin(view_h);
EXPECT_TRUE(mydiff == stddiff);
}
Kokkos::fence();
}
template <class Tag, class ValueType>
void run_all_scenarios() {
const std::map<std::string, std::size_t> scenarios = {{"empty", 0},
{"one-element-a", 1},
{"one-element-b", 1},
{"two-elements-a", 2},
{"two-elements-b", 2},
{"three-elements-a", 3},
{"three-elements-b", 3},
{"four-elements-a", 4},
{"four-elements-b", 4},
{"small-a", 11},
{"small-b", 13},
{"medium-a", 11103},
{"medium-b", 21103},
{"large-a", 101513},
{"large-b", 100111}};
const std::vector<std::size_t> seq_extents = {0, 1, 2, 3, 4, 5, 8,
11, 20, 31, 113, 523, 1035};
// for each scenario we want to run "find_first_of"
// for a set of sequences of various extents
for (const auto& it : scenarios) {
for (const auto& it2 : seq_extents) {
run_single_scenario<Tag, ValueType>(it, it2);
using func_t = IsEqualFunctor<ValueType>;
run_single_scenario<Tag, ValueType>(it, it2, func_t());
}
}
}
TEST(std_algorithms_non_mod_seq_ops, find_first_of) {
run_all_scenarios<DynamicTag, int>();
run_all_scenarios<StridedThreeTag, int>();
}
} // namespace FindFirstOf
} // namespace stdalgos
} // namespace Test

View File

@ -0,0 +1,167 @@
/*
//@HEADER
// ************************************************************************
//
// Kokkos v. 3.0
// Copyright (2020) 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.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the Corporation nor the names of the
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Questions? Contact Christian R. Trott (crtrott@sandia.gov)
//
// ************************************************************************
//@HEADER
*/
#include <TestStdAlgorithmsCommon.hpp>
#include <std_algorithms/Kokkos_BeginEnd.hpp>
#include <std_algorithms/Kokkos_NonModifyingSequenceOperations.hpp>
#include <algorithm>
namespace Test {
namespace stdalgos {
namespace ForEach {
namespace KE = Kokkos::Experimental;
template <class ViewType>
void test_for_each(const ViewType view) {
using value_t = typename ViewType::value_type;
using view_host_space_t = Kokkos::View<value_t*, Kokkos::HostSpace>;
view_host_space_t expected("for_each_expected", view.extent(0));
compare_views(expected, view);
const auto mod_functor = IncrementElementWiseFunctor<value_t>();
// pass view, functor takes non-const ref
KE::for_each("label", exespace(), view, mod_functor);
std::for_each(KE::begin(expected), KE::end(expected), mod_functor);
compare_views(expected, view);
// pass iterators, functor takes non-const ref
KE::for_each(exespace(), KE::begin(view), KE::end(view), mod_functor);
std::for_each(KE::begin(expected), KE::end(expected), mod_functor);
compare_views(expected, view);
const auto non_mod_functor = NoOpNonMutableFunctor<value_t>();
// pass view, functor takes const ref
KE::for_each(exespace(), view, non_mod_functor);
std::for_each(KE::begin(expected), KE::end(expected), non_mod_functor);
compare_views(expected, view);
// pass const iterators, functor takes const ref
KE::for_each(exespace(), KE::cbegin(view), KE::cend(view), non_mod_functor);
std::for_each(KE::begin(expected), KE::end(expected), non_mod_functor);
compare_views(expected, view);
#if defined(KOKKOS_ENABLE_CXX11_DISPATCH_LAMBDA)
const auto mod_lambda = KOKKOS_LAMBDA(value_t & i) { ++i; };
// pass view, lambda takes non-const ref
KE::for_each(exespace(), view, mod_lambda);
std::for_each(KE::begin(expected), KE::end(expected), mod_lambda);
compare_views(expected, view);
// pass iterators, lambda takes non-const ref
KE::for_each(exespace(), KE::begin(view), KE::end(view), mod_lambda);
std::for_each(KE::begin(expected), KE::end(expected), mod_lambda);
compare_views(expected, view);
const auto non_mod_lambda = KOKKOS_LAMBDA(const value_t& i) { (void)i; };
// pass view, lambda takes const ref
KE::for_each(exespace(), view, non_mod_lambda);
std::for_each(KE::cbegin(expected), KE::cend(expected), non_mod_lambda);
compare_views(expected, view);
// pass const iterators, lambda takes const ref
KE::for_each(exespace(), KE::cbegin(view), KE::cend(view), non_mod_lambda);
std::for_each(KE::cbegin(expected), KE::cend(expected), non_mod_lambda);
compare_views(expected, view);
#endif
}
// std::for_each_n is C++17, so we cannot compare results directly
template <class ViewType>
void test_for_each_n(const ViewType view) {
using value_t = typename ViewType::value_type;
const std::size_t n = view.extent(0);
const auto non_mod_functor = NoOpNonMutableFunctor<value_t>();
// pass const iterators, functor takes const ref
EXPECT_EQ(KE::cbegin(view) + n,
KE::for_each_n(exespace(), KE::cbegin(view), n, non_mod_functor));
verify_values(value_t{0}, view);
// pass view, functor takes const ref
EXPECT_EQ(KE::begin(view) + n,
KE::for_each_n(exespace(), view, n, non_mod_functor));
verify_values(value_t{0}, view);
// pass iterators, functor takes non-const ref
const auto mod_functor = IncrementElementWiseFunctor<value_t>();
EXPECT_EQ(KE::begin(view) + n,
KE::for_each_n(exespace(), KE::begin(view), n, mod_functor));
verify_values(value_t{1}, view);
// pass view, functor takes non-const ref
EXPECT_EQ(KE::begin(view) + n,
KE::for_each_n("label", exespace(), view, n, mod_functor));
verify_values(value_t{2}, view);
}
template <class Tag, class ValueType>
void run_all_scenarios() {
for (const auto& scenario : default_scenarios) {
{
auto view = create_view<ValueType>(Tag{}, scenario.second, "for_each");
test_for_each(view);
}
{
auto view = create_view<ValueType>(Tag{}, scenario.second, "for_each_n");
test_for_each_n(view);
}
}
}
TEST(std_algorithms_for_each_test, test) {
run_all_scenarios<DynamicTag, double>();
run_all_scenarios<StridedTwoTag, int>();
run_all_scenarios<StridedThreeTag, unsigned>();
}
} // namespace ForEach
} // namespace stdalgos
} // namespace Test

View File

@ -0,0 +1,188 @@
/*
//@HEADER
// ************************************************************************
//
// Kokkos v. 3.0
// Copyright (2020) 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.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the Corporation nor the names of the
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Questions? Contact Christian R. Trott (crtrott@sandia.gov)
//
// ************************************************************************
//@HEADER
*/
#ifndef KOKKOS_ALGORITHMS_UNITTESTS_TEST_STD_ALGOS_HELPERS_FUNCTORS_HPP
#define KOKKOS_ALGORITHMS_UNITTESTS_TEST_STD_ALGOS_HELPERS_FUNCTORS_HPP
#include <Kokkos_Core.hpp>
#include <type_traits>
namespace Test {
namespace stdalgos {
template <class ViewTypeFrom, class ViewTypeTo>
struct CopyFunctor {
ViewTypeFrom m_view_from;
ViewTypeTo m_view_to;
CopyFunctor() = delete;
CopyFunctor(const ViewTypeFrom view_from, const ViewTypeTo view_to)
: m_view_from(view_from), m_view_to(view_to) {}
KOKKOS_INLINE_FUNCTION
void operator()(int i) const { m_view_to(i) = m_view_from(i); }
};
template <class ItTypeFrom, class ViewTypeTo>
struct CopyFromIteratorFunctor {
ItTypeFrom m_it_from;
ViewTypeTo m_view_to;
CopyFromIteratorFunctor(const ItTypeFrom it_from, const ViewTypeTo view_to)
: m_it_from(it_from), m_view_to(view_to) {}
KOKKOS_INLINE_FUNCTION
void operator()(int) const { m_view_to() = *m_it_from; }
};
template <class ValueType>
struct IncrementElementWiseFunctor {
KOKKOS_INLINE_FUNCTION
void operator()(ValueType& val) const { ++val; }
};
template <class ViewType>
struct FillZeroFunctor {
ViewType m_view;
KOKKOS_INLINE_FUNCTION
void operator()(int index) const {
m_view(index) = static_cast<typename ViewType::value_type>(0);
}
KOKKOS_INLINE_FUNCTION
FillZeroFunctor(ViewType viewIn) : m_view(viewIn) {}
};
template <class ValueType>
struct NoOpNonMutableFunctor {
KOKKOS_INLINE_FUNCTION
void operator()(const ValueType& val) const { (void)val; }
};
template <class ViewType>
struct AssignIndexFunctor {
ViewType m_view;
AssignIndexFunctor(ViewType view) : m_view(view) {}
KOKKOS_INLINE_FUNCTION
void operator()(int i) const { m_view(i) = typename ViewType::value_type(i); }
};
template <class ValueType>
struct IsEvenFunctor {
static_assert(std::is_integral<ValueType>::value,
"IsEvenFunctor uses operator%, so ValueType must be int");
KOKKOS_INLINE_FUNCTION
bool operator()(const ValueType val) const { return (val % 2 == 0); }
};
template <class ValueType>
struct IsPositiveFunctor {
KOKKOS_INLINE_FUNCTION
bool operator()(const ValueType val) const { return (val > 0); }
};
template <class ValueType>
struct IsNegativeFunctor {
KOKKOS_INLINE_FUNCTION
bool operator()(const ValueType val) const { return (val < 0); }
};
template <class ValueType>
struct NotEqualsZeroFunctor {
KOKKOS_INLINE_FUNCTION
bool operator()(const ValueType val) const { return val != 0; }
};
template <class ValueType>
struct EqualsValFunctor {
const ValueType m_value;
EqualsValFunctor(ValueType value) : m_value(value) {}
KOKKOS_INLINE_FUNCTION
bool operator()(const ValueType val) const { return val == m_value; }
};
template <class ValueType1, class ValueType2>
struct CustomLessThanComparator {
KOKKOS_INLINE_FUNCTION
bool operator()(const ValueType1& a, const ValueType2& b) const {
return a < b;
}
KOKKOS_INLINE_FUNCTION
bool operator()(const volatile ValueType1& a,
const volatile ValueType1& b) const {
return a < b;
}
KOKKOS_INLINE_FUNCTION
CustomLessThanComparator() {}
};
template <class ValueType>
struct CustomEqualityComparator {
KOKKOS_INLINE_FUNCTION
bool operator()(const ValueType& a, const ValueType& b) const {
return a == b;
}
};
template <class ValueType1, class ValueType2 = ValueType1>
struct IsEqualFunctor {
KOKKOS_INLINE_FUNCTION
bool operator()(const ValueType1& a, const ValueType2& b) const {
return (a == b);
}
};
} // namespace stdalgos
} // namespace Test
#endif

View File

@ -0,0 +1,390 @@
/*
//@HEADER
// ************************************************************************
//
// Kokkos v. 3.0
// Copyright (2020) 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.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the Corporation nor the names of the
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Questions? Contact Christian R. Trott (crtrott@sandia.gov)
//
// ************************************************************************
//@HEADER
*/
#include <TestStdAlgorithmsCommon.hpp>
#include <std_algorithms/Kokkos_BeginEnd.hpp>
#include <std_algorithms/Kokkos_Numeric.hpp>
#include <utility>
namespace Test {
namespace stdalgos {
namespace IncScan {
namespace KE = Kokkos::Experimental;
template <class ValueType>
struct UnifDist;
template <>
struct UnifDist<double> {
using dist_type = std::uniform_real_distribution<double>;
std::mt19937 m_gen;
dist_type m_dist;
UnifDist() : m_dist(0.05, 1.2) { m_gen.seed(1034343); }
double operator()() { return m_dist(m_gen); }
};
template <>
struct UnifDist<int> {
using dist_type = std::uniform_int_distribution<int>;
std::mt19937 m_gen;
dist_type m_dist;
UnifDist() : m_dist(1, 3) { m_gen.seed(1034343); }
int operator()() { return m_dist(m_gen); }
};
template <class ViewType>
void fill_zero(ViewType view) {
Kokkos::parallel_for(view.extent(0), FillZeroFunctor<ViewType>(view));
}
template <class ViewType>
void fill_view(ViewType dest_view, const std::string& name) {
using value_type = typename ViewType::value_type;
using exe_space = typename ViewType::execution_space;
const std::size_t ext = dest_view.extent(0);
using aux_view_t = Kokkos::View<value_type*, exe_space>;
aux_view_t aux_view("aux_view", ext);
auto v_h = create_mirror_view(Kokkos::HostSpace(), aux_view);
UnifDist<value_type> randObj;
if (name == "empty") {
// no op
}
else if (name == "one-element") {
v_h(0) = static_cast<value_type>(1);
}
else if (name == "two-elements-a") {
v_h(0) = static_cast<value_type>(1);
v_h(1) = static_cast<value_type>(2);
}
else if (name == "two-elements-b") {
v_h(0) = static_cast<value_type>(2);
v_h(1) = static_cast<value_type>(-1);
}
else if (name == "small-a") {
for (std::size_t i = 0; i < ext; ++i) {
v_h(i) = static_cast<value_type>(i + 1);
}
}
else if (name == "small-b") {
for (std::size_t i = 0; i < ext; ++i) {
v_h(i) = randObj();
}
v_h(5) = static_cast<value_type>(-2);
}
else if (name == "medium-a" || name == "medium-b" || name == "large") {
for (std::size_t i = 0; i < ext; ++i) {
v_h(i) = randObj();
}
}
else {
throw std::runtime_error("invalid choice");
}
Kokkos::deep_copy(aux_view, v_h);
CopyFunctor<aux_view_t, ViewType> F1(aux_view, dest_view);
Kokkos::parallel_for("copy", dest_view.extent(0), F1);
}
// my own because std::inclusive_scan is ONLY found with std=c++17
template <class it1, class it2, class BinOp>
void my_host_inclusive_scan(it1 first, it1 last, it2 dest, BinOp bop) {
if (first != last) {
auto init = *first;
*dest = init;
while (++first < last) {
init = bop(*first, init);
*(++dest) = init;
}
}
}
template <class it1, class it2, class BinOp, class ValType>
void my_host_inclusive_scan(it1 first, it1 last, it2 dest, BinOp bop,
ValType init) {
if (first != last) {
init = bop(*first, init);
*dest = init;
while (++first < last) {
init = bop(*first, init);
*(++dest) = init;
}
}
}
template <class ViewType1, class ViewType2, class BinaryOp, class... Args>
void verify_data(ViewType1 data_view, // contains data
ViewType2 test_view, // the view to test
BinaryOp bop, Args... args /* copy on purpose */) {
//! always careful because views might not be deep copyable
auto data_view_dc = create_deep_copyable_compatible_clone(data_view);
auto data_view_h =
create_mirror_view_and_copy(Kokkos::HostSpace(), data_view_dc);
using gold_view_value_type = typename ViewType2::value_type;
Kokkos::View<gold_view_value_type*, Kokkos::HostSpace> gold_h(
"goldh", data_view.extent(0));
my_host_inclusive_scan(KE::cbegin(data_view_h), KE::cend(data_view_h),
KE::begin(gold_h), bop, args...);
auto test_view_dc = create_deep_copyable_compatible_clone(test_view);
auto test_view_h =
create_mirror_view_and_copy(Kokkos::HostSpace(), test_view_dc);
const auto ext = test_view_h.extent(0);
if (ext > 0) {
for (std::size_t i = 0; i < ext; ++i) {
// std::cout << i << " " << std::setprecision(15) << data_view_h(i) << " "
// << gold_h(i) << " " << test_view_h(i) << " "
// << std::abs(gold_h(i) - test_view_h(i)) << std::endl;
if (std::is_same<gold_view_value_type, int>::value) {
EXPECT_TRUE(gold_h(i) == test_view_h(i));
} else {
const auto error = std::abs(gold_h(i) - test_view_h(i));
if (error > 1e-10) {
std::cout << i << " " << std::setprecision(15) << data_view_h(i)
<< " " << gold_h(i) << " " << test_view_h(i) << " "
<< std::abs(gold_h(i) - test_view_h(i)) << std::endl;
}
EXPECT_TRUE(error < 1e-10);
}
}
// std::cout << " last el: " << test_view_h(ext-1) << std::endl;
}
}
template <class ValueType>
struct MultiplyFunctor {
KOKKOS_INLINE_FUNCTION
ValueType operator()(const ValueType& a, const ValueType& b) const {
return (a * b);
}
KOKKOS_INLINE_FUNCTION
ValueType operator()(const volatile ValueType& a,
const volatile ValueType& b) const {
return (a * b);
}
};
template <class ValueType>
struct SumFunctor {
KOKKOS_INLINE_FUNCTION
ValueType operator()(const ValueType& a, const ValueType& b) const {
return (a + b);
}
KOKKOS_INLINE_FUNCTION
ValueType operator()(const volatile ValueType& a,
const volatile ValueType& b) const {
return (a + b);
}
};
std::string value_type_to_string(int) { return "int"; }
std::string value_type_to_string(double) { return "double"; }
template <class Tag, class ValueType, class InfoType>
void run_single_scenario_default_op(const InfoType& scenario_info) {
using default_op = SumFunctor<ValueType>;
const auto name = std::get<0>(scenario_info);
const std::size_t view_ext = std::get<1>(scenario_info);
// std::cout << "inclusive_scan default op: " << name << ", "
// << view_tag_to_string(Tag{}) << ", "
// << value_type_to_string(ValueType()) << std::endl;
auto view_dest = create_view<ValueType>(Tag{}, view_ext, "inclusive_scan");
auto view_from = create_view<ValueType>(Tag{}, view_ext, "inclusive_scan");
fill_view(view_from, name);
{
fill_zero(view_dest);
auto r = KE::inclusive_scan(exespace(), KE::cbegin(view_from),
KE::cend(view_from), KE::begin(view_dest));
EXPECT_TRUE(r == KE::end(view_dest));
verify_data(view_from, view_dest, default_op());
}
{
fill_zero(view_dest);
auto r = KE::inclusive_scan("label", exespace(), KE::cbegin(view_from),
KE::cend(view_from), KE::begin(view_dest));
EXPECT_TRUE(r == KE::end(view_dest));
verify_data(view_from, view_dest, default_op());
}
{
fill_zero(view_dest);
auto r = KE::inclusive_scan(exespace(), view_from, view_dest);
EXPECT_TRUE(r == KE::end(view_dest));
verify_data(view_from, view_dest, default_op());
}
{
fill_zero(view_dest);
auto r = KE::inclusive_scan("label", exespace(), view_from, view_dest);
EXPECT_TRUE(r == KE::end(view_dest));
verify_data(view_from, view_dest, default_op());
}
Kokkos::fence();
}
template <class Tag, class ValueType, class InfoType, class BinaryOp,
class... Args>
void run_single_scenario_custom_op(const InfoType& scenario_info, BinaryOp bop,
Args... args /* copy on purpose */) {
const auto name = std::get<0>(scenario_info);
const std::size_t view_ext = std::get<1>(scenario_info);
// if (1 == sizeof...(Args)) {
// std::cout << "inclusive_scan custom op and init value: " << name << ", "
// << view_tag_to_string(Tag{}) << ", "
// << value_type_to_string(ValueType()) << ", " << std::endl;
// } else {
// std::cout << "inclusive_scan custom op: " << name << ", "
// << view_tag_to_string(Tag{}) << ", "
// << value_type_to_string(ValueType()) << ", " << std::endl;
// }
auto view_dest = create_view<ValueType>(Tag{}, view_ext, "inclusive_scan");
auto view_from = create_view<ValueType>(Tag{}, view_ext, "inclusive_scan");
fill_view(view_from, name);
{
fill_zero(view_dest);
auto r = KE::inclusive_scan(exespace(), KE::cbegin(view_from),
KE::cend(view_from), KE::begin(view_dest), bop,
args...);
EXPECT_TRUE(r == KE::end(view_dest));
verify_data(view_from, view_dest, bop, args...);
}
{
fill_zero(view_dest);
auto r = KE::inclusive_scan("label", exespace(), KE::cbegin(view_from),
KE::cend(view_from), KE::begin(view_dest), bop,
args...);
EXPECT_TRUE(r == KE::end(view_dest));
verify_data(view_from, view_dest, bop, args...);
}
{
fill_zero(view_dest);
auto r = KE::inclusive_scan(exespace(), view_from, view_dest, bop, args...);
EXPECT_TRUE(r == KE::end(view_dest));
verify_data(view_from, view_dest, bop, args...);
}
{
fill_zero(view_dest);
auto r = KE::inclusive_scan("label", exespace(), view_from, view_dest, bop,
args...);
EXPECT_TRUE(r == KE::end(view_dest));
verify_data(view_from, view_dest, bop, args...);
}
Kokkos::fence();
}
template <class Tag, class ValueType>
void run_inclusive_scan_all_scenarios() {
const std::map<std::string, std::size_t> scenarios = {
{"empty", 0}, {"one-element", 1}, {"two-elements-a", 2},
{"two-elements-b", 2}, {"small-a", 9}, {"small-b", 13},
{"medium-a", 313}, {"medium-b", 1103}, {"large", 10513}};
for (const auto& it : scenarios) {
run_single_scenario_default_op<Tag, ValueType>(it);
#if not defined KOKKOS_ENABLE_OPENMPTARGET
// the sum custom op is always run
using sum_binary_op = SumFunctor<ValueType>;
sum_binary_op sbop;
run_single_scenario_custom_op<Tag, ValueType>(it, sbop);
run_single_scenario_custom_op<Tag, ValueType>(it, sbop, ValueType{0});
run_single_scenario_custom_op<Tag, ValueType>(it, sbop, ValueType{1});
run_single_scenario_custom_op<Tag, ValueType>(it, sbop, ValueType{-2});
run_single_scenario_custom_op<Tag, ValueType>(it, sbop, ValueType{3});
// custom multiply only for small views to avoid overflows
if (it.first == "small-a" || it.first == "small-b") {
using mult_binary_op = MultiplyFunctor<ValueType>;
mult_binary_op mbop;
run_single_scenario_custom_op<Tag, ValueType>(it, mbop);
run_single_scenario_custom_op<Tag, ValueType>(it, mbop, ValueType{0});
run_single_scenario_custom_op<Tag, ValueType>(it, mbop, ValueType{1});
run_single_scenario_custom_op<Tag, ValueType>(it, mbop, ValueType{-2});
run_single_scenario_custom_op<Tag, ValueType>(it, mbop, ValueType{3});
}
#endif
}
}
TEST(std_algorithms_numeric_ops_test, inclusive_scan) {
run_inclusive_scan_all_scenarios<DynamicTag, double>();
run_inclusive_scan_all_scenarios<StridedThreeTag, double>();
run_inclusive_scan_all_scenarios<DynamicTag, int>();
run_inclusive_scan_all_scenarios<StridedThreeTag, int>();
}
} // namespace IncScan
} // namespace stdalgos
} // namespace Test

View File

@ -0,0 +1,222 @@
/*
//@HEADER
// ************************************************************************
//
// Kokkos v. 3.0
// Copyright (2020) 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.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the Corporation nor the names of the
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Questions? Contact Christian R. Trott (crtrott@sandia.gov)
//
// ************************************************************************
//@HEADER
*/
#include <TestStdAlgorithmsCommon.hpp>
#include <std_algorithms/Kokkos_BeginEnd.hpp>
#include <std_algorithms/Kokkos_SortingOperations.hpp>
#include <utility>
namespace Test {
namespace stdalgos {
namespace IsSorted {
namespace KE = Kokkos::Experimental;
template <class ViewType>
void fill_view(ViewType dest_view, const std::string& name) {
using value_type = typename ViewType::value_type;
using exe_space = typename ViewType::execution_space;
const std::size_t ext = dest_view.extent(0);
using aux_view_t = Kokkos::View<value_type*, exe_space>;
aux_view_t aux_view("aux_view", ext);
auto v_h = create_mirror_view(Kokkos::HostSpace(), aux_view);
if (name == "empty") {
// no op
}
else if (name == "one-element") {
v_h(0) = static_cast<value_type>(1);
}
else if (name == "two-elements-a") {
v_h(0) = static_cast<value_type>(1);
v_h(1) = static_cast<value_type>(2);
}
else if (name == "two-elements-b") {
v_h(0) = static_cast<value_type>(2);
v_h(1) = static_cast<value_type>(-1);
}
else if (name == "small-a") {
for (std::size_t i = 0; i < ext; ++i) {
v_h(i) = static_cast<value_type>(i);
}
}
else if (name == "small-b") {
for (std::size_t i = 0; i < ext; ++i) {
v_h(i) = static_cast<value_type>(i);
}
v_h(5) = static_cast<value_type>(-15);
}
else if (name == "medium-a") {
for (std::size_t i = 0; i < ext; ++i) {
v_h(i) = static_cast<value_type>(i);
}
}
else if (name == "medium-b") {
for (std::size_t i = 0; i < ext; ++i) {
v_h(i) = static_cast<value_type>(i);
}
v_h(4) = static_cast<value_type>(-1);
}
else if (name == "large-a") {
for (std::size_t i = 0; i < ext; ++i) {
v_h(i) = static_cast<value_type>(-100) + static_cast<value_type>(i);
}
}
else if (name == "large-b") {
for (std::size_t i = 0; i < ext; ++i) {
v_h(i) = static_cast<value_type>(-100) + static_cast<value_type>(i);
}
v_h(156) = static_cast<value_type>(-250);
}
else {
throw std::runtime_error("invalid choice");
}
Kokkos::deep_copy(aux_view, v_h);
CopyFunctor<aux_view_t, ViewType> F1(aux_view, dest_view);
Kokkos::parallel_for("copy", dest_view.extent(0), F1);
}
bool compute_gold(const std::string& name) {
if (name == "empty") {
return true;
} else if (name == "one-element") {
return true;
} else if (name == "two-elements-a") {
return true;
} else if (name == "two-elements-b") {
return false;
} else if (name == "small-a") {
return true;
} else if (name == "small-b") {
return false;
} else if (name == "medium-a") {
return true;
} else if (name == "medium-b") {
return false;
} else if (name == "large-a") {
return true;
} else if (name == "large-b") {
return false;
} else {
throw std::runtime_error("invalid choice");
}
}
template <class Tag, class ValueType, class InfoType>
void run_single_scenario(const InfoType& scenario_info) {
const auto name = std::get<0>(scenario_info);
const std::size_t view_ext = std::get<1>(scenario_info);
// std::cout << "is-sorted: " << name << ", " << view_tag_to_string(Tag{})
// << std::endl;
auto view = create_view<ValueType>(Tag{}, view_ext, "is_sorted");
fill_view(view, name);
const auto gold = compute_gold(name);
std::vector<bool> resultsA(4);
resultsA[0] = KE::is_sorted(exespace(), KE::cbegin(view), KE::cend(view));
resultsA[1] =
KE::is_sorted("label", exespace(), KE::cbegin(view), KE::cend(view));
resultsA[2] = KE::is_sorted(exespace(), view);
resultsA[3] = KE::is_sorted("label", exespace(), view);
const auto allA = std::all_of(resultsA.cbegin(), resultsA.cend(),
[=](bool v) { return v == gold; });
EXPECT_TRUE(allA);
#if not defined KOKKOS_ENABLE_OPENMPTARGET
CustomLessThanComparator<ValueType, ValueType> comp;
std::vector<bool> resultsB(4);
resultsB[0] =
KE::is_sorted(exespace(), KE::cbegin(view), KE::cend(view), comp);
resultsB[1] = KE::is_sorted("label", exespace(), KE::cbegin(view),
KE::cend(view), comp);
resultsB[2] = KE::is_sorted(exespace(), view, comp);
resultsB[3] = KE::is_sorted("label", exespace(), view, comp);
const auto allB = std::all_of(resultsB.cbegin(), resultsB.cend(),
[=](bool v) { return v == gold; });
EXPECT_TRUE(allB);
#endif
Kokkos::fence();
}
template <class Tag, class ValueType>
void run_is_sorted_all_scenarios() {
const std::map<std::string, std::size_t> scenarios = {
{"empty", 0}, {"one-element", 1}, {"two-elements-a", 2},
{"two-elements-b", 2}, {"small-a", 9}, {"small-b", 13},
{"medium-a", 1003}, {"medium-b", 1003}, {"large-a", 101513},
{"large-b", 101513}};
std::cout << "is_sorted: " << view_tag_to_string(Tag{})
<< ", all overloads \n";
for (const auto& it : scenarios) {
run_single_scenario<Tag, ValueType>(it);
}
}
TEST(std_algorithms_sorting_ops_test, is_sorted) {
run_is_sorted_all_scenarios<DynamicTag, double>();
run_is_sorted_all_scenarios<StridedTwoTag, double>();
run_is_sorted_all_scenarios<StridedThreeTag, double>();
}
} // namespace IsSorted
} // namespace stdalgos
} // namespace Test

View File

@ -0,0 +1,225 @@
/*
//@HEADER
// ************************************************************************
//
// Kokkos v. 3.0
// Copyright (2020) 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.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the Corporation nor the names of the
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Questions? Contact Christian R. Trott (crtrott@sandia.gov)
//
// ************************************************************************
//@HEADER
*/
#include <TestStdAlgorithmsCommon.hpp>
#include <std_algorithms/Kokkos_BeginEnd.hpp>
#include <std_algorithms/Kokkos_SortingOperations.hpp>
#include <utility>
namespace Test {
namespace stdalgos {
namespace IsSortedUntil {
namespace KE = Kokkos::Experimental;
template <class ViewType>
void fill_view(ViewType dest_view, const std::string& name) {
using value_type = typename ViewType::value_type;
using exe_space = typename ViewType::execution_space;
const std::size_t ext = dest_view.extent(0);
using aux_view_t = Kokkos::View<value_type*, exe_space>;
aux_view_t aux_view("aux_view", ext);
auto v_h = create_mirror_view(Kokkos::HostSpace(), aux_view);
if (name == "empty") {
// no op
}
else if (name == "one-element") {
v_h(0) = static_cast<value_type>(1);
}
else if (name == "two-elements-a") {
v_h(0) = static_cast<value_type>(1);
v_h(1) = static_cast<value_type>(2);
}
else if (name == "two-elements-b") {
v_h(0) = static_cast<value_type>(2);
v_h(1) = static_cast<value_type>(-1);
}
else if (name == "small-a") {
for (std::size_t i = 0; i < ext; ++i) {
v_h(i) = static_cast<value_type>(i);
}
}
else if (name == "small-b") {
for (std::size_t i = 0; i < ext; ++i) {
v_h(i) = static_cast<value_type>(i);
}
v_h(5) = static_cast<value_type>(15);
}
else if (name == "medium-a") {
for (std::size_t i = 0; i < ext; ++i) {
v_h(i) = static_cast<value_type>(i);
}
}
else if (name == "medium-b") {
for (std::size_t i = 0; i < ext; ++i) {
v_h(i) = static_cast<value_type>(i);
}
v_h(4) = static_cast<value_type>(-1);
}
else if (name == "large-a") {
for (std::size_t i = 0; i < ext; ++i) {
v_h(i) = static_cast<value_type>(-100) + static_cast<value_type>(i);
}
}
else if (name == "large-b") {
for (std::size_t i = 0; i < ext; ++i) {
v_h(i) = static_cast<value_type>(-100) + static_cast<value_type>(i);
}
v_h(156) = static_cast<value_type>(-250);
}
else {
throw std::runtime_error("invalid choice");
}
Kokkos::deep_copy(aux_view, v_h);
CopyFunctor<aux_view_t, ViewType> F1(aux_view, dest_view);
Kokkos::parallel_for("copy", dest_view.extent(0), F1);
}
template <class ViewType>
auto compute_gold(ViewType view, const std::string& name) {
if (name == "empty") {
return KE::end(view);
} else if (name == "one-element") {
return KE::end(view);
} else if (name == "two-elements-a") {
return KE::end(view);
} else if (name == "two-elements-b") {
return KE::begin(view) + 1;
} else if (name == "small-a") {
return KE::end(view);
} else if (name == "small-b") {
return KE::begin(view) + 6;
} else if (name == "medium-a") {
return KE::end(view);
} else if (name == "medium-b") {
return KE::begin(view) + 4;
} else if (name == "large-a") {
return KE::end(view);
} else if (name == "large-b") {
return KE::begin(view) + 156;
} else {
throw std::runtime_error("invalid choice");
}
}
template <class Tag, class ValueType, class InfoType>
void run_single_scenario(const InfoType& scenario_info) {
const auto name = std::get<0>(scenario_info);
const std::size_t view_ext = std::get<1>(scenario_info);
// std::cout << "is-sorted-until: " << name << ", " <<
// view_tag_to_string(Tag{})
// << std::endl;
auto view = create_view<ValueType>(Tag{}, view_ext, "is_sorted_until");
fill_view(view, name);
const auto gold = compute_gold(view, name);
auto r1 = KE::is_sorted_until(exespace(), KE::begin(view), KE::end(view));
auto r2 =
KE::is_sorted_until("label", exespace(), KE::begin(view), KE::end(view));
auto r3 = KE::is_sorted_until(exespace(), view);
auto r4 = KE::is_sorted_until("label", exespace(), view);
EXPECT_TRUE(r1 == gold);
EXPECT_TRUE(r2 == gold);
EXPECT_TRUE(r3 == gold);
EXPECT_TRUE(r4 == gold);
#if not defined KOKKOS_ENABLE_OPENMPTARGET
CustomLessThanComparator<ValueType, ValueType> comp;
auto r5 =
KE::is_sorted_until(exespace(), KE::cbegin(view), KE::cend(view), comp);
auto r6 = KE::is_sorted_until("label", exespace(), KE::cbegin(view),
KE::cend(view), comp);
auto r7 = KE::is_sorted_until(exespace(), view, comp);
auto r8 = KE::is_sorted_until("label", exespace(), view, comp);
#endif
EXPECT_TRUE(r1 == gold);
EXPECT_TRUE(r2 == gold);
EXPECT_TRUE(r3 == gold);
EXPECT_TRUE(r4 == gold);
Kokkos::fence();
}
template <class Tag, class ValueType>
void run_is_sorted_until_all_scenarios() {
const std::map<std::string, std::size_t> scenarios = {
{"empty", 0}, {"one-element", 1}, {"two-elements-a", 2},
{"two-elements-b", 2}, {"small-a", 9}, {"small-b", 13},
{"medium-a", 1003}, {"medium-b", 1003}, {"large-a", 101513},
{"large-b", 101513}};
std::cout << "is_sorted_until: " << view_tag_to_string(Tag{})
<< ", all overloads \n";
for (const auto& it : scenarios) {
run_single_scenario<Tag, ValueType>(it);
}
}
TEST(std_algorithms_sorting_ops_test, is_sorted_until) {
run_is_sorted_until_all_scenarios<DynamicTag, double>();
run_is_sorted_until_all_scenarios<StridedTwoTag, double>();
run_is_sorted_until_all_scenarios<StridedThreeTag, double>();
}
} // namespace IsSortedUntil
} // namespace stdalgos
} // namespace Test

View File

@ -0,0 +1,184 @@
/*
//@HEADER
// ************************************************************************
//
// Kokkos v. 3.0
// Copyright (2020) 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.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the Corporation nor the names of the
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Questions? Contact Christian R. Trott (crtrott@sandia.gov)
//
// ************************************************************************
//@HEADER
*/
#include <TestStdAlgorithmsCommon.hpp>
#include <std_algorithms/Kokkos_BeginEnd.hpp>
#include <std_algorithms/Kokkos_NonModifyingSequenceOperations.hpp>
#include <std_algorithms/Kokkos_ModifyingSequenceOperations.hpp>
#include <algorithm>
namespace Test {
namespace stdalgos {
namespace LexicographicalCompare {
namespace KE = Kokkos::Experimental;
template <class ViewType1, class ViewType2>
void test_lexicographical_compare(const ViewType1 view_1, ViewType2 view_2) {
auto host_copy_1 = create_host_space_copy(view_1);
auto host_copy_2 = create_host_space_copy(view_2);
auto first_1 = KE::begin(view_1);
auto last_1 = KE::end(view_1);
auto first_2 = KE::begin(view_2);
auto last_2 = KE::end(view_2);
auto h_first_1 = KE::begin(host_copy_1);
auto h_last_1 = KE::end(host_copy_1);
auto h_first_2 = KE::begin(host_copy_2);
auto h_last_2 = KE::end(host_copy_2);
{
// default comparator
auto std_result =
std::lexicographical_compare(h_first_1, h_last_1, h_first_2, h_last_2);
// pass iterators
EXPECT_EQ(std_result, KE::lexicographical_compare(exespace(), first_1,
last_1, first_2, last_2));
EXPECT_EQ(std_result,
KE::lexicographical_compare("label", exespace(), first_1, last_1,
first_2, last_2));
// pass views
EXPECT_EQ(std_result,
KE::lexicographical_compare(exespace(), view_1, view_2));
EXPECT_EQ(std_result,
KE::lexicographical_compare("label", exespace(), view_1, view_2));
}
{
// custom comparator
using value_t_1 = typename ViewType1::value_type;
using value_t_2 = typename ViewType2::value_type;
const auto custom_comparator =
CustomLessThanComparator<value_t_1, value_t_2>();
auto std_result = std::lexicographical_compare(
h_first_1, h_last_1, h_first_2, h_last_2, custom_comparator);
// pass iterators
EXPECT_EQ(std_result,
KE::lexicographical_compare(exespace(), first_1, last_1, first_2,
last_2, custom_comparator));
EXPECT_EQ(std_result,
KE::lexicographical_compare("label", exespace(), first_1, last_1,
first_2, last_2, custom_comparator));
// pass views
EXPECT_EQ(std_result, KE::lexicographical_compare(
exespace(), view_1, view_2, custom_comparator));
EXPECT_EQ(std_result,
KE::lexicographical_compare("label", exespace(), view_1, view_2,
custom_comparator));
}
{
// empty vs non-empty
auto std_result =
std::lexicographical_compare(h_first_1, h_first_1, h_first_2, h_last_2);
EXPECT_EQ(std_result, KE::lexicographical_compare(
exespace(), first_1, first_1, first_2, last_2));
}
{
// pass shorter range
if (view_1.extent(0) > 1) {
auto std_result = std::lexicographical_compare(h_first_1, h_last_1 - 1,
h_first_2, h_last_2);
EXPECT_EQ(std_result,
KE::lexicographical_compare(exespace(), first_1, last_1 - 1,
first_2, last_2));
}
}
{
// first element smaller
if (view_1.extent(0) > 1) {
KE::fill(exespace(), first_1, first_1 + 1, 1);
KE::fill(exespace(), first_2, first_2 + 1, 2);
EXPECT_TRUE(KE::lexicographical_compare(exespace(), first_1, last_1,
first_2, last_2));
}
}
{
// first element bigger, last element smaller
if (view_1.extent(0) > 2) {
KE::fill(exespace(), first_1, first_1 + 1, 2);
KE::fill(exespace(), first_2, first_2 + 1, 1);
KE::fill(exespace(), last_1 - 1, last_1, 1);
KE::fill(exespace(), last_2 - 1, last_2, 2);
EXPECT_FALSE(KE::lexicographical_compare(exespace(), first_1, last_1,
first_2, last_2));
}
}
}
template <class Tag, class ValueType>
void run_all_scenarios() {
for (const auto& scenario : default_scenarios) {
auto view1 = create_view<ValueType>(Tag{}, scenario.second,
"lexicographical_compare_1");
auto view2 = create_view<ValueType>(Tag{}, scenario.second,
"lexicographical_compare_2");
test_lexicographical_compare(view1, view2);
}
}
TEST(std_algorithms_lexicographical_compare_test, test) {
// FIXME: should this disable only custom comparator tests?
#if not defined KOKKOS_ENABLE_OPENMPTARGET
run_all_scenarios<DynamicTag, double>();
run_all_scenarios<StridedTwoTag, int>();
run_all_scenarios<StridedThreeTag, unsigned>();
#endif
}
} // namespace LexicographicalCompare
} // namespace stdalgos
} // namespace Test

View File

@ -0,0 +1,492 @@
/*
//@HEADER
// ************************************************************************
//
// Kokkos v. 3.0
// Copyright (2020) 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.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the Corporation nor the names of the
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Questions? Contact Christian R. Trott (crtrott@sandia.gov)
//
// ************************************************************************
//@HEADER
*/
#include <TestStdAlgorithmsCommon.hpp>
#include <std_algorithms/Kokkos_MinMaxElementOperations.hpp>
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<int, value_type> 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<int, value_type> 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<int, value_type>, Kokkos::pair<int, value_type>>
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 <class ViewType>
void test_max_element_non_trivial_data(ViewType view);
template <class ViewType>
void test_min_element_non_trivial_data(ViewType view);
template <class ViewType>
void test_minmax_element_non_trivial_data(ViewType view);
template <class ViewType>
void test_max_element_non_trivial_data_custom_comp(ViewType view);
template <class ViewType>
void test_min_element_non_trivial_data_custom_comp(ViewType view);
template <class ViewType>
void test_minmax_element_non_trivial_data_custom_comp(ViewType view);
};
template <class IndexType, class ValueType, class ItType, class TestedViewType>
void std_algo_min_max_test_verify(Kokkos::pair<IndexType, ValueType> goldPair,
const ItType result,
TestedViewType testedView) {
// check that iterator is pointing to right element
EXPECT_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<int>;
result_view_t resultView("result");
CopyFromIteratorFunctor<ItType, result_view_t> 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
EXPECT_EQ(result_v_h(), goldPair.second);
}
template <class GoldSolutionType, class ItType, class TestedViewType>
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 <class ViewType>
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));
EXPECT_TRUE(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);
EXPECT_TRUE(result2 == it1);
}
template <class ViewType>
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));
EXPECT_TRUE(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);
EXPECT_TRUE(result2 == it1);
}
template <class ViewType>
void test_minmax_element_empty_range(ViewType view) {
auto result =
KE::minmax_element(exespace(), KE::cbegin(view), KE::cbegin(view));
EXPECT_TRUE(result.first == KE::cbegin(view));
EXPECT_TRUE(result.second == KE::cbegin(view));
auto it0 = KE::cbegin(view) + 3;
auto it1 = it0;
auto result2 = KE::minmax_element(exespace(), it0, it1);
EXPECT_TRUE(result2.first == it1);
EXPECT_TRUE(result2.second == it1);
}
template <class ViewType>
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 <class ViewType>
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 <class ViewType>
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 not defined KOKKOS_ENABLE_OPENMPTARGET
template <class ViewType>
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<value_type, value_type> 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 <class ViewType>
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<value_type, value_type> 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 <class ViewType>
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<value_type, value_type> 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 not 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 not 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

View File

@ -0,0 +1,228 @@
/*
//@HEADER
// ************************************************************************
//
// Kokkos v. 3.0
// Copyright (2020) 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.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the Corporation nor the names of the
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Questions? Contact Christian R. Trott (crtrott@sandia.gov)
//
// ************************************************************************
//@HEADER
*/
#include <TestStdAlgorithmsCommon.hpp>
#include <iterator>
#include <std_algorithms/Kokkos_BeginEnd.hpp>
#include <std_algorithms/Kokkos_NonModifyingSequenceOperations.hpp>
#include <algorithm>
#include <numeric>
namespace Test {
namespace stdalgos {
namespace Mismatch {
namespace KE = Kokkos::Experimental;
std::string value_type_to_string(int) { return "int"; }
std::string value_type_to_string(double) { return "double"; }
template <class Tag, class ValueType>
void print_scenario_details(std::size_t ext1, std::size_t ext2,
const std::string& flag) {
std::cout << "mismatch: "
<< "ext1 = " << ext1 << ", "
<< "ext2 = " << ext2 << ", " << flag << ", "
<< view_tag_to_string(Tag{}) << ", "
<< value_type_to_string(ValueType()) << std::endl;
}
template <class Tag, class ViewType, class... Args>
void run_single_scenario(ViewType view1, ViewType view2,
const std::string& flag, Args... args) {
using value_type = typename ViewType::value_type;
using exe_space = typename ViewType::execution_space;
using aux_view_t = Kokkos::View<value_type*, exe_space>;
const std::size_t ext1 = view1.extent(0);
const std::size_t ext2 = view2.extent(0);
// print_scenario_details<Tag, value_type>(ext1, ext2, flag);
aux_view_t aux_view1("aux_view1", ext1);
auto v1_h = create_mirror_view(Kokkos::HostSpace(), aux_view1);
aux_view_t aux_view2("aux_view2", ext2);
auto v2_h = create_mirror_view(Kokkos::HostSpace(), aux_view2);
// note that the checks ext1>0 and ext2>0 are there
// otherwise we get an error for CUDA NVCC DEBUG CI
// view is is always filled with 8's
if (ext1 > 0) {
for (std::size_t i = 0; i < ext1; ++i) {
v1_h(i) = static_cast<value_type>(8);
}
}
if (flag == "fill-to-match") {
if (ext2 > 0) {
for (std::size_t i = 0; i < ext2; ++i) {
v2_h(i) = static_cast<value_type>(8);
}
}
}
else if (flag == "fill-to-mismatch") {
// need to make them mismatch, so we fill
// with same value and only modifify the
// second view arbitrarily at middle point
if (ext2 > 0) {
for (std::size_t i = 0; i < ext2; ++i) {
v2_h(i) = static_cast<value_type>(8);
}
// make them mismatch at middle
v2_h(ext2 / 2) = -5;
}
} else {
throw std::runtime_error("Kokkos: stdalgo: test: mismatch: Invalid string");
}
Kokkos::deep_copy(aux_view1, v1_h);
CopyFunctor<aux_view_t, ViewType> F1(aux_view1, view1);
Kokkos::parallel_for("copy1", view1.extent(0), F1);
Kokkos::deep_copy(aux_view2, v2_h);
CopyFunctor<aux_view_t, ViewType> F2(aux_view2, view2);
Kokkos::parallel_for("copy2", view2.extent(0), F2);
// run the std::mismatch on a host copy of the data
auto view1_h = create_host_space_copy(view1);
auto view2_h = create_host_space_copy(view2);
auto f1_h = KE::cbegin(view1_h);
auto l1_h = KE::cend(view1_h);
auto f2_h = KE::cbegin(view2_h);
auto l2_h = KE::cend(view2_h);
auto std_res = std::mismatch(f1_h, l1_h, f2_h, l2_h, args...);
const auto std_diff1 = std_res.first - f1_h;
const auto std_diff2 = std_res.second - f2_h;
{
// check our overloads with iterators
auto f1 = KE::cbegin(view1);
auto l1 = KE::cend(view1);
auto f2 = KE::cbegin(view2);
auto l2 = KE::cend(view2);
auto my_res1 = KE::mismatch(exespace(), f1, l1, f2, l2, args...);
auto my_res2 = KE::mismatch("label", exespace(), f1, l1, f2, l2, args...);
const auto my_diff11 = my_res1.first - f1;
const auto my_diff12 = my_res1.second - f2;
const auto my_diff21 = my_res2.first - f1;
const auto my_diff22 = my_res2.second - f2;
EXPECT_TRUE(my_diff11 == std_diff1);
EXPECT_TRUE(my_diff12 == std_diff2);
EXPECT_TRUE(my_diff21 == std_diff1);
EXPECT_TRUE(my_diff22 == std_diff2);
}
{
// check our overloads with views
auto my_res1 = KE::mismatch(exespace(), view1, view2, args...);
auto my_res2 = KE::mismatch("label", exespace(), view1, view2, args...);
const auto my_diff11 = my_res1.first - KE::begin(view1);
const auto my_diff12 = my_res1.second - KE::begin(view2);
const auto my_diff21 = my_res2.first - KE::begin(view1);
const auto my_diff22 = my_res2.second - KE::begin(view2);
EXPECT_TRUE(my_diff11 == std_diff1);
EXPECT_TRUE(my_diff12 == std_diff2);
EXPECT_TRUE(my_diff21 == std_diff1);
EXPECT_TRUE(my_diff22 == std_diff2);
}
}
template <class Tag, class ValueType>
void run_all_scenarios() {
using vecs_t = std::vector<std::string>;
const std::map<std::string, std::size_t> scenarios = {
{"empty", 0}, {"one-element", 1}, {"two-elements", 2},
{"small", 11}, {"medium", 21103}, {"large", 101513}};
for (const auto& scenario : scenarios) {
{
const std::size_t view1_ext = scenario.second;
auto view1 = create_view<ValueType>(Tag{}, view1_ext, "mismatch_view_1");
// for each view1 scenario, I want to test the case of a
// second view that is smaller, equal size and greater than the view1
const vecs_t view2cases = (scenario.first != "empty")
? vecs_t({"smaller", "equalsize", "larger"})
: vecs_t({"equalsize", "larger"});
for (auto it2 : view2cases) {
std::size_t view2_ext = view1_ext;
// modify extent of view2 based on what we want
if (std::string(it2) == "smaller") {
view2_ext -= 1;
} else if (std::string(it2) == "larger") {
view2_ext += 3;
}
auto view2 =
create_view<ValueType>(Tag{}, view2_ext, "mismatch_view_2");
// and now we want to test both the case view1 and view2 match,
// as well as the case where they don't match
for (const auto& it3 : {"fill-to-match", "fill-to-mismatch"}) {
// run to use default predicate
run_single_scenario<Tag>(view1, view2, it3);
// run using an arbitrary predicate
using predicate_type = IsEqualFunctor<ValueType>;
run_single_scenario<Tag>(view1, view2, it3, predicate_type());
}
}
}
}
}
TEST(std_algorithms_mismatch_test, test) {
run_all_scenarios<DynamicTag, double>();
run_all_scenarios<StridedThreeTag, int>();
}
} // namespace Mismatch
} // namespace stdalgos
} // namespace Test

View File

@ -0,0 +1,209 @@
/*
//@HEADER
// ************************************************************************
//
// Kokkos v. 3.0
// Copyright (2020) 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.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the Corporation nor the names of the
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Questions? Contact Christian R. Trott (crtrott@sandia.gov)
//
// ************************************************************************
//@HEADER
*/
#include <TestStdAlgorithmsCommon.hpp>
#include <std_algorithms/Kokkos_ModifyingOperations.hpp>
namespace Test {
namespace stdalgos {
namespace ModOps {
namespace KE = Kokkos::Experimental;
// ------------
// move
// ------------
struct MyMovableType {
int m_value = 11;
MyMovableType() = default;
MyMovableType(MyMovableType&& other) {
if (this != &other) {
m_value = other.m_value;
other.m_value = -2;
}
}
MyMovableType& operator=(MyMovableType&& other) {
if (this != &other) {
m_value = other.m_value;
other.m_value = -4;
}
return *this;
}
};
TEST(std_algorithms_mod_ops_test, move) {
MyMovableType a;
using move_t = decltype(KE::move(a));
static_assert(std::is_rvalue_reference<move_t>::value, "");
// move constr
MyMovableType b(KE::move(a));
EXPECT_TRUE(b.m_value == 11);
EXPECT_TRUE(a.m_value == -2);
// move assign
MyMovableType c;
c = KE::move(b);
EXPECT_TRUE(c.m_value == 11);
EXPECT_TRUE(b.m_value == -4);
}
template <class ViewType>
struct StdAlgoModSeqOpsTestMove {
ViewType m_view;
KOKKOS_INLINE_FUNCTION
void operator()(const int index) const {
typename ViewType::value_type a{11};
using move_t = decltype(KE::move(a));
static_assert(std::is_rvalue_reference<move_t>::value, "");
m_view(index) = KE::move(a);
}
StdAlgoModSeqOpsTestMove(ViewType view) : m_view(view) {}
};
TEST(std_algorithms_mod_ops_test, move_within_parfor) {
using view_t = Kokkos::View<double*>;
view_t a("a", 10);
StdAlgoModSeqOpsTestMove<view_t> fnc(a);
Kokkos::parallel_for(a.extent(0), fnc);
auto a_h = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), a);
for (std::size_t i = 0; i < a.extent(0); ++i) {
EXPECT_DOUBLE_EQ(a_h(0), 11.);
}
}
// ------------
// swap
// ------------
TEST(std_algorithms_mod_ops_test, swap) {
{
int a = 1;
int b = 2;
KE::swap(a, b);
EXPECT_TRUE(a == 2);
EXPECT_TRUE(b == 1);
}
{
double a = 3.;
double b = 1.;
KE::swap(a, b);
EXPECT_DOUBLE_EQ(a, 1.);
EXPECT_DOUBLE_EQ(b, 3.);
}
}
template <class ViewType>
struct StdAlgoModSeqOpsTestSwap {
ViewType m_view;
KOKKOS_INLINE_FUNCTION
void operator()(const int index) const {
typename ViewType::value_type newval{11};
KE::swap(m_view(index), newval);
}
StdAlgoModSeqOpsTestSwap(ViewType aIn) : m_view(aIn) {}
};
TEST(std_algorithms_mod_ops_test, swap_within_parfor) {
auto a = create_view<double>(stdalgos::DynamicTag{}, 10, "a");
StdAlgoModSeqOpsTestSwap<decltype(a)> fnc(a);
Kokkos::parallel_for(a.extent(0), fnc);
auto a_h = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), a);
for (std::size_t i = 0; i < a.extent(0); ++i) {
EXPECT_DOUBLE_EQ(a_h(0), 11.);
}
}
// ------------
// iter_swap
// ------------
template <class ViewType>
void test_iter_swap(ViewType view) {
/* fill view */
auto F = AssignIndexFunctor<ViewType>(view);
Kokkos::parallel_for(view.extent(0), std::move(F));
/* call iter_swap */
auto it1 = KE::begin(view);
KE::iter_swap(it1, it1 + 3);
KE::iter_swap(it1 + 4, it1 + 6);
/* check result */
using value_type = typename ViewType::value_type;
auto a_dc = create_deep_copyable_compatible_clone(view);
auto a_h = create_mirror_view_and_copy(Kokkos::HostSpace(), a_dc);
EXPECT_TRUE(view.extent(0) == 10);
EXPECT_TRUE(a_h(0) == value_type(3));
EXPECT_TRUE(a_h(1) == value_type(1));
EXPECT_TRUE(a_h(2) == value_type(2));
EXPECT_TRUE(a_h(3) == value_type(0));
EXPECT_TRUE(a_h(4) == value_type(6));
EXPECT_TRUE(a_h(5) == value_type(5));
EXPECT_TRUE(a_h(6) == value_type(4));
EXPECT_TRUE(a_h(7) == value_type(7));
EXPECT_TRUE(a_h(8) == value_type(8));
EXPECT_TRUE(a_h(9) == value_type(9));
}
TEST(std_algorithms_mod_ops_test, iter_swap_static_view) {
auto a = create_view<double>(stdalgos::DynamicTag{}, 10, "a");
test_iter_swap(a);
auto a1 = create_view<double>(stdalgos::StridedTwoTag{}, 10, "a1");
test_iter_swap(a1);
auto a2 = create_view<double>(stdalgos::StridedThreeTag{}, 10, "a2");
test_iter_swap(a2);
}
} // namespace ModOps
} // namespace stdalgos
} // namespace Test

View File

@ -0,0 +1,429 @@
/*
//@HEADER
// ************************************************************************
//
// Kokkos v. 3.0
// Copyright (2020) 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.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the Corporation nor the names of the
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Questions? Contact Christian R. Trott (crtrott@sandia.gov)
//
// ************************************************************************
//@HEADER
*/
#include <TestStdAlgorithmsCommon.hpp>
#include <std_algorithms/Kokkos_ModifyingSequenceOperations.hpp>
#include "std_algorithms/Kokkos_BeginEnd.hpp"
namespace KE = Kokkos::Experimental;
namespace Test {
namespace stdalgos {
struct std_algorithms_mod_seq_ops_test : std_algorithms_test {
public:
virtual void SetUp() {
Kokkos::parallel_for(m_static_view.extent(0),
AssignIndexFunctor<static_view_t>(m_static_view));
}
};
//----------------------------------------------------------------------------
TEST_F(std_algorithms_mod_seq_ops_test, copy) {
auto result = KE::copy(exespace(), KE::begin(m_static_view),
KE::end(m_static_view), KE::begin(m_strided_view));
EXPECT_EQ(KE::end(m_strided_view), result);
compare_views(m_static_view, m_strided_view);
auto result2 = KE::copy(exespace(), KE::begin(m_strided_view),
KE::end(m_strided_view), KE::begin(m_dynamic_view));
EXPECT_EQ(KE::end(m_dynamic_view), result2);
compare_views(m_dynamic_view, m_strided_view);
}
TEST_F(std_algorithms_mod_seq_ops_test, copy_view) {
EXPECT_EQ(KE::end(m_dynamic_view),
KE::copy(exespace(), m_static_view, m_dynamic_view));
compare_views(m_static_view, m_dynamic_view);
EXPECT_EQ(KE::end(m_strided_view),
KE::copy(exespace(), m_dynamic_view, m_strided_view));
compare_views(m_dynamic_view, m_strided_view);
}
TEST_F(std_algorithms_mod_seq_ops_test, copy_n) {
constexpr std::size_t n = 5;
view_host_space_t expected("copy_n_expected");
expected(0) = 0;
expected(1) = 1;
expected(2) = 2;
expected(3) = 3;
expected(4) = 4;
expected(5) = 0;
expected(6) = 0;
expected(7) = 0;
expected(8) = 0;
expected(9) = 0;
// pass iterators
auto first = KE::begin(m_static_view);
auto dest = KE::begin(m_dynamic_view);
EXPECT_EQ(dest + n, KE::copy_n(exespace(), first, n, dest));
compare_views(expected, m_dynamic_view);
// pass views
EXPECT_EQ(KE::begin(m_strided_view) + n,
KE::copy_n(exespace(), m_static_view, n, m_strided_view));
compare_views(expected, m_strided_view);
}
TEST_F(std_algorithms_mod_seq_ops_test, copy_backward) {
auto first = KE::begin(m_static_view);
auto last = KE::end(m_static_view);
auto dest = KE::end(m_dynamic_view);
// pass iterators
EXPECT_EQ(KE::begin(m_dynamic_view),
KE::copy_backward(exespace(), first, last, dest));
compare_views(m_static_view, m_dynamic_view);
// pass views
EXPECT_EQ(KE::begin(m_strided_view),
KE::copy_backward(exespace(), m_static_view, m_strided_view));
compare_views(m_static_view, m_strided_view);
}
TEST_F(std_algorithms_mod_seq_ops_test, reverse_copy) {
view_host_space_t expected("reverse_copy_expected");
expected(0) = 9;
expected(1) = 8;
expected(2) = 7;
expected(3) = 6;
expected(4) = 5;
expected(5) = 4;
expected(6) = 3;
expected(7) = 2;
expected(8) = 1;
expected(9) = 0;
auto first = KE::begin(m_static_view);
auto last = KE::end(m_static_view);
auto dest = KE::begin(m_dynamic_view);
EXPECT_EQ(KE::end(m_dynamic_view),
KE::reverse_copy(exespace(), first, last, dest));
compare_views(expected, m_dynamic_view);
EXPECT_EQ(KE::end(m_strided_view),
KE::reverse_copy(exespace(), m_static_view, m_strided_view));
compare_views(expected, m_strided_view);
}
TEST_F(std_algorithms_mod_seq_ops_test, fill) {
constexpr auto fill_value = 1.0;
view_host_space_t expected("fill_n_expected");
expected(0) = 0;
expected(1) = 0;
expected(2) = 0;
expected(3) = 0;
expected(4) = 0;
expected(5) = 0;
expected(6) = 0;
expected(7) = 0;
expected(8) = fill_value;
expected(9) = fill_value;
// pass iterators
KE::fill(exespace(), KE::begin(m_dynamic_view) + 8, KE::end(m_dynamic_view),
fill_value);
compare_views(expected, m_dynamic_view);
// pass view
KE::fill(exespace(), m_strided_view, fill_value);
verify_values(fill_value, m_strided_view);
}
TEST_F(std_algorithms_mod_seq_ops_test, fill_n) {
constexpr auto fill_n_value = 100.0;
constexpr auto fill_n_new_value = 200.0;
// fill all elements
// pass iterator
EXPECT_EQ(KE::end(m_static_view),
KE::fill_n(exespace(), KE::begin(m_static_view),
m_static_view.extent(0), fill_n_value));
verify_values(fill_n_value, m_static_view);
// pass view
EXPECT_EQ(KE::end(m_strided_view),
KE::fill_n(exespace(), m_strided_view, m_strided_view.extent(0),
fill_n_value));
verify_values(fill_n_value, m_strided_view);
// fill zero elements
// pass view
EXPECT_EQ(KE::begin(m_dynamic_view),
KE::fill_n(exespace(), m_dynamic_view, 0, fill_n_new_value));
// fill single element
// pass iterator
EXPECT_EQ(
KE::begin(m_static_view) + 1,
KE::fill_n(exespace(), KE::begin(m_static_view), 1, fill_n_new_value));
view_host_space_t expected("fill_n_expected");
expected(0) = fill_n_new_value;
expected(1) = fill_n_value;
expected(2) = fill_n_value;
expected(3) = fill_n_value;
expected(4) = fill_n_value;
expected(5) = fill_n_value;
expected(6) = fill_n_value;
expected(7) = fill_n_value;
expected(8) = fill_n_value;
expected(9) = fill_n_value;
compare_views(expected, m_static_view);
}
struct TransformFunctor {
KOKKOS_INLINE_FUNCTION
value_type operator()(const value_type& val) const {
(void)val;
return static_cast<value_type>(-1);
}
};
TEST_F(std_algorithms_mod_seq_ops_test, transform_from_fixture_unary_op) {
view_host_space_t gold_source("transform_expected");
gold_source(0) = 0;
gold_source(1) = 1;
gold_source(2) = 2;
gold_source(3) = 3;
gold_source(4) = 4;
gold_source(5) = 5;
gold_source(6) = 6;
gold_source(7) = 7;
gold_source(8) = 8;
gold_source(9) = 9;
// transform static view, store results in dynamic view
auto r1 = KE::transform(exespace(), KE::begin(m_static_view),
KE::end(m_static_view), KE::begin(m_dynamic_view),
TransformFunctor());
EXPECT_EQ(r1, KE::end(m_dynamic_view));
compare_views(gold_source, m_static_view);
verify_values(-1., m_dynamic_view);
// transform dynamic view, store results in strided view
auto r2 = KE::transform(exespace(), m_dynamic_view, m_strided_view,
TransformFunctor());
EXPECT_EQ(r2, KE::end(m_strided_view));
verify_values(-1., m_dynamic_view);
verify_values(-1., m_strided_view);
// transform strided view, store results in static view
auto r3 = KE::transform(exespace(), m_strided_view, m_static_view,
TransformFunctor());
EXPECT_EQ(r3, KE::end(m_static_view));
verify_values(-1., m_static_view);
verify_values(-1., m_strided_view);
}
struct TransformBinaryFunctor {
KOKKOS_INLINE_FUNCTION
value_type operator()(const value_type& val1, const value_type& val2) const {
return val1 + val2;
}
};
TEST_F(std_algorithms_mod_seq_ops_test, transform_from_fixture_binary_op) {
view_host_space_t expected("transform_expected");
expected(0) = 0;
expected(1) = 1;
expected(2) = 2;
expected(3) = 3;
expected(4) = 4;
expected(5) = 5;
expected(6) = 6;
expected(7) = 7;
expected(8) = 8;
expected(9) = 9;
auto r1 = KE::transform(exespace(), KE::begin(m_static_view),
KE::end(m_static_view), KE::begin(m_dynamic_view),
KE::begin(m_strided_view), TransformBinaryFunctor());
EXPECT_EQ(r1, KE::end(m_strided_view));
compare_views(expected, m_strided_view);
expected(0) = 0;
expected(1) = 2;
expected(2) = 4;
expected(3) = 6;
expected(4) = 8;
expected(5) = 10;
expected(6) = 12;
expected(7) = 14;
expected(8) = 16;
expected(9) = 18;
auto r2 = KE::transform("label", exespace(), m_static_view, m_strided_view,
m_dynamic_view, TransformBinaryFunctor());
EXPECT_EQ(r2, KE::end(m_dynamic_view));
compare_views(expected, m_dynamic_view);
}
constexpr value_type generated_value = 2.0;
struct GenerateFunctor {
KOKKOS_INLINE_FUNCTION
value_type operator()() const { return generated_value; }
};
// cuda illegal instruction error appears for this one:
// constexpr int generate_f() { return generated_value; }
TEST_F(std_algorithms_mod_seq_ops_test, generate) {
// view + functor
KE::generate(exespace(), m_static_view, GenerateFunctor());
verify_values(generated_value, m_static_view);
// iterators + functor
KE::generate(exespace(), KE::begin(m_strided_view), KE::end(m_strided_view),
GenerateFunctor());
verify_values(generated_value, m_strided_view);
}
TEST_F(std_algorithms_mod_seq_ops_test, generate_n) {
// iterator + functor
EXPECT_EQ(KE::end(m_static_view),
KE::generate_n(exespace(), KE::begin(m_static_view),
m_static_view.extent(0), GenerateFunctor()));
verify_values(generated_value, m_static_view);
// view + functor
EXPECT_EQ(KE::end(m_dynamic_view),
KE::generate_n(exespace(), m_dynamic_view, m_dynamic_view.extent(0),
GenerateFunctor()));
verify_values(generated_value, m_dynamic_view);
// view + functor, negative n
EXPECT_EQ(KE::begin(m_strided_view),
KE::generate_n(exespace(), m_strided_view, -1, GenerateFunctor()));
}
// -----------------
// test swap_ranges
// -----------------
template <class ViewType>
struct StdModOpsSwapRangesFillFunctorA {
ViewType m_view;
StdModOpsSwapRangesFillFunctorA(ViewType view) : m_view(view) {}
KOKKOS_INLINE_FUNCTION
void operator()(int i) const { m_view(i) = i; }
};
template <class ViewType>
struct StdModOpsSwapRangesFillFunctorB {
ViewType m_view;
StdModOpsSwapRangesFillFunctorB(ViewType view) : m_view(view) {}
KOKKOS_INLINE_FUNCTION
void operator()(int i) const { m_view(i) = 100 - i; }
};
template <class ViewType>
void test_swap_ranges(ViewType view) {
const auto ext = view.extent(0);
/* fill view_a */
auto FA = StdModOpsSwapRangesFillFunctorA<ViewType>(view);
Kokkos::parallel_for(ext, std::move(FA));
/* fill view_b */
using static_view_type = std_algorithms_test::static_view_t;
static_view_type viewB("viewB");
auto FB = StdModOpsSwapRangesFillFunctorB<static_view_type>(viewB);
Kokkos::parallel_for(ext, std::move(FB));
/* call swap_ranges */
auto first1 = KE::begin(view) + 2;
auto last1 = first1 + 4;
auto first2 = KE::begin(viewB) + 1;
auto r = KE::swap_ranges(exespace(), first1, last1, first2);
EXPECT_EQ(r, first2 + 4);
/* check VIEW_A */
static_view_type checkViewA("tmp");
using cp_func_a_t = CopyFunctor<ViewType, static_view_type>;
parallel_for(ext, cp_func_a_t(view, checkViewA));
auto cvA_h =
Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), checkViewA);
EXPECT_TRUE(cvA_h(0) == 0);
EXPECT_TRUE(cvA_h(1) == 1);
EXPECT_TRUE(cvA_h(2) == 99);
EXPECT_TRUE(cvA_h(3) == 98);
EXPECT_TRUE(cvA_h(4) == 97);
EXPECT_TRUE(cvA_h(5) == 96);
EXPECT_TRUE(cvA_h(6) == 6);
EXPECT_TRUE(cvA_h(7) == 7);
EXPECT_TRUE(cvA_h(8) == 8);
EXPECT_TRUE(cvA_h(9) == 9);
/* check viewB */
static_view_type checkViewB("tmpB");
using cp_func_b_t = CopyFunctor<static_view_type, static_view_type>;
Kokkos::parallel_for(ext, cp_func_b_t(viewB, checkViewB));
auto cvB_h =
Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(), checkViewB);
EXPECT_TRUE(cvB_h(0) == 100);
EXPECT_TRUE(cvB_h(1) == 2);
EXPECT_TRUE(cvB_h(2) == 3);
EXPECT_TRUE(cvB_h(3) == 4);
EXPECT_TRUE(cvB_h(4) == 5);
EXPECT_TRUE(cvB_h(5) == 95);
EXPECT_TRUE(cvB_h(6) == 94);
EXPECT_TRUE(cvB_h(7) == 93);
EXPECT_TRUE(cvB_h(8) == 92);
EXPECT_TRUE(cvB_h(9) == 91);
}
TEST_F(std_algorithms_mod_seq_ops_test, swap_ranges) {
test_swap_ranges(m_static_view);
test_swap_ranges(m_dynamic_view);
test_swap_ranges(m_strided_view);
}
} // namespace stdalgos
} // namespace Test

View File

@ -0,0 +1,716 @@
/*
//@HEADER
// ************************************************************************
//
// Kokkos v. 3.0
// Copyright (2020) 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.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the Corporation nor the names of the
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Questions? Contact Christian R. Trott (crtrott@sandia.gov)
//
// ************************************************************************
//@HEADER
*/
#include <TestStdAlgorithmsCommon.hpp>
#include <std_algorithms/Kokkos_Numeric.hpp>
namespace KE = Kokkos::Experimental;
namespace Test {
namespace stdalgos {
struct CustomValueType {
KOKKOS_INLINE_FUNCTION
CustomValueType(){};
KOKKOS_INLINE_FUNCTION
CustomValueType(value_type val) : value(val){};
KOKKOS_INLINE_FUNCTION
CustomValueType(const CustomValueType& other) { this->value = other.value; }
KOKKOS_INLINE_FUNCTION
value_type& operator()() { return value; }
KOKKOS_INLINE_FUNCTION
const value_type& operator()() const { return value; }
KOKKOS_INLINE_FUNCTION
CustomValueType& operator+=(const CustomValueType& other) {
this->value += other.value;
return *this;
}
KOKKOS_INLINE_FUNCTION
CustomValueType& operator=(const CustomValueType& other) {
this->value = other.value;
return *this;
}
KOKKOS_INLINE_FUNCTION
CustomValueType operator+(const CustomValueType& other) const {
CustomValueType result;
result.value = this->value + other.value;
return result;
}
KOKKOS_INLINE_FUNCTION
CustomValueType operator*(const CustomValueType& other) const {
CustomValueType result;
result.value = this->value * other.value;
return result;
}
KOKKOS_INLINE_FUNCTION
bool operator==(const CustomValueType& other) const {
return this->value == other.value;
}
//
// volatile overloads needed for the kokkos reductions
//
// note the void return
KOKKOS_INLINE_FUNCTION
void operator+=(const volatile CustomValueType& other) volatile {
this->value += other.value;
}
// note the void return
KOKKOS_INLINE_FUNCTION
void operator=(const CustomValueType& other) volatile {
this->value = other.value;
}
KOKKOS_INLINE_FUNCTION
CustomValueType operator+(const volatile CustomValueType& other) const
volatile {
CustomValueType result;
result.value = this->value + other.value;
return result;
}
private:
value_type value = {};
};
template <class ValueType>
struct TimesTwoUnaryTransformFunctor {
KOKKOS_INLINE_FUNCTION
ValueType operator()(const ValueType& a) const { return (a * 2.); }
};
template <class ValueType>
struct MultiplyAndHalveBinaryTransformFunctor {
KOKKOS_INLINE_FUNCTION
ValueType operator()(const ValueType& a, const ValueType& b) const {
return (a * b) * 0.5;
}
};
template <class ValueType>
struct SumJoinFunctor {
KOKKOS_INLINE_FUNCTION
ValueType operator()(const ValueType& a, const ValueType& b) const {
return a + b;
}
KOKKOS_INLINE_FUNCTION
ValueType operator()(const volatile ValueType& a,
const volatile ValueType& b) const {
return a + b;
}
};
struct std_algorithms_numerics_test : public ::testing::Test {
Kokkos::LayoutStride layout{20, 2};
// value_type
using static_view_t = Kokkos::View<value_type[20]>;
using dyn_view_t = Kokkos::View<value_type*>;
using strided_view_t = Kokkos::View<value_type*, Kokkos::LayoutStride>;
static_view_t m_static_view{"std-algo-test-1D-contiguous-view-static"};
dyn_view_t m_dynamic_view{"std-algo-test-1D-contiguous-view-dyn", 20};
strided_view_t m_strided_view{"std-algo-test-1D-strided-view", layout};
// custom scalar (cs)
using static_view_cs_t = Kokkos::View<CustomValueType[20]>;
using dyn_view_cs_t = Kokkos::View<CustomValueType*>;
using strided_view_cs_t =
Kokkos::View<CustomValueType*, Kokkos::LayoutStride>;
static_view_cs_t m_static_view_cs{
"std-algo-test-1D-contiguous-view-static-custom-scalar"};
dyn_view_cs_t m_dynamic_view_cs{
"std-algo-test-1D-contiguous-view-dyn-custom_scalar", 20};
strided_view_cs_t m_strided_view_cs{
"std-algo-test-1D-strided-view-custom-scalar", layout};
template <class ViewFromType, class ViewToType>
void copyPodViewToCustom(ViewFromType v_from, ViewToType v_to) {
for (std::size_t i = 0; i < v_from.extent(0); ++i) {
v_to(i)() = v_from(i);
}
}
void fillFixtureViews() {
static_view_t tmpView("tmpView");
static_view_cs_t tmpViewCs("tmpViewCs");
auto tmp_view_h = Kokkos::create_mirror_view(Kokkos::HostSpace(), tmpView);
auto tmp_view_cs_h =
Kokkos::create_mirror_view(Kokkos::HostSpace(), tmpViewCs);
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.;
tmp_view_h(10) = -2.;
tmp_view_h(11) = -2.;
tmp_view_h(12) = 0.;
tmp_view_h(13) = 2.;
tmp_view_h(14) = 2.;
tmp_view_h(15) = 1.;
tmp_view_h(16) = 1.;
tmp_view_h(17) = 1.;
tmp_view_h(18) = 1.;
tmp_view_h(19) = 0.;
copyPodViewToCustom(tmp_view_h, tmp_view_cs_h);
Kokkos::deep_copy(tmpView, tmp_view_h);
Kokkos::deep_copy(tmpViewCs, tmp_view_cs_h);
CopyFunctor<static_view_t, static_view_t> F1(tmpView, m_static_view);
Kokkos::parallel_for("_std_algo_copy1", 20, F1);
CopyFunctor<static_view_t, dyn_view_t> F2(tmpView, m_dynamic_view);
Kokkos::parallel_for("_std_algo_copy2", 20, F2);
CopyFunctor<static_view_t, strided_view_t> F3(tmpView, m_strided_view);
Kokkos::parallel_for("_std_algo_copy3", 20, F3);
CopyFunctor<static_view_cs_t, static_view_cs_t> F4(tmpViewCs,
m_static_view_cs);
Kokkos::parallel_for("_std_algo_copy4", 20, F4);
CopyFunctor<static_view_cs_t, dyn_view_cs_t> F5(tmpViewCs,
m_dynamic_view_cs);
Kokkos::parallel_for("_std_algo_copy5", 20, F5);
CopyFunctor<static_view_cs_t, strided_view_cs_t> F6(tmpViewCs,
m_strided_view_cs);
Kokkos::parallel_for("_std_algo_copy6", 20, F6);
}
};
#if not defined KOKKOS_ENABLE_OPENMPTARGET
// -------------------------------------------------------------------
// test default case of transform_reduce
//
// test for both POD types and custom scalar types
// -------------------------------------------------------------------
template <class ExecutionSpace, class ViewType1, class ViewType2,
class ValueType>
void run_and_check_transform_reduce_default(ViewType1 first_view,
ViewType2 second_view,
ValueType init_value,
ValueType result_value) {
// trivial cases
const auto r1 = KE::transform_reduce(ExecutionSpace(), KE::cbegin(first_view),
KE::cbegin(first_view),
KE::cbegin(second_view), init_value);
const auto r2 = KE::transform_reduce(
"MYLABEL", ExecutionSpace(), KE::cbegin(first_view),
KE::cbegin(first_view), KE::cbegin(second_view), init_value);
EXPECT_TRUE(r1 == init_value);
EXPECT_TRUE(r2 == init_value);
// non-trivial cases
const auto r3 = KE::transform_reduce(ExecutionSpace(), KE::cbegin(first_view),
KE::cend(first_view),
KE::cbegin(second_view), init_value);
const auto r4 = KE::transform_reduce(
"MYLABEL", ExecutionSpace(), KE::cbegin(first_view), KE::cend(first_view),
KE::cbegin(second_view), init_value);
const auto r5 = KE::transform_reduce(ExecutionSpace(), first_view,
second_view, init_value);
const auto r6 = KE::transform_reduce("MYLABEL", ExecutionSpace(), first_view,
second_view, init_value);
EXPECT_TRUE(r3 == result_value);
EXPECT_TRUE(r4 == result_value);
EXPECT_TRUE(r5 == result_value);
EXPECT_TRUE(r6 == result_value);
}
TEST_F(std_algorithms_numerics_test,
transform_reduce_default_functors_using_pod_value_type) {
fillFixtureViews();
const value_type init0 = 0.;
const value_type init5 = 5.;
const value_type gold0 = 32.;
const value_type gold5 = 37.;
run_and_check_transform_reduce_default<exespace>(
m_static_view, m_dynamic_view, init0, gold0);
run_and_check_transform_reduce_default<exespace>(
m_static_view, m_dynamic_view, init5, gold5);
run_and_check_transform_reduce_default<exespace>(
m_static_view, m_strided_view, init0, gold0);
run_and_check_transform_reduce_default<exespace>(
m_static_view, m_strided_view, init5, gold5);
run_and_check_transform_reduce_default<exespace>(
m_dynamic_view, m_strided_view, init0, gold0);
run_and_check_transform_reduce_default<exespace>(
m_dynamic_view, m_strided_view, init5, gold5);
}
TEST_F(std_algorithms_numerics_test,
transform_reduce_default_functors_using_custom_value_type) {
fillFixtureViews();
const CustomValueType init0{0.};
const CustomValueType init5{5.};
const CustomValueType gold0{32.};
const CustomValueType gold5{37.};
run_and_check_transform_reduce_default<exespace>(
m_static_view_cs, m_dynamic_view_cs, init0, gold0);
run_and_check_transform_reduce_default<exespace>(
m_static_view_cs, m_dynamic_view_cs, init5, gold5);
run_and_check_transform_reduce_default<exespace>(
m_static_view_cs, m_strided_view_cs, init0, gold0);
run_and_check_transform_reduce_default<exespace>(
m_static_view_cs, m_strided_view_cs, init5, gold5);
run_and_check_transform_reduce_default<exespace>(
m_dynamic_view_cs, m_strided_view_cs, init0, gold0);
run_and_check_transform_reduce_default<exespace>(
m_dynamic_view_cs, m_strided_view_cs, init5, gold5);
}
// -------------------------------------------------------------------
// transform_reduce for custom joiner and custom transform op
// test for both POD types and custom scalar types
//
// test overload1 accepting two intervals
//
// Note that in the std, the reducer is called BinaryReductionOp
// but in the Kokkos naming convention, it corresponds to a "joiner"
// that knows how to join two values.
// the "joiner" is assumed to be commutative:
//
// https://en.cppreference.com/w/cpp/algorithm/transform_reduce
//
// -------------------------------------------------------------------
template <class ExecutionSpace, class ViewType1, class ViewType2,
class ValueType, class... Args>
void run_and_check_transform_reduce_overloadA(ViewType1 first_view,
ViewType2 second_view,
ValueType init_value,
ValueType result_value,
Args&&... args) {
// trivial cases
const auto r1 = KE::transform_reduce(
ExecutionSpace(), KE::cbegin(first_view), KE::cbegin(first_view),
KE::cbegin(second_view), init_value, std::forward<Args>(args)...);
const auto r2 =
KE::transform_reduce("MYLABEL", ExecutionSpace(), KE::cbegin(first_view),
KE::cbegin(first_view), KE::cbegin(second_view),
init_value, std::forward<Args>(args)...);
EXPECT_TRUE(r1 == init_value);
EXPECT_TRUE(r2 == init_value);
// non trivial cases
const auto r3 = KE::transform_reduce(
ExecutionSpace(), KE::cbegin(first_view), KE::cend(first_view),
KE::cbegin(second_view), init_value, std::forward<Args>(args)...);
const auto r4 = KE::transform_reduce(
"MYLABEL", ExecutionSpace(), KE::cbegin(first_view), KE::cend(first_view),
KE::cbegin(second_view), init_value, std::forward<Args>(args)...);
const auto r5 =
KE::transform_reduce(ExecutionSpace(), first_view, second_view,
init_value, std::forward<Args>(args)...);
const auto r6 =
KE::transform_reduce("MYLABEL", ExecutionSpace(), first_view, second_view,
init_value, std::forward<Args>(args)...);
EXPECT_TRUE(r3 == result_value);
EXPECT_TRUE(r4 == result_value);
EXPECT_TRUE(r5 == result_value);
EXPECT_TRUE(r6 == result_value);
}
TEST_F(std_algorithms_numerics_test,
transform_reduce_custom_functors_overloadA_using_pod_value_type) {
using joiner_type = SumJoinFunctor<value_type>;
using transf_type = MultiplyAndHalveBinaryTransformFunctor<value_type>;
const value_type init0 = 0.;
const value_type init5 = 5.;
const value_type gold0 = 16.;
const value_type gold5 = 21.;
fillFixtureViews();
run_and_check_transform_reduce_overloadA<exespace>(
m_static_view, m_dynamic_view, init0, gold0, joiner_type(),
transf_type());
run_and_check_transform_reduce_overloadA<exespace>(
m_static_view, m_dynamic_view, init5, gold5, joiner_type(),
transf_type());
run_and_check_transform_reduce_overloadA<exespace>(
m_static_view, m_strided_view, init0, gold0, joiner_type(),
transf_type());
run_and_check_transform_reduce_overloadA<exespace>(
m_static_view, m_strided_view, init5, gold5, joiner_type(),
transf_type());
run_and_check_transform_reduce_overloadA<exespace>(
m_dynamic_view, m_strided_view, init0, gold0, joiner_type(),
transf_type());
run_and_check_transform_reduce_overloadA<exespace>(
m_dynamic_view, m_strided_view, init5, gold5, joiner_type(),
transf_type());
}
TEST_F(std_algorithms_numerics_test,
transform_reduce_custom_functors_overloadA_using_custom_value_type) {
using joiner_type = SumJoinFunctor<CustomValueType>;
using transf_type = MultiplyAndHalveBinaryTransformFunctor<CustomValueType>;
const CustomValueType init0{0.};
const CustomValueType init5{5.};
const CustomValueType gold0{16.};
const CustomValueType gold5{21.};
fillFixtureViews();
run_and_check_transform_reduce_overloadA<exespace>(
m_static_view_cs, m_dynamic_view_cs, init0, gold0, joiner_type(),
transf_type());
run_and_check_transform_reduce_overloadA<exespace>(
m_static_view_cs, m_dynamic_view_cs, init5, gold5, joiner_type(),
transf_type());
run_and_check_transform_reduce_overloadA<exespace>(
m_static_view_cs, m_strided_view_cs, init0, gold0, joiner_type(),
transf_type());
run_and_check_transform_reduce_overloadA<exespace>(
m_static_view_cs, m_strided_view_cs, init5, gold5, joiner_type(),
transf_type());
run_and_check_transform_reduce_overloadA<exespace>(
m_dynamic_view_cs, m_strided_view_cs, init0, gold0, joiner_type(),
transf_type());
run_and_check_transform_reduce_overloadA<exespace>(
m_dynamic_view_cs, m_strided_view_cs, init5, gold5, joiner_type(),
transf_type());
}
// -------------------------------------------------------------------
// transform_reduce for custom joiner and custom transform op
// test for both POD types and custom scalar types
//
// test overload1 accepting single interval/view
//
// Note that in the std, the reducer is called BinaryReductionOp
// but in the Kokkos naming convention, it corresponds to a "joiner"
// that knows how to join two values.
// the "joiner" is assumed to be commutative:
//
// https://en.cppreference.com/w/cpp/algorithm/transform_reduce
//
// -------------------------------------------------------------------
template <class ExecutionSpace, class ViewType, class ValueType, class... Args>
void run_and_check_transform_reduce_overloadB(ViewType view,
ValueType init_value,
ValueType result_value,
Args&&... args) {
// trivial
const auto r1 =
KE::transform_reduce(ExecutionSpace(), KE::cbegin(view), KE::cbegin(view),
init_value, std::forward<Args>(args)...);
const auto r2 = KE::transform_reduce("MYLABEL", ExecutionSpace(),
KE::cbegin(view), KE::cbegin(view),
init_value, std::forward<Args>(args)...);
EXPECT_TRUE(r1 == init_value);
EXPECT_TRUE(r2 == init_value);
// non trivial
const auto r3 =
KE::transform_reduce(ExecutionSpace(), KE::cbegin(view), KE::cend(view),
init_value, std::forward<Args>(args)...);
const auto r4 = KE::transform_reduce("MYLABEL", ExecutionSpace(),
KE::cbegin(view), KE::cend(view),
init_value, std::forward<Args>(args)...);
const auto r5 = KE::transform_reduce(ExecutionSpace(), view, init_value,
std::forward<Args>(args)...);
const auto r6 = KE::transform_reduce("MYLABEL", ExecutionSpace(), view,
init_value, std::forward<Args>(args)...);
EXPECT_TRUE(r3 == result_value);
EXPECT_TRUE(r4 == result_value);
EXPECT_TRUE(r5 == result_value);
EXPECT_TRUE(r6 == result_value);
}
TEST_F(std_algorithms_numerics_test,
transform_reduce_custom_functors_overloadB_using_pod_value_type) {
using joiner_type = SumJoinFunctor<value_type>;
using transf_type = TimesTwoUnaryTransformFunctor<value_type>;
const value_type init0 = 0.;
const value_type init5 = 5.;
const value_type gold0 = 24.;
const value_type gold5 = 29.;
fillFixtureViews();
run_and_check_transform_reduce_overloadB<exespace>(
m_static_view, init0, gold0, joiner_type(), transf_type());
run_and_check_transform_reduce_overloadB<exespace>(
m_dynamic_view, init5, gold5, joiner_type(), transf_type());
run_and_check_transform_reduce_overloadB<exespace>(
m_strided_view, init0, gold0, joiner_type(), transf_type());
}
TEST_F(std_algorithms_numerics_test,
transform_reduce_custom_functors_overloadB_using_custom_value_type) {
using joiner_type = SumJoinFunctor<CustomValueType>;
using transf_type = TimesTwoUnaryTransformFunctor<CustomValueType>;
const CustomValueType init0{0.};
const CustomValueType init5{5.};
const CustomValueType gold0{24.};
const CustomValueType gold5{29.};
fillFixtureViews();
run_and_check_transform_reduce_overloadB<exespace>(
m_static_view_cs, init0, gold0, joiner_type(), transf_type());
run_and_check_transform_reduce_overloadB<exespace>(
m_dynamic_view_cs, init5, gold5, joiner_type(), transf_type());
run_and_check_transform_reduce_overloadB<exespace>(
m_strided_view_cs, init0, gold0, joiner_type(), transf_type());
}
// -------------------------------------------------------------------
// test reduce overload1
//
// test for both POD types and custom scalar types
// -------------------------------------------------------------------
template <class ExecutionSpace, class ViewType, class ValueType>
void run_and_check_reduce_overloadA(ViewType view, ValueType non_trivial_result,
ValueType trivial_result) {
// trivial cases
const auto r1 =
KE::reduce(ExecutionSpace(), KE::cbegin(view), KE::cbegin(view));
const auto r2 = KE::reduce("MYLABEL", ExecutionSpace(), KE::cbegin(view),
KE::cbegin(view));
EXPECT_TRUE(r1 == trivial_result);
EXPECT_TRUE(r2 == trivial_result);
// non trivial cases
const auto r3 =
KE::reduce(ExecutionSpace(), KE::cbegin(view), KE::cend(view));
const auto r4 =
KE::reduce("MYLABEL", ExecutionSpace(), KE::cbegin(view), KE::cend(view));
const auto r5 = KE::reduce(ExecutionSpace(), view);
const auto r6 = KE::reduce("MYLABEL", ExecutionSpace(), view);
EXPECT_TRUE(r3 == non_trivial_result);
EXPECT_TRUE(r4 == non_trivial_result);
EXPECT_TRUE(r5 == non_trivial_result);
EXPECT_TRUE(r6 == non_trivial_result);
}
TEST_F(std_algorithms_numerics_test,
reduce_default_functors_overloadA_using_pod_value_type) {
fillFixtureViews();
const value_type trivial_gold = 0.;
const value_type non_trivial_gold = 12.;
run_and_check_reduce_overloadA<exespace>(m_static_view, non_trivial_gold,
trivial_gold);
run_and_check_reduce_overloadA<exespace>(m_dynamic_view, non_trivial_gold,
trivial_gold);
run_and_check_reduce_overloadA<exespace>(m_strided_view, non_trivial_gold,
trivial_gold);
}
TEST_F(std_algorithms_numerics_test,
reduce_default_functors_overloadA_using_custom_value_type) {
fillFixtureViews();
const CustomValueType trivial_gold{0.};
const CustomValueType non_trivial_gold{12.};
run_and_check_reduce_overloadA<exespace>(m_static_view_cs, non_trivial_gold,
trivial_gold);
run_and_check_reduce_overloadA<exespace>(m_dynamic_view_cs, non_trivial_gold,
trivial_gold);
run_and_check_reduce_overloadA<exespace>(m_strided_view_cs, non_trivial_gold,
trivial_gold);
}
// -------------------------------------------------------------------
// test reduce overload2 with init value
//
// test for both POD types and custom scalar types
// -------------------------------------------------------------------
template <class ExecutionSpace, class ViewType, class ValueType>
void run_and_check_reduce_overloadB(ViewType view, ValueType result_value,
ValueType init_value) {
// trivial cases
const auto r1 = KE::reduce(ExecutionSpace(), KE::cbegin(view),
KE::cbegin(view), init_value);
const auto r2 = KE::reduce("MYLABEL", ExecutionSpace(), KE::cbegin(view),
KE::cbegin(view), init_value);
EXPECT_TRUE(r1 == init_value);
EXPECT_TRUE(r2 == init_value);
// non trivial cases
const auto r3 = KE::reduce(ExecutionSpace(), KE::cbegin(view), KE::cend(view),
init_value);
const auto r4 = KE::reduce("MYLABEL", ExecutionSpace(), KE::cbegin(view),
KE::cend(view), init_value);
const auto r5 = KE::reduce(ExecutionSpace(), view, init_value);
const auto r6 = KE::reduce("MYLABEL", ExecutionSpace(), view, init_value);
EXPECT_TRUE(r3 == result_value);
EXPECT_TRUE(r4 == result_value);
EXPECT_TRUE(r5 == result_value);
EXPECT_TRUE(r6 == result_value);
}
TEST_F(std_algorithms_numerics_test,
reduce_default_functors_overloadB_using_pod_value_type) {
fillFixtureViews();
const value_type init = 5.;
const value_type gold = 17.;
run_and_check_reduce_overloadB<exespace>(m_static_view, gold, init);
run_and_check_reduce_overloadB<exespace>(m_dynamic_view, gold, init);
run_and_check_reduce_overloadB<exespace>(m_strided_view, gold, init);
}
TEST_F(std_algorithms_numerics_test,
reduce_default_functors_overloadB_using_custom_value_type) {
fillFixtureViews();
const CustomValueType init{5.};
const CustomValueType gold{17.};
run_and_check_reduce_overloadB<exespace>(m_static_view_cs, gold, init);
run_and_check_reduce_overloadB<exespace>(m_dynamic_view_cs, gold, init);
run_and_check_reduce_overloadB<exespace>(m_strided_view_cs, gold, init);
}
// -------------------------------------------------------------------
// test reduce overload3 with init value
//
// test for both POD types and custom scalar types
// -------------------------------------------------------------------
template <class ExecutionSpace, class ViewType, class ValueType, class BinaryOp>
void run_and_check_reduce_overloadC(ViewType view, ValueType result_value,
ValueType init_value, BinaryOp joiner) {
// trivial cases
const auto r1 = KE::reduce(ExecutionSpace(), KE::cbegin(view),
KE::cbegin(view), init_value, joiner);
const auto r2 = KE::reduce("MYLABEL", ExecutionSpace(), KE::cbegin(view),
KE::cbegin(view), init_value, joiner);
EXPECT_TRUE(r1 == init_value);
EXPECT_TRUE(r2 == init_value);
// non trivial cases
const auto r3 = KE::reduce(ExecutionSpace(), KE::cbegin(view), KE::cend(view),
init_value, joiner);
const auto r4 = KE::reduce("MYLABEL", ExecutionSpace(), KE::cbegin(view),
KE::cend(view), init_value, joiner);
const auto r5 = KE::reduce(ExecutionSpace(), view, init_value, joiner);
const auto r6 =
KE::reduce("MYLABEL", ExecutionSpace(), view, init_value, joiner);
EXPECT_TRUE(r3 == result_value);
EXPECT_TRUE(r4 == result_value);
EXPECT_TRUE(r5 == result_value);
EXPECT_TRUE(r6 == result_value);
}
TEST_F(std_algorithms_numerics_test,
reduce_custom_functors_using_pod_value_type) {
using joiner_type = SumJoinFunctor<value_type>;
fillFixtureViews();
const value_type init = 5.;
const value_type gold = 17.;
run_and_check_reduce_overloadC<exespace>(m_static_view, gold, init,
joiner_type());
run_and_check_reduce_overloadC<exespace>(m_dynamic_view, gold, init,
joiner_type());
run_and_check_reduce_overloadC<exespace>(m_strided_view, gold, init,
joiner_type());
}
TEST_F(std_algorithms_numerics_test,
reduce_custom_functors_using_custom_value_type) {
using joiner_type = SumJoinFunctor<CustomValueType>;
fillFixtureViews();
const CustomValueType init{5.};
const CustomValueType gold{17.};
run_and_check_reduce_overloadC<exespace>(m_static_view_cs, gold, init,
joiner_type());
run_and_check_reduce_overloadC<exespace>(m_dynamic_view_cs, gold, init,
joiner_type());
run_and_check_reduce_overloadC<exespace>(m_strided_view_cs, gold, init,
joiner_type());
}
#endif // not defined KOKKOS_ENABLE_OPENMPTARGET
} // namespace stdalgos
} // namespace Test

View File

@ -0,0 +1,303 @@
/*
//@HEADER
// ************************************************************************
//
// Kokkos v. 3.0
// Copyright (2020) 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.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the Corporation nor the names of the
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Questions? Contact Christian R. Trott (crtrott@sandia.gov)
//
// ************************************************************************
//@HEADER
*/
#include <TestStdAlgorithmsCommon.hpp>
#include <std_algorithms/Kokkos_BeginEnd.hpp>
#include <std_algorithms/Kokkos_PartitioningOperations.hpp>
#include <utility>
#include <algorithm>
namespace Test {
namespace stdalgos {
namespace PartitionCopy {
namespace KE = Kokkos::Experimental;
template <class ValueType>
struct UnifDist;
template <>
struct UnifDist<int> {
using dist_type = std::uniform_int_distribution<int>;
std::mt19937 m_gen;
dist_type m_dist;
UnifDist() : m_dist(-100, 100) { m_gen.seed(1034343); }
int operator()() { return m_dist(m_gen); }
};
template <class ViewType>
void fill_view(ViewType dest_view, const std::string& name) {
using value_type = typename ViewType::value_type;
using exe_space = typename ViewType::execution_space;
const std::size_t ext = dest_view.extent(0);
using aux_view_t = Kokkos::View<value_type*, exe_space>;
aux_view_t aux_view("aux_view", ext);
auto v_h = create_mirror_view(Kokkos::HostSpace(), aux_view);
if (name == "empty") {
// no op
}
else if (name == "one-element-a") {
v_h(0) = static_cast<value_type>(1);
}
else if (name == "one-element-b") {
v_h(0) = static_cast<value_type>(2);
}
else if (name == "two-elements-a") {
v_h(0) = static_cast<value_type>(1);
v_h(1) = static_cast<value_type>(2);
}
else if (name == "two-elements-b") {
v_h(0) = static_cast<value_type>(2);
v_h(1) = static_cast<value_type>(-1);
}
else if (name == "small-a") {
for (std::size_t i = 0; i < ext; ++i) {
v_h(i) = value_type{-5} + static_cast<value_type>(i + 1);
}
}
else if (name == "small-b") {
for (std::size_t i = 0; i < ext; ++i) {
v_h(i) = static_cast<value_type>(22);
}
}
else if (name == "small-c") {
for (std::size_t i = 0; i < ext; ++i) {
v_h(i) = static_cast<value_type>(-13);
}
}
else if (name == "medium" || name == "large") {
UnifDist<value_type> randObj;
for (std::size_t i = 0; i < ext; ++i) {
v_h(i) = randObj();
}
}
else {
throw std::runtime_error("invalid choice");
}
Kokkos::deep_copy(aux_view, v_h);
CopyFunctor<aux_view_t, ViewType> F1(aux_view, dest_view);
Kokkos::parallel_for("copy", dest_view.extent(0), F1);
}
template <class ViewTypeFrom, class ResultType, class ViewTypeDestTrue,
class ViewTypeDestFalse, class PredType>
void verify_data(const std::string& name, ResultType my_result,
ViewTypeFrom view_from, ViewTypeDestTrue view_dest_true,
ViewTypeDestFalse view_dest_false, PredType pred) {
using value_type = typename ViewTypeFrom::value_type;
static_assert(
std::is_same<value_type, typename ViewTypeDestTrue::value_type>::value,
"");
static_assert(
std::is_same<value_type, typename ViewTypeDestFalse::value_type>::value,
"");
const std::size_t ext = view_from.extent(0);
// create host clone of view_from and run std::partition_copy on it
auto view_from_h = create_host_space_copy(view_from);
std::vector<value_type> std_vec_true(ext, 0);
std::vector<value_type> std_vec_false(ext, 0);
auto std_result =
std::partition_copy(KE::cbegin(view_from_h), KE::cend(view_from_h),
std_vec_true.begin(), std_vec_false.begin(), pred);
const std::size_t std_diff_true = std_result.first - std_vec_true.begin();
const std::size_t std_diff_false = std_result.second - std_vec_false.begin();
const std::size_t my_diff_true = my_result.first - KE::begin(view_dest_true);
const std::size_t my_diff_false =
my_result.second - KE::begin(view_dest_false);
EXPECT_TRUE(std_diff_true == my_diff_true);
EXPECT_TRUE(std_diff_false == my_diff_false);
auto view_dest_true_h = create_host_space_copy(view_dest_true);
for (std::size_t i = 0; i < std_diff_true; ++i) {
EXPECT_TRUE(std_vec_true[i] == view_dest_true_h(i));
// std::cout << "i= " << i << " "
// << " std_true = " << std_vec_true[i] << " "
// << " mine = " << view_dest_true_h(i) << '\n';
}
auto view_dest_false_h = create_host_space_copy(view_dest_false);
for (std::size_t i = 0; i < std_diff_false; ++i) {
EXPECT_TRUE(std_vec_false[i] == view_dest_false_h(i));
// std::cout << "i= " << i << " "
// << " std_false = " << std_vec_false[i] << " "
// << " mine = " << view_dest_false_h(i) << '\n';
}
if (name == "empty") {
EXPECT_TRUE(my_diff_true == 0);
EXPECT_TRUE(my_diff_false == 0);
}
else if (name == "one-element-a") {
EXPECT_TRUE(my_diff_true == 0);
EXPECT_TRUE(my_diff_false == 1);
}
else if (name == "one-element-b") {
EXPECT_TRUE(my_diff_true == 1);
EXPECT_TRUE(my_diff_false == 0);
}
else if (name == "two-elements-a") {
EXPECT_TRUE(my_diff_true == 1);
EXPECT_TRUE(my_diff_false == 1);
}
else if (name == "two-elements-b") {
EXPECT_TRUE(my_diff_true == 1);
EXPECT_TRUE(my_diff_false == 1);
}
else if (name == "small-b") {
EXPECT_TRUE(my_diff_true == 13);
EXPECT_TRUE(my_diff_false == 0);
}
else if (name == "small-c") {
EXPECT_TRUE(my_diff_true == 0);
EXPECT_TRUE(my_diff_false == 15);
}
}
std::string value_type_to_string(int) { return "int"; }
std::string value_type_to_string(double) { return "double"; }
template <class Tag, class ValueType, class InfoType>
void run_single_scenario(const InfoType& scenario_info) {
const auto name = std::get<0>(scenario_info);
const std::size_t view_ext = std::get<1>(scenario_info);
// std::cout << "partition_copy: " << name << ", " <<
// view_tag_to_string(Tag{})
// << ", " << value_type_to_string(ValueType()) << std::endl;
auto view_from =
create_view<ValueType>(Tag{}, view_ext, "partition_copy_from");
IsEvenFunctor<ValueType> pred;
{
auto view_dest_true =
create_view<ValueType>(Tag{}, view_ext, "partition_copy_dest_true");
auto view_dest_false =
create_view<ValueType>(Tag{}, view_ext, "partition_copy_dest_false");
fill_view(view_from, name);
auto result = KE::partition_copy(
exespace(), KE::cbegin(view_from), KE::cend(view_from),
KE::begin(view_dest_true), KE::begin(view_dest_false), pred);
verify_data(name, result, view_from, view_dest_true, view_dest_false, pred);
}
{
auto view_dest_true =
create_view<ValueType>(Tag{}, view_ext, "partition_copy_dest_true");
auto view_dest_false =
create_view<ValueType>(Tag{}, view_ext, "partition_copy_dest_false");
fill_view(view_from, name);
auto result = KE::partition_copy(
"my_label", exespace(), KE::cbegin(view_from), KE::cend(view_from),
KE::begin(view_dest_true), KE::begin(view_dest_false), pred);
verify_data(name, result, view_from, view_dest_true, view_dest_false, pred);
}
{
auto view_dest_true =
create_view<ValueType>(Tag{}, view_ext, "partition_copy_dest_true");
auto view_dest_false =
create_view<ValueType>(Tag{}, view_ext, "partition_copy_dest_false");
fill_view(view_from, name);
auto result = KE::partition_copy(exespace(), view_from, view_dest_true,
view_dest_false, pred);
verify_data(name, result, view_from, view_dest_true, view_dest_false, pred);
}
{
auto view_dest_true =
create_view<ValueType>(Tag{}, view_ext, "partition_copy_dest_true");
auto view_dest_false =
create_view<ValueType>(Tag{}, view_ext, "partition_copy_dest_false");
fill_view(view_from, name);
auto result = KE::partition_copy("my_label", exespace(), view_from,
view_dest_true, view_dest_false, pred);
verify_data(name, result, view_from, view_dest_true, view_dest_false, pred);
}
Kokkos::fence();
}
template <class Tag, class ValueType>
void run_all_scenarios() {
const std::map<std::string, std::size_t> scenarios = {
{"empty", 0}, {"one-element-a", 1},
{"one-element-b", 1}, {"two-elements-a", 2},
{"two-elements-b", 2}, {"small-a", 9},
{"small-b", 13}, {"small-c", 15},
{"medium", 103}}; // {"large", 101513}};
for (const auto& it : scenarios) {
run_single_scenario<Tag, ValueType>(it);
}
}
TEST(std_algorithms_partitioning_ops, partition_copy) {
run_all_scenarios<DynamicTag, int>();
run_all_scenarios<StridedThreeTag, int>();
}
} // namespace PartitionCopy
} // namespace stdalgos
} // namespace Test

View File

@ -0,0 +1,258 @@
/*
//@HEADER
// ************************************************************************
//
// Kokkos v. 3.0
// Copyright (2020) 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.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the Corporation nor the names of the
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Questions? Contact Christian R. Trott (crtrott@sandia.gov)
//
// ************************************************************************
//@HEADER
*/
#include <TestStdAlgorithmsCommon.hpp>
#include <std_algorithms/Kokkos_PartitioningOperations.hpp>
namespace KE = Kokkos::Experimental;
namespace Test {
namespace stdalgos {
struct std_algorithms_partitioning_test : public std_algorithms_test {
enum FixtureViews {
Mixed,
NegativeFirst,
AllNegative,
AllPositive,
NegativeLast,
SingleNegative,
Count
};
void fillFixtureViews(FixtureViews caseNumber) {
static_view_t tmpView("tmpView");
auto tmp_view_h = Kokkos::create_mirror_view(Kokkos::HostSpace(), tmpView);
switch (caseNumber) {
case FixtureViews::Mixed:
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;
break;
case FixtureViews::NegativeFirst:
tmp_view_h(0) = -2;
tmp_view_h(1) = -4;
tmp_view_h(2) = -6;
tmp_view_h(3) = -80;
tmp_view_h(4) = 5;
tmp_view_h(5) = 7;
tmp_view_h(6) = 115;
tmp_view_h(7) = 3;
tmp_view_h(8) = 9;
tmp_view_h(9) = 11;
break;
case FixtureViews::AllNegative:
tmp_view_h(0) = -2;
tmp_view_h(1) = -4;
tmp_view_h(2) = -6;
tmp_view_h(3) = -8;
tmp_view_h(4) = -4;
tmp_view_h(5) = -12;
tmp_view_h(6) = -14;
tmp_view_h(7) = -2;
tmp_view_h(8) = -6;
tmp_view_h(9) = -8;
break;
case FixtureViews::AllPositive:
tmp_view_h(0) = 11;
tmp_view_h(1) = 3;
tmp_view_h(2) = 17;
tmp_view_h(3) = 9;
tmp_view_h(4) = 3;
tmp_view_h(5) = 11;
tmp_view_h(6) = 13;
tmp_view_h(7) = 1;
tmp_view_h(8) = 9;
tmp_view_h(9) = 43;
break;
case FixtureViews::NegativeLast:
tmp_view_h(0) = 1;
tmp_view_h(1) = 11;
tmp_view_h(2) = 1;
tmp_view_h(3) = 33;
tmp_view_h(4) = 3;
tmp_view_h(5) = 3;
tmp_view_h(6) = -3;
tmp_view_h(7) = -5;
tmp_view_h(8) = -5;
tmp_view_h(9) = -10;
break;
case FixtureViews::SingleNegative:
tmp_view_h(0) = -200;
tmp_view_h(1) = 1;
tmp_view_h(2) = 1;
tmp_view_h(3) = 3;
tmp_view_h(4) = 3;
tmp_view_h(5) = 211;
tmp_view_h(6) = 3;
tmp_view_h(7) = 5;
tmp_view_h(8) = 5;
tmp_view_h(9) = 11;
break;
default: break;
}
Kokkos::deep_copy(tmpView, tmp_view_h);
copyInputViewToFixtureViews(tmpView);
}
bool goldSolutionIsPartitioned(FixtureViews caseNumber) const {
switch (caseNumber) {
case Mixed: return false;
case NegativeFirst: return true;
case AllNegative: return true;
case AllPositive: return false;
case NegativeLast: return false;
case SingleNegative: return true;
default: return false;
}
}
int goldSolutionPartitionedPoint(FixtureViews caseNumber) const {
switch (caseNumber) {
case Mixed: return 2;
case NegativeFirst: return 4;
case AllNegative: return 10;
case AllPositive: return 0;
case NegativeLast: return 0;
case SingleNegative: return 1;
default: return -1;
}
}
};
TEST_F(std_algorithms_partitioning_test, is_partitioned_trivial) {
IsNegativeFunctor<value_type> p;
const auto result1 = KE::is_partitioned(exespace(), KE::cbegin(m_static_view),
KE::cbegin(m_static_view), p);
EXPECT_EQ(true, result1);
const auto result2 = KE::is_partitioned(
exespace(), KE::cbegin(m_dynamic_view), KE::cbegin(m_dynamic_view), p);
EXPECT_EQ(true, result2);
const auto result3 = KE::is_partitioned(
exespace(), KE::cbegin(m_strided_view), KE::cbegin(m_strided_view), p);
EXPECT_EQ(true, result3);
}
TEST_F(std_algorithms_partitioning_test, is_partitioned_accepting_iterators) {
const IsNegativeFunctor<value_type> p;
for (int id = 0; id < FixtureViews::Count; ++id) {
fillFixtureViews(static_cast<FixtureViews>(id));
const bool goldBool =
goldSolutionIsPartitioned(static_cast<FixtureViews>(id));
const auto result1 = KE::is_partitioned(
exespace(), KE::cbegin(m_static_view), KE::cend(m_static_view), p);
EXPECT_EQ(goldBool, result1);
const auto result2 = KE::is_partitioned(
exespace(), KE::cbegin(m_dynamic_view), KE::cend(m_dynamic_view), p);
EXPECT_EQ(goldBool, result2);
const auto result3 = KE::is_partitioned(
exespace(), KE::cbegin(m_strided_view), KE::cend(m_strided_view), p);
EXPECT_EQ(goldBool, result3);
}
}
TEST_F(std_algorithms_partitioning_test, is_partitioned_accepting_view) {
const IsNegativeFunctor<value_type> p;
for (int id = 0; id < FixtureViews::Count; ++id) {
fillFixtureViews(static_cast<FixtureViews>(id));
const bool goldBool =
goldSolutionIsPartitioned(static_cast<FixtureViews>(id));
const auto result1 = KE::is_partitioned(exespace(), m_static_view, p);
EXPECT_EQ(goldBool, result1);
const auto result2 = KE::is_partitioned(exespace(), m_dynamic_view, p);
EXPECT_EQ(goldBool, result2);
const auto result3 = KE::is_partitioned(exespace(), m_strided_view, p);
EXPECT_EQ(goldBool, result3);
}
}
TEST_F(std_algorithms_partitioning_test, partition_point) {
const IsNegativeFunctor<value_type> p;
for (int id = 0; id < FixtureViews::Count; ++id) {
fillFixtureViews(static_cast<FixtureViews>(id));
const auto goldIndex =
goldSolutionPartitionedPoint(static_cast<FixtureViews>(id));
auto first1 = KE::cbegin(m_static_view);
auto last1 = KE::cend(m_static_view);
const auto result1 = KE::partition_point(exespace(), first1, last1, p);
EXPECT_EQ(goldIndex, result1 - first1);
auto first2 = KE::cbegin(m_dynamic_view);
auto last2 = KE::cend(m_dynamic_view);
const auto result2 = KE::partition_point(exespace(), first2, last2, p);
EXPECT_EQ(goldIndex, result2 - first2);
auto first3 = KE::cbegin(m_strided_view);
auto last3 = KE::cend(m_strided_view);
const auto result3 = KE::partition_point(exespace(), first3, last3, p);
EXPECT_EQ(goldIndex, result3 - first3);
}
}
} // namespace stdalgos
} // namespace Test

View File

@ -0,0 +1,234 @@
/*
//@HEADER
// ************************************************************************
//
// Kokkos v. 3.0
// Copyright (2020) 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.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the Corporation nor the names of the
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Questions? Contact Christian R. Trott (crtrott@sandia.gov)
//
// ************************************************************************
//@HEADER
*/
#include <TestStdAlgorithmsCommon.hpp>
#include <std_algorithms/Kokkos_BeginEnd.hpp>
#include <std_algorithms/Kokkos_ModifyingSequenceOperations.hpp>
#include <utility>
#include <algorithm>
namespace Test {
namespace stdalgos {
namespace Remove {
namespace KE = Kokkos::Experimental;
constexpr int match_value = 4;
template <class ValueType>
struct UnifDist;
template <>
struct UnifDist<int> {
using dist_type = std::uniform_int_distribution<int>;
std::mt19937 m_gen;
dist_type m_dist;
UnifDist() : m_dist(-100, 100) { m_gen.seed(1034343); }
int operator()() { return m_dist(m_gen); }
};
template <class ViewType>
void fill_view(ViewType dest_view, const std::string& name) {
using value_type = typename ViewType::value_type;
using exe_space = typename ViewType::execution_space;
const std::size_t ext = dest_view.extent(0);
using aux_view_t = Kokkos::View<value_type*, exe_space>;
aux_view_t aux_view("aux_view", ext);
auto v_h = create_mirror_view(Kokkos::HostSpace(), aux_view);
if (name == "empty") {
// no op
}
else if (name == "one-element-a") {
v_h(0) = static_cast<value_type>(1);
}
else if (name == "one-element-b") {
v_h(0) = static_cast<value_type>(match_value);
}
else if (name == "two-elements-a") {
v_h(0) = static_cast<value_type>(1);
v_h(1) = static_cast<value_type>(match_value);
}
else if (name == "two-elements-b") {
v_h(0) = static_cast<value_type>(match_value);
v_h(1) = static_cast<value_type>(-1);
}
else if (name == "small-a") {
for (std::size_t i = 0; i < ext; ++i) {
v_h(i) = static_cast<value_type>(i + 1);
}
}
else if (name == "small-b") {
for (std::size_t i = 0; i < ext; ++i) {
if (i % 2 == 0) {
v_h(i) = static_cast<value_type>(match_value);
} else {
v_h(i) = static_cast<value_type>(-12);
}
}
}
else if (name == "medium" || name == "large") {
UnifDist<value_type> randObj;
for (std::size_t i = 0; i < ext; ++i) {
if (i % 8 == 0) {
v_h(i) = static_cast<value_type>(match_value);
} else {
v_h(i) = randObj();
}
}
}
else {
throw std::runtime_error("invalid choice");
}
Kokkos::deep_copy(aux_view, v_h);
CopyFunctor<aux_view_t, ViewType> F1(aux_view, dest_view);
Kokkos::parallel_for("copy", dest_view.extent(0), F1);
}
template <class ViewTypeData, class ViewTypeTest, class MyItResult>
void verify_data(ViewTypeData view_data_h, ViewTypeTest view_test,
MyItResult my_result) {
// run std::remove
auto std_result =
std::remove(KE::begin(view_data_h), KE::end(view_data_h), match_value);
// check that returned iterators are correct
const std::size_t std_diff = std_result - KE::begin(view_data_h);
const std::size_t my_diff = my_result - KE::begin(view_test);
EXPECT_TRUE(std_diff == my_diff);
// check the actual data after algo has been applied
auto view_test_h = create_host_space_copy(view_test);
for (std::size_t i = 0; i < my_diff; ++i) {
EXPECT_TRUE(view_test_h(i) == view_data_h[i]);
// std::cout << "i= " << i << " "
// << "mine: " << view_test_h(i) << " "
// << "std: " << view_data_h(i)
// << '\n';
}
}
std::string value_type_to_string(int) { return "int"; }
std::string value_type_to_string(double) { return "double"; }
template <class Tag, class ValueType, class InfoType>
void run_single_scenario(const InfoType& scenario_info) {
const auto name = std::get<0>(scenario_info);
const std::size_t view_ext = std::get<1>(scenario_info);
// std::cout << "remove: " << name << ", " << view_tag_to_string(Tag{}) << ",
// "
// << value_type_to_string(ValueType()) << std::endl;
{
auto view = create_view<ValueType>(Tag{}, view_ext, "remove_from");
fill_view(view, name);
// make host copy BEFORE running algo
auto data_h = create_host_space_copy(view);
auto rit = KE::remove(exespace(), KE::begin(view), KE::end(view),
(ValueType)match_value);
verify_data(data_h, view, rit);
}
{
auto view = create_view<ValueType>(Tag{}, view_ext, "remove_from");
fill_view(view, name);
// make host copy BEFORE running algo
auto data_h = create_host_space_copy(view);
auto rit = KE::remove("label", exespace(), KE::begin(view), KE::end(view),
(ValueType)match_value);
verify_data(data_h, view, rit);
}
{
auto view = create_view<ValueType>(Tag{}, view_ext, "remove_from");
fill_view(view, name);
// make host copy BEFORE running algo
auto data_h = create_host_space_copy(view);
auto rit = KE::remove(exespace(), view, (ValueType)match_value);
verify_data(data_h, view, rit);
}
{
auto view = create_view<ValueType>(Tag{}, view_ext, "remove_from");
fill_view(view, name);
// make host copy BEFORE running algo
auto data_h = create_host_space_copy(view);
auto rit = KE::remove("label", exespace(), view, (ValueType)match_value);
verify_data(data_h, view, rit);
}
Kokkos::fence();
}
template <class Tag, class ValueType>
void run_all_scenarios() {
const std::map<std::string, std::size_t> scenarios = {
{"empty", 0}, {"one-element-a", 1}, {"one-element-b", 1},
{"two-elements-a", 2}, {"two-elements-b", 2}, {"small-a", 9},
{"small-b", 13}, {"medium", 13031}, {"large", 101513}};
for (const auto& it : scenarios) {
run_single_scenario<Tag, ValueType>(it);
}
}
TEST(std_algorithms_mod_seq_ops, remove) {
run_all_scenarios<DynamicTag, int>();
run_all_scenarios<StridedThreeTag, int>();
}
} // namespace Remove
} // namespace stdalgos
} // namespace Test

View File

@ -0,0 +1,265 @@
/*
//@HEADER
// ************************************************************************
//
// Kokkos v. 3.0
// Copyright (2020) 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.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the Corporation nor the names of the
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Questions? Contact Christian R. Trott (crtrott@sandia.gov)
//
// ************************************************************************
//@HEADER
*/
#include <TestStdAlgorithmsCommon.hpp>
#include <std_algorithms/Kokkos_BeginEnd.hpp>
#include <std_algorithms/Kokkos_ModifyingSequenceOperations.hpp>
#include <utility>
#include <algorithm>
namespace Test {
namespace stdalgos {
namespace RemoveCopy {
namespace KE = Kokkos::Experimental;
constexpr int match_value = 4;
template <class ValueType>
struct UnifDist;
template <>
struct UnifDist<int> {
using dist_type = std::uniform_int_distribution<int>;
std::mt19937 m_gen;
dist_type m_dist;
UnifDist() : m_dist(-100, 100) { m_gen.seed(1034343); }
int operator()() { return m_dist(m_gen); }
};
template <>
struct UnifDist<double> {
using dist_type = std::uniform_real_distribution<double>;
std::mt19937 m_gen;
dist_type m_dist;
UnifDist() : m_dist(-100., 100.) { m_gen.seed(341043); }
int operator()() { return m_dist(m_gen); }
};
template <class ViewType>
void fill_view(ViewType dest_view, const std::string& name) {
using value_type = typename ViewType::value_type;
using exe_space = typename ViewType::execution_space;
const std::size_t ext = dest_view.extent(0);
using aux_view_t = Kokkos::View<value_type*, exe_space>;
aux_view_t aux_view("aux_view", ext);
auto v_h = create_mirror_view(Kokkos::HostSpace(), aux_view);
if (name == "empty") {
// no op
}
else if (name == "one-element-a") {
v_h(0) = static_cast<value_type>(1);
}
else if (name == "one-element-b") {
v_h(0) = static_cast<value_type>(match_value);
}
else if (name == "two-elements-a") {
v_h(0) = static_cast<value_type>(1);
v_h(1) = static_cast<value_type>(match_value);
}
else if (name == "two-elements-b") {
v_h(0) = static_cast<value_type>(match_value);
v_h(1) = static_cast<value_type>(-1);
}
else if (name == "small-a") {
for (std::size_t i = 0; i < ext; ++i) {
v_h(i) = static_cast<value_type>(i + 1);
}
}
else if (name == "small-b") {
for (std::size_t i = 0; i < ext; ++i) {
if (i % 2 == 0) {
v_h(i) = static_cast<value_type>(match_value);
} else {
v_h(i) = static_cast<value_type>(-12);
}
}
}
else if (name == "medium" || name == "large") {
UnifDist<value_type> randObj;
for (std::size_t i = 0; i < ext; ++i) {
if (i % 8 == 0) {
v_h(i) = static_cast<value_type>(match_value);
} else {
v_h(i) = randObj();
}
}
}
else {
throw std::runtime_error("invalid choice");
}
Kokkos::deep_copy(aux_view, v_h);
CopyFunctor<aux_view_t, ViewType> F1(aux_view, dest_view);
Kokkos::parallel_for("copy", dest_view.extent(0), F1);
}
template <class ViewFromType, class ViewDestType, class MyItResult>
void verify_data(ViewFromType view_from, ViewDestType view_dest,
MyItResult my_result) {
// make a host copy of the view_from
auto view_from_h = create_host_space_copy(view_from);
const std::size_t ext = view_from_h.extent(0);
using value_type = typename ViewFromType::value_type;
// run std::remove_copy
std::vector<value_type> gold_dest_std(ext);
auto std_result =
std::remove_copy(KE::cbegin(view_from_h), KE::cend(view_from_h),
gold_dest_std.begin(), (value_type)match_value);
// check that returned iterators are correct
const std::size_t std_diff = std_result - gold_dest_std.begin();
const std::size_t my_diff = my_result - KE::begin(view_dest);
EXPECT_TRUE(std_diff == my_diff);
// check the actual data after algo has been applied
auto view_dest_h = create_host_space_copy(view_dest);
for (std::size_t i = 0; i < my_diff; ++i) {
EXPECT_TRUE(view_dest_h(i) == gold_dest_std[i]);
// std::cout << "i= " << i << " "
// << "mine: " << view_dest_h(i) << " "
// << "std: " << gold_dest_std[i]
// << '\n';
}
}
std::string value_type_to_string(int) { return "int"; }
std::string value_type_to_string(double) { return "double"; }
template <class Tag, class ValueType, class InfoType>
void run_single_scenario(const InfoType& scenario_info) {
const auto name = std::get<0>(scenario_info);
const std::size_t view_ext = std::get<1>(scenario_info);
// std::cout << "remove_copy: " << name << ", " << view_tag_to_string(Tag{})
// << ", " << value_type_to_string(ValueType()) << std::endl;
{
auto view_from =
create_view<ValueType>(Tag{}, view_ext, "remove_copy_view_from");
fill_view(view_from, name);
auto view_dest =
create_view<ValueType>(Tag{}, view_ext, "remove_copy_view_dest");
auto rit =
KE::remove_copy(exespace(), KE::cbegin(view_from), KE::cend(view_from),
KE::begin(view_dest), (ValueType)match_value);
verify_data(view_from, view_dest, rit);
}
{
auto view_from =
create_view<ValueType>(Tag{}, view_ext, "remove_copy_view_from");
fill_view(view_from, name);
auto view_dest =
create_view<ValueType>(Tag{}, view_ext, "remove_copy_view_dest");
auto rit = KE::remove_copy("label", exespace(), KE::cbegin(view_from),
KE::cend(view_from), KE::begin(view_dest),
(ValueType)match_value);
verify_data(view_from, view_dest, rit);
}
{
auto view_from =
create_view<ValueType>(Tag{}, view_ext, "remove_copy_view_from");
fill_view(view_from, name);
auto view_dest =
create_view<ValueType>(Tag{}, view_ext, "remove_copy_view_dest");
auto rit = KE::remove_copy(exespace(), view_from, view_dest,
(ValueType)match_value);
verify_data(view_from, view_dest, rit);
}
{
auto view_from =
create_view<ValueType>(Tag{}, view_ext, "remove_copy_view_from");
fill_view(view_from, name);
auto view_dest =
create_view<ValueType>(Tag{}, view_ext, "remove_copy_view_dest");
auto rit = KE::remove_copy("label", exespace(), view_from, view_dest,
(ValueType)match_value);
verify_data(view_from, view_dest, rit);
}
Kokkos::fence();
}
template <class Tag, class ValueType>
void run_all_scenarios() {
const std::map<std::string, std::size_t> scenarios = {
{"empty", 0}, {"one-element-a", 1}, {"one-element-b", 1},
{"two-elements-a", 2}, {"two-elements-b", 2}, {"small-a", 9},
{"small-b", 13}, {"medium", 13031}, {"large", 101513}};
for (const auto& it : scenarios) {
run_single_scenario<Tag, ValueType>(it);
}
}
TEST(std_algorithms_mod_seq_ops, remove_copy) {
run_all_scenarios<DynamicTag, int>();
run_all_scenarios<StridedThreeTag, int>();
run_all_scenarios<DynamicTag, double>();
run_all_scenarios<StridedThreeTag, double>();
}
} // namespace RemoveCopy
} // namespace stdalgos
} // namespace Test

View File

@ -0,0 +1,247 @@
/*
//@HEADER
// ************************************************************************
//
// Kokkos v. 3.0
// Copyright (2020) 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.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the Corporation nor the names of the
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Questions? Contact Christian R. Trott (crtrott@sandia.gov)
//
// ************************************************************************
//@HEADER
*/
#include <TestStdAlgorithmsCommon.hpp>
#include <std_algorithms/Kokkos_BeginEnd.hpp>
#include <std_algorithms/Kokkos_ModifyingSequenceOperations.hpp>
#include <utility>
#include <algorithm>
namespace Test {
namespace stdalgos {
namespace RemoveCopyIf {
namespace KE = Kokkos::Experimental;
template <class ValueType>
struct UnifDist;
template <>
struct UnifDist<int> {
using dist_type = std::uniform_int_distribution<int>;
std::mt19937 m_gen;
dist_type m_dist;
UnifDist() : m_dist(-100, 100) { m_gen.seed(1034343); }
int operator()() { return m_dist(m_gen); }
};
template <class ViewType>
void fill_view(ViewType dest_view, const std::string& name) {
using value_type = typename ViewType::value_type;
using exe_space = typename ViewType::execution_space;
const std::size_t ext = dest_view.extent(0);
using aux_view_t = Kokkos::View<value_type*, exe_space>;
aux_view_t aux_view("aux_view", ext);
auto v_h = create_mirror_view(Kokkos::HostSpace(), aux_view);
if (name == "empty") {
// no op
}
else if (name == "one-element-a") {
v_h(0) = static_cast<value_type>(1);
}
else if (name == "one-element-b") {
v_h(0) = static_cast<value_type>(2);
}
else if (name == "two-elements-a") {
v_h(0) = static_cast<value_type>(1);
v_h(1) = static_cast<value_type>(2);
}
else if (name == "two-elements-b") {
v_h(0) = static_cast<value_type>(2);
v_h(1) = static_cast<value_type>(-1);
}
else if (name == "small-a") {
for (std::size_t i = 0; i < ext; ++i) {
v_h(i) = static_cast<value_type>(i + 1);
}
}
else if (name == "small-b") {
for (std::size_t i = 0; i < ext; ++i) {
if (i % 2 == 0) {
v_h(i) = static_cast<value_type>(22);
} else {
v_h(i) = static_cast<value_type>(-12);
}
}
}
else if (name == "medium" || name == "large") {
UnifDist<value_type> randObj;
for (std::size_t i = 0; i < ext; ++i) {
v_h(i) = randObj();
}
}
else {
throw std::runtime_error("invalid choice");
}
Kokkos::deep_copy(aux_view, v_h);
CopyFunctor<aux_view_t, ViewType> F1(aux_view, dest_view);
Kokkos::parallel_for("copy", dest_view.extent(0), F1);
}
template <class ViewTypeFrom, class ViewTypeDest, class MyItResult,
class PredicateType>
void verify_data(ViewTypeFrom view_from, ViewTypeDest view_dest,
MyItResult my_result, PredicateType pred) {
// make a host copy of the view_from
auto view_from_h = create_host_space_copy(view_from);
const std::size_t ext = view_from_h.extent(0);
using value_type = typename ViewTypeFrom::value_type;
// run std::remove_copy_if
std::vector<value_type> gold_dest_std(ext);
auto std_result =
std::remove_copy_if(KE::cbegin(view_from_h), KE::cend(view_from_h),
gold_dest_std.begin(), pred);
// check that returned iterators are correct
const std::size_t std_diff = std_result - gold_dest_std.begin();
const std::size_t my_diff = my_result - KE::begin(view_dest);
EXPECT_TRUE(std_diff == my_diff);
// check the actual data after algo has been applied
auto view_dest_h = create_host_space_copy(view_dest);
for (std::size_t i = 0; i < my_diff; ++i) {
EXPECT_TRUE(view_dest_h(i) == gold_dest_std[i]);
// std::cout << "i= " << i << " "
// << "mine: " << view_dest_h(i) << " "
// << "std: " << gold_dest_std[i]
// << '\n';
}
}
std::string value_type_to_string(int) { return "int"; }
std::string value_type_to_string(double) { return "double"; }
template <class Tag, class ValueType, class InfoType>
void run_single_scenario(const InfoType& scenario_info) {
const auto name = std::get<0>(scenario_info);
const std::size_t view_ext = std::get<1>(scenario_info);
// std::cout << "remove_copy_if: " << name << ", " <<
// view_tag_to_string(Tag{})
// << ", " << value_type_to_string(ValueType()) << std::endl;
using pred_type = IsEvenFunctor<ValueType>;
pred_type remove_if_even;
{
auto view_from =
create_view<ValueType>(Tag{}, view_ext, "remove_copy_if_view_from");
auto view_dest =
create_view<ValueType>(Tag{}, view_ext, "remove_copy_if_view_dest");
fill_view(view_from, name);
auto rit = KE::remove_copy_if(exespace(), KE::cbegin(view_from),
KE::cend(view_from), KE::begin(view_dest),
remove_if_even);
verify_data(view_from, view_dest, rit, remove_if_even);
}
{
auto view_from =
create_view<ValueType>(Tag{}, view_ext, "remove_copy_if_view_from");
auto view_dest =
create_view<ValueType>(Tag{}, view_ext, "remove_copy_if_view_dest");
fill_view(view_from, name);
auto rit = KE::remove_copy_if("label", exespace(), KE::cbegin(view_from),
KE::cend(view_from), KE::begin(view_dest),
remove_if_even);
verify_data(view_from, view_dest, rit, remove_if_even);
}
{
auto view_from =
create_view<ValueType>(Tag{}, view_ext, "remove_copy_if_view_from");
auto view_dest =
create_view<ValueType>(Tag{}, view_ext, "remove_copy_if_view_dest");
fill_view(view_from, name);
auto rit =
KE::remove_copy_if(exespace(), view_from, view_dest, remove_if_even);
verify_data(view_from, view_dest, rit, remove_if_even);
}
{
auto view_from =
create_view<ValueType>(Tag{}, view_ext, "remove_copy_if_view_from");
auto view_dest =
create_view<ValueType>(Tag{}, view_ext, "remove_copy_if_view_dest");
fill_view(view_from, name);
auto rit = KE::remove_copy_if("label", exespace(), view_from, view_dest,
remove_if_even);
verify_data(view_from, view_dest, rit, remove_if_even);
}
Kokkos::fence();
}
template <class Tag, class ValueType>
void run_all_scenarios() {
const std::map<std::string, std::size_t> scenarios = {
{"empty", 0}, {"one-element-a", 1}, {"one-element-b", 1},
{"two-elements-a", 2}, {"two-elements-b", 2}, {"small-a", 9},
{"small-b", 13}, {"medium", 23103}, {"large", 101513}};
for (const auto& it : scenarios) {
run_single_scenario<Tag, ValueType>(it);
}
}
TEST(std_algorithms_mod_seq_ops, remove_copy_if) {
run_all_scenarios<DynamicTag, int>();
run_all_scenarios<StridedThreeTag, int>();
}
} // namespace RemoveCopyIf
} // namespace stdalgos
} // namespace Test

View File

@ -0,0 +1,231 @@
/*
//@HEADER
// ************************************************************************
//
// Kokkos v. 3.0
// Copyright (2020) 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.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the Corporation nor the names of the
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Questions? Contact Christian R. Trott (crtrott@sandia.gov)
//
// ************************************************************************
//@HEADER
*/
#include <TestStdAlgorithmsCommon.hpp>
#include <std_algorithms/Kokkos_BeginEnd.hpp>
#include <std_algorithms/Kokkos_ModifyingSequenceOperations.hpp>
#include <utility>
#include <algorithm>
namespace Test {
namespace stdalgos {
namespace RemoveIf {
namespace KE = Kokkos::Experimental;
template <class ValueType>
struct UnifDist;
template <>
struct UnifDist<int> {
using dist_type = std::uniform_int_distribution<int>;
std::mt19937 m_gen;
dist_type m_dist;
UnifDist() : m_dist(-100, 100) { m_gen.seed(1034343); }
int operator()() { return m_dist(m_gen); }
};
template <class ViewType>
void fill_view(ViewType dest_view, const std::string& name) {
using value_type = typename ViewType::value_type;
using exe_space = typename ViewType::execution_space;
const std::size_t ext = dest_view.extent(0);
using aux_view_t = Kokkos::View<value_type*, exe_space>;
aux_view_t aux_view("aux_view", ext);
auto v_h = create_mirror_view(Kokkos::HostSpace(), aux_view);
if (name == "empty") {
// no op
}
else if (name == "one-element-a") {
v_h(0) = static_cast<value_type>(1);
}
else if (name == "one-element-b") {
v_h(0) = static_cast<value_type>(2);
}
else if (name == "two-elements-a") {
v_h(0) = static_cast<value_type>(1);
v_h(1) = static_cast<value_type>(2);
}
else if (name == "two-elements-b") {
v_h(0) = static_cast<value_type>(2);
v_h(1) = static_cast<value_type>(-1);
}
else if (name == "small-a") {
for (std::size_t i = 0; i < ext; ++i) {
v_h(i) = static_cast<value_type>(i + 1);
}
}
else if (name == "small-b") {
for (std::size_t i = 0; i < ext; ++i) {
if (i % 2 == 0) {
v_h(i) = static_cast<value_type>(22);
} else {
v_h(i) = static_cast<value_type>(-12);
}
}
}
else if (name == "medium" || name == "large") {
UnifDist<value_type> randObj;
for (std::size_t i = 0; i < ext; ++i) {
v_h(i) = randObj();
}
}
else {
throw std::runtime_error("invalid choice");
}
Kokkos::deep_copy(aux_view, v_h);
CopyFunctor<aux_view_t, ViewType> F1(aux_view, dest_view);
Kokkos::parallel_for("copy", dest_view.extent(0), F1);
}
template <class ViewTypeData, class ViewTypeTest, class MyItResult,
class PredicateType>
void verify_data(ViewTypeData view_data_h, ViewTypeTest view_test,
MyItResult my_result, PredicateType pred) {
// run std::remove_if
auto std_result =
std::remove_if(KE::begin(view_data_h), KE::end(view_data_h), pred);
// check that returned iterators are correct
const std::size_t std_diff = std_result - KE::begin(view_data_h);
const std::size_t my_diff = my_result - KE::begin(view_test);
EXPECT_TRUE(std_diff == my_diff);
// check the actual data after algo has been applied
auto view_test_h = create_host_space_copy(view_test);
for (std::size_t i = 0; i < my_diff; ++i) {
EXPECT_TRUE(view_test_h(i) == view_data_h[i]);
// std::cout << "i= " << i << " "
// << "mine: " << view_test_h(i) << " "
// << "std: " << view_data_h(i)
// << '\n';
}
}
std::string value_type_to_string(int) { return "int"; }
std::string value_type_to_string(double) { return "double"; }
template <class Tag, class ValueType, class InfoType>
void run_single_scenario(const InfoType& scenario_info) {
const auto name = std::get<0>(scenario_info);
const std::size_t view_ext = std::get<1>(scenario_info);
// std::cout << "remove_if: " << name << ", " << view_tag_to_string(Tag{})
// << ", " << value_type_to_string(ValueType()) << std::endl;
using pred_type = IsEvenFunctor<ValueType>;
pred_type remove_if_even;
{
auto view = create_view<ValueType>(Tag{}, view_ext, "remove_if_view");
fill_view(view, name);
// make host copy BEFORE running algo
auto data_h = create_host_space_copy(view);
auto rit = KE::remove_if(exespace(), KE::begin(view), KE::end(view),
remove_if_even);
verify_data(data_h, view, rit, remove_if_even);
}
{
auto view = create_view<ValueType>(Tag{}, view_ext, "remove_if_view");
fill_view(view, name);
// make host copy BEFORE running algo
auto data_h = create_host_space_copy(view);
auto rit = KE::remove_if("label", exespace(), KE::begin(view),
KE::end(view), remove_if_even);
verify_data(data_h, view, rit, remove_if_even);
}
{
auto view = create_view<ValueType>(Tag{}, view_ext, "remove_if_view");
fill_view(view, name);
// make host copy BEFORE running algo
auto data_h = create_host_space_copy(view);
auto rit = KE::remove_if(exespace(), view, remove_if_even);
verify_data(data_h, view, rit, remove_if_even);
}
{
auto view = create_view<ValueType>(Tag{}, view_ext, "remove_if_view");
fill_view(view, name);
// make host copy BEFORE running algo
auto data_h = create_host_space_copy(view);
auto rit = KE::remove_if("label", exespace(), view, remove_if_even);
verify_data(data_h, view, rit, remove_if_even);
}
Kokkos::fence();
}
template <class Tag, class ValueType>
void run_all_scenarios() {
const std::map<std::string, std::size_t> scenarios = {
{"empty", 0}, {"one-element-a", 1}, {"one-element-b", 1},
{"two-elements-a", 2}, {"two-elements-b", 2}, {"small-a", 9},
{"small-b", 13}, {"medium", 23103}, {"large", 101513}};
for (const auto& it : scenarios) {
run_single_scenario<Tag, ValueType>(it);
}
}
TEST(std_algorithms_mod_seq_ops, remove_if) {
run_all_scenarios<DynamicTag, int>();
run_all_scenarios<StridedThreeTag, int>();
}
} // namespace RemoveIf
} // namespace stdalgos
} // namespace Test

View File

@ -0,0 +1,255 @@
/*
//@HEADER
// ************************************************************************
//
// Kokkos v. 3.0
// Copyright (2020) 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.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the Corporation nor the names of the
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Questions? Contact Christian R. Trott (crtrott@sandia.gov)
//
// ************************************************************************
//@HEADER
*/
#include <TestStdAlgorithmsCommon.hpp>
#include <std_algorithms/Kokkos_BeginEnd.hpp>
#include <std_algorithms/Kokkos_ModifyingSequenceOperations.hpp>
#include <utility>
namespace Test {
namespace stdalgos {
namespace Replace {
namespace KE = Kokkos::Experimental;
template <class ViewType>
void fill_view(ViewType dest_view, const std::string& name) {
using value_type = typename ViewType::value_type;
using exe_space = typename ViewType::execution_space;
const std::size_t ext = dest_view.extent(0);
using aux_view_t = Kokkos::View<value_type*, exe_space>;
aux_view_t aux_view("aux_view", ext);
auto v_h = create_mirror_view(Kokkos::HostSpace(), aux_view);
if (name == "empty") {
// no op
}
else if (name == "one-element-a") {
v_h(0) = static_cast<value_type>(1);
}
else if (name == "one-element-b") {
v_h(0) = static_cast<value_type>(2);
}
else if (name == "two-elements-a") {
v_h(0) = static_cast<value_type>(1);
v_h(1) = static_cast<value_type>(2);
}
else if (name == "two-elements-b") {
v_h(0) = static_cast<value_type>(2);
v_h(1) = static_cast<value_type>(-1);
}
else if (name == "small-a") {
for (std::size_t i = 0; i < ext; ++i) {
v_h(i) = value_type{-5} + static_cast<value_type>(i + 1);
}
v_h(0) = static_cast<value_type>(2);
v_h(3) = static_cast<value_type>(2);
v_h(5) = static_cast<value_type>(2);
}
else if (name == "small-b") {
for (std::size_t i = 0; i < ext; ++i) {
if (i < 4) {
v_h(i) = static_cast<value_type>(-1);
} else {
v_h(i) = static_cast<value_type>(2);
}
}
}
else if (name == "medium" || name == "large") {
for (std::size_t i = 0; i < ext; ++i) {
if (i % 2 == 0) {
v_h(i) = static_cast<value_type>(-1);
} else {
v_h(i) = static_cast<value_type>(2);
}
}
}
else {
throw std::runtime_error("invalid choice");
}
Kokkos::deep_copy(aux_view, v_h);
CopyFunctor<aux_view_t, ViewType> F1(aux_view, dest_view);
Kokkos::parallel_for("copy", dest_view.extent(0), F1);
}
template <class ViewType1, class ValueType>
void verify_data(const std::string& name, ViewType1 test_view,
ValueType new_value) {
//! always careful because views might not be deep copyable
auto view_dc = create_deep_copyable_compatible_clone(test_view);
auto view_h = create_mirror_view_and_copy(Kokkos::HostSpace(), view_dc);
if (name == "empty") {
// no op
}
else if (name == "one-element-a") {
EXPECT_TRUE(view_h(0) == ValueType{1});
}
else if (name == "one-element-b") {
EXPECT_TRUE(view_h(0) == new_value);
}
else if (name == "two-elements-a") {
EXPECT_TRUE(view_h(0) == ValueType{1});
EXPECT_TRUE(view_h(1) == new_value);
}
else if (name == "two-elements-b") {
EXPECT_TRUE(view_h(0) == new_value);
EXPECT_TRUE(view_h(1) == ValueType{-1});
}
else if (name == "small-a") {
for (std::size_t i = 0; i < view_h.extent(0); ++i) {
if (i == 0 || i == 3 || i == 5 || i == 6) {
EXPECT_TRUE(view_h(i) == new_value);
} else {
const auto gold = ValueType{-5} + static_cast<ValueType>(i + 1);
EXPECT_TRUE(view_h(i) == gold);
}
}
}
else if (name == "small-b") {
for (std::size_t i = 0; i < view_h.extent(0); ++i) {
if (i < 4) {
EXPECT_TRUE(view_h(i) == ValueType{-1});
} else {
EXPECT_TRUE(view_h(i) == new_value);
}
}
}
else if (name == "medium" || name == "large") {
for (std::size_t i = 0; i < view_h.extent(0); ++i) {
if (i % 2 == 0) {
EXPECT_TRUE(view_h(i) == ValueType{-1});
} else {
EXPECT_TRUE(view_h(i) == new_value);
}
}
}
else {
throw std::runtime_error("invalid choice");
}
}
std::string value_type_to_string(int) { return "int"; }
std::string value_type_to_string(double) { return "double"; }
template <class Tag, class ValueType, class InfoType>
void run_single_scenario(const InfoType& scenario_info) {
const auto name = std::get<0>(scenario_info);
const std::size_t view_ext = std::get<1>(scenario_info);
// std::cout << "replace: " << name << ", " << view_tag_to_string(Tag{}) << ",
// "
// << value_type_to_string(ValueType()) << std::endl;
ValueType old_value{2};
ValueType new_value{43};
auto view = create_view<ValueType>(Tag{}, view_ext, "replace");
{
fill_view(view, name);
KE::replace(exespace(), KE::begin(view), KE::end(view), old_value,
new_value);
verify_data(name, view, new_value);
}
{
fill_view(view, name);
KE::replace("label", exespace(), KE::begin(view), KE::end(view), old_value,
new_value);
verify_data(name, view, new_value);
}
{
fill_view(view, name);
KE::replace(exespace(), view, old_value, new_value);
verify_data(name, view, new_value);
}
{
fill_view(view, name);
KE::replace("label", exespace(), view, old_value, new_value);
verify_data(name, view, new_value);
}
Kokkos::fence();
}
template <class Tag, class ValueType>
void run_all_scenarios() {
const std::map<std::string, std::size_t> scenarios = {
{"empty", 0}, {"one-element-a", 1}, {"one-element-b", 1},
{"two-elements-a", 2}, {"two-elements-b", 2}, {"small-a", 9},
{"small-b", 13}, {"medium", 1103}, {"large", 101513}};
for (const auto& it : scenarios) {
run_single_scenario<Tag, ValueType>(it);
}
}
TEST(std_algorithms_replace_ops_test, replace) {
run_all_scenarios<DynamicTag, double>();
run_all_scenarios<StridedThreeTag, double>();
run_all_scenarios<DynamicTag, int>();
run_all_scenarios<StridedThreeTag, int>();
}
} // namespace Replace
} // namespace stdalgos
} // namespace Test

View File

@ -0,0 +1,299 @@
/*
//@HEADER
// ************************************************************************
//
// Kokkos v. 3.0
// Copyright (2020) 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.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the Corporation nor the names of the
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Questions? Contact Christian R. Trott (crtrott@sandia.gov)
//
// ************************************************************************
//@HEADER
*/
#include <TestStdAlgorithmsCommon.hpp>
#include <std_algorithms/Kokkos_BeginEnd.hpp>
#include <std_algorithms/Kokkos_ModifyingSequenceOperations.hpp>
#include <utility>
namespace Test {
namespace stdalgos {
namespace ReplaceCopy {
namespace KE = Kokkos::Experimental;
template <class ViewType>
void fill_view(ViewType dest_view, const std::string& name) {
using value_type = typename ViewType::value_type;
using exe_space = typename ViewType::execution_space;
const std::size_t ext = dest_view.extent(0);
using aux_view_t = Kokkos::View<value_type*, exe_space>;
aux_view_t aux_view("aux_view", ext);
auto v_h = create_mirror_view(Kokkos::HostSpace(), aux_view);
if (name == "empty") {
// no op
}
else if (name == "one-element-a") {
v_h(0) = static_cast<value_type>(1);
}
else if (name == "one-element-b") {
v_h(0) = static_cast<value_type>(2);
}
else if (name == "two-elements-a") {
v_h(0) = static_cast<value_type>(1);
v_h(1) = static_cast<value_type>(2);
}
else if (name == "two-elements-b") {
v_h(0) = static_cast<value_type>(2);
v_h(1) = static_cast<value_type>(-1);
}
else if (name == "small-a") {
for (std::size_t i = 0; i < ext; ++i) {
v_h(i) = value_type{-5} + static_cast<value_type>(i + 1);
}
v_h(0) = static_cast<value_type>(2);
v_h(3) = static_cast<value_type>(2);
v_h(5) = static_cast<value_type>(2);
}
else if (name == "small-b") {
for (std::size_t i = 0; i < ext; ++i) {
if (i < 4) {
v_h(i) = static_cast<value_type>(-1);
} else {
v_h(i) = static_cast<value_type>(2);
}
}
}
else if (name == "medium" || name == "large") {
for (std::size_t i = 0; i < ext; ++i) {
if (i % 2 == 0) {
v_h(i) = static_cast<value_type>(-1);
} else {
v_h(i) = static_cast<value_type>(2);
}
}
}
else {
throw std::runtime_error("invalid choice");
}
Kokkos::deep_copy(aux_view, v_h);
CopyFunctor<aux_view_t, ViewType> F1(aux_view, dest_view);
Kokkos::parallel_for("copy", dest_view.extent(0), F1);
}
template <class ViewTypeFrom, class ViewTypeTest, class ValueType>
void verify_data(const std::string& name, ViewTypeFrom view_from,
ViewTypeTest view_test, ValueType new_value) {
//! always careful because views might not be deep copyable
auto view_test_dc = create_deep_copyable_compatible_clone(view_test);
auto view_test_h =
create_mirror_view_and_copy(Kokkos::HostSpace(), view_test_dc);
auto view_from_dc = create_deep_copyable_compatible_clone(view_from);
auto view_from_h =
create_mirror_view_and_copy(Kokkos::HostSpace(), view_from_dc);
// we check that view_from is unchanged from what it was after filling
// while view_test should be changed
if (name == "empty") {
// no op
}
else if (name == "one-element-a") {
EXPECT_TRUE(view_from_h(0) == ValueType{1});
EXPECT_TRUE(view_test_h(0) == view_from_h(0));
}
else if (name == "one-element-b") {
EXPECT_TRUE(view_from_h(0) == ValueType{2});
EXPECT_TRUE(view_test_h(0) == new_value);
}
else if (name == "two-elements-a") {
EXPECT_TRUE(view_from_h(0) == ValueType{1});
EXPECT_TRUE(view_from_h(1) == ValueType{2});
EXPECT_TRUE(view_test_h(0) == view_from_h(0));
EXPECT_TRUE(view_test_h(1) == new_value);
}
else if (name == "two-elements-b") {
EXPECT_TRUE(view_from_h(0) == ValueType{2});
EXPECT_TRUE(view_from_h(1) == ValueType{-1});
EXPECT_TRUE(view_test_h(0) == new_value);
EXPECT_TRUE(view_test_h(1) == view_from_h(1));
}
else if (name == "small-a") {
for (std::size_t i = 0; i < view_test_h.extent(0); ++i) {
if (i == 0 || i == 3 || i == 5 || i == 6) {
EXPECT_TRUE(view_from_h(i) == ValueType{2});
EXPECT_TRUE(view_test_h(i) == new_value);
} else {
const auto gold = ValueType{-5} + static_cast<ValueType>(i + 1);
EXPECT_TRUE(view_from_h(i) == gold);
EXPECT_TRUE(view_test_h(i) == gold);
}
}
}
else if (name == "small-b") {
for (std::size_t i = 0; i < view_test_h.extent(0); ++i) {
if (i < 4) {
EXPECT_TRUE(view_from_h(i) == ValueType{-1});
EXPECT_TRUE(view_test_h(i) == view_from_h(i));
} else {
EXPECT_TRUE(view_from_h(i) == ValueType{2});
EXPECT_TRUE(view_test_h(i) == new_value);
}
}
}
else if (name == "medium" || name == "large") {
for (std::size_t i = 0; i < view_test_h.extent(0); ++i) {
if (i % 2 == 0) {
EXPECT_TRUE(view_from_h(i) == ValueType{-1});
EXPECT_TRUE(view_test_h(i) == view_from_h(i));
} else {
EXPECT_TRUE(view_from_h(i) == ValueType{2});
EXPECT_TRUE(view_test_h(i) == new_value);
}
}
}
else {
throw std::runtime_error("invalid choice");
}
}
std::string value_type_to_string(int) { return "int"; }
std::string value_type_to_string(double) { return "double"; }
template <class Tag, class ValueType, class InfoType>
void run_single_scenario(const InfoType& scenario_info) {
const auto name = std::get<0>(scenario_info);
const std::size_t view_ext = std::get<1>(scenario_info);
// std::cout << "replace_copy: " << name << ", " << view_tag_to_string(Tag{})
// << ", " << value_type_to_string(ValueType()) << std::endl;
ValueType old_value{2};
ValueType new_value{43};
{
auto view_from =
create_view<ValueType>(Tag{}, view_ext, "replace_copy_from");
auto view_dest =
create_view<ValueType>(Tag{}, view_ext, "replace_copy_dest");
fill_view(view_from, name);
auto rit =
KE::replace_copy(exespace(), KE::cbegin(view_from), KE::cend(view_from),
KE::begin(view_dest), old_value, new_value);
verify_data(name, view_from, view_dest, new_value);
EXPECT_TRUE(rit == (KE::begin(view_dest) + view_ext));
}
{
auto view_from =
create_view<ValueType>(Tag{}, view_ext, "replace_copy_from");
auto view_dest =
create_view<ValueType>(Tag{}, view_ext, "replace_copy_dest");
fill_view(view_from, name);
auto rit = KE::replace_copy("label", exespace(), KE::cbegin(view_from),
KE::cend(view_from), KE::begin(view_dest),
old_value, new_value);
verify_data(name, view_from, view_dest, new_value);
EXPECT_TRUE(rit == (KE::begin(view_dest) + view_ext));
}
{
auto view_from =
create_view<ValueType>(Tag{}, view_ext, "replace_copy_from");
auto view_dest =
create_view<ValueType>(Tag{}, view_ext, "replace_copy_dest");
fill_view(view_from, name);
auto rit = KE::replace_copy(exespace(), view_from, view_dest, old_value,
new_value);
verify_data(name, view_from, view_dest, new_value);
EXPECT_TRUE(rit == (KE::begin(view_dest) + view_ext));
}
{
auto view_from =
create_view<ValueType>(Tag{}, view_ext, "replace_copy_from");
auto view_dest =
create_view<ValueType>(Tag{}, view_ext, "replace_copy_dest");
fill_view(view_from, name);
auto rit = KE::replace_copy("label", exespace(), view_from, view_dest,
old_value, new_value);
verify_data(name, view_from, view_dest, new_value);
EXPECT_TRUE(rit == (KE::begin(view_dest) + view_ext));
}
Kokkos::fence();
}
template <class Tag, class ValueType>
void run_all_scenarios() {
const std::map<std::string, std::size_t> scenarios = {
{"empty", 0}, {"one-element-a", 1}, {"one-element-b", 1},
{"two-elements-a", 2}, {"two-elements-b", 2}, {"small-a", 9},
{"small-b", 13}, {"medium", 1103}, {"large", 101513}};
for (const auto& it : scenarios) {
run_single_scenario<Tag, ValueType>(it);
}
}
TEST(std_algorithms_replace_ops_test, replace_copy) {
run_all_scenarios<DynamicTag, int>();
run_all_scenarios<StridedThreeTag, int>();
run_all_scenarios<DynamicTag, double>();
run_all_scenarios<StridedThreeTag, double>();
}
} // namespace ReplaceCopy
} // namespace stdalgos
} // namespace Test

View File

@ -0,0 +1,300 @@
/*
//@HEADER
// ************************************************************************
//
// Kokkos v. 3.0
// Copyright (2020) 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.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the Corporation nor the names of the
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Questions? Contact Christian R. Trott (crtrott@sandia.gov)
//
// ************************************************************************
//@HEADER
*/
#include <TestStdAlgorithmsCommon.hpp>
#include <std_algorithms/Kokkos_BeginEnd.hpp>
#include <std_algorithms/Kokkos_ModifyingSequenceOperations.hpp>
#include <utility>
namespace Test {
namespace stdalgos {
namespace ReplaceCopyIf {
namespace KE = Kokkos::Experimental;
template <class ViewType>
void fill_view(ViewType dest_view, const std::string& name) {
using value_type = typename ViewType::value_type;
using exe_space = typename ViewType::execution_space;
const std::size_t ext = dest_view.extent(0);
using aux_view_t = Kokkos::View<value_type*, exe_space>;
aux_view_t aux_view("aux_view", ext);
auto v_h = create_mirror_view(Kokkos::HostSpace(), aux_view);
if (name == "empty") {
// no op
}
else if (name == "one-element-a") {
v_h(0) = static_cast<value_type>(1);
}
else if (name == "one-element-b") {
v_h(0) = static_cast<value_type>(2);
}
else if (name == "two-elements-a") {
v_h(0) = static_cast<value_type>(1);
v_h(1) = static_cast<value_type>(2);
}
else if (name == "two-elements-b") {
v_h(0) = static_cast<value_type>(2);
v_h(1) = static_cast<value_type>(-1);
}
else if (name == "small-a") {
for (std::size_t i = 0; i < ext; ++i) {
v_h(i) = value_type{-5} + static_cast<value_type>(i + 1);
}
v_h(0) = static_cast<value_type>(2);
v_h(3) = static_cast<value_type>(2);
v_h(5) = static_cast<value_type>(2);
}
else if (name == "small-b") {
for (std::size_t i = 0; i < ext; ++i) {
if (i < 4) {
v_h(i) = static_cast<value_type>(-1);
} else {
v_h(i) = static_cast<value_type>(2);
}
}
}
else if (name == "medium" || name == "large") {
for (std::size_t i = 0; i < ext; ++i) {
if (i % 2 == 0) {
v_h(i) = static_cast<value_type>(-1);
} else {
v_h(i) = static_cast<value_type>(2);
}
}
}
else {
throw std::runtime_error("invalid choice");
}
Kokkos::deep_copy(aux_view, v_h);
CopyFunctor<aux_view_t, ViewType> F1(aux_view, dest_view);
Kokkos::parallel_for("copy", dest_view.extent(0), F1);
}
template <class ViewTypeFrom, class ViewTypeTest, class ValueType>
void verify_data(const std::string& name, ViewTypeFrom view_from,
ViewTypeTest view_test, ValueType new_value) {
//! always careful because views might not be deep copyable
auto view_test_dc = create_deep_copyable_compatible_clone(view_test);
auto view_test_h =
create_mirror_view_and_copy(Kokkos::HostSpace(), view_test_dc);
auto view_from_dc = create_deep_copyable_compatible_clone(view_from);
auto view_from_h =
create_mirror_view_and_copy(Kokkos::HostSpace(), view_from_dc);
// we check that view_from is unchanged from what it was after filling
// while view_test should be changed
if (name == "empty") {
// no op
}
else if (name == "one-element-a") {
EXPECT_TRUE(view_from_h(0) == ValueType{1});
EXPECT_TRUE(view_test_h(0) == view_from_h(0));
}
else if (name == "one-element-b") {
EXPECT_TRUE(view_from_h(0) == ValueType{2});
EXPECT_TRUE(view_test_h(0) == new_value);
}
else if (name == "two-elements-a") {
EXPECT_TRUE(view_from_h(0) == ValueType{1});
EXPECT_TRUE(view_from_h(1) == ValueType{2});
EXPECT_TRUE(view_test_h(0) == view_from_h(0));
EXPECT_TRUE(view_test_h(1) == new_value);
}
else if (name == "two-elements-b") {
EXPECT_TRUE(view_from_h(0) == ValueType{2});
EXPECT_TRUE(view_from_h(1) == ValueType{-1});
EXPECT_TRUE(view_test_h(0) == new_value);
EXPECT_TRUE(view_test_h(1) == view_from_h(1));
}
else if (name == "small-a") {
for (std::size_t i = 0; i < view_test_h.extent(0); ++i) {
if (i == 0 || i == 3 || i == 5 || i == 6) {
EXPECT_TRUE(view_from_h(i) == ValueType{2});
EXPECT_TRUE(view_test_h(i) == new_value);
} else {
const auto gold = ValueType{-5} + static_cast<ValueType>(i + 1);
EXPECT_TRUE(view_from_h(i) == gold);
EXPECT_TRUE(view_test_h(i) == gold);
}
}
}
else if (name == "small-b") {
for (std::size_t i = 0; i < view_test_h.extent(0); ++i) {
if (i < 4) {
EXPECT_TRUE(view_from_h(i) == ValueType{-1});
EXPECT_TRUE(view_test_h(i) == view_from_h(i));
} else {
EXPECT_TRUE(view_from_h(i) == ValueType{2});
EXPECT_TRUE(view_test_h(i) == new_value);
}
}
}
else if (name == "medium" || name == "large") {
for (std::size_t i = 0; i < view_test_h.extent(0); ++i) {
if (i % 2 == 0) {
EXPECT_TRUE(view_from_h(i) == ValueType{-1});
EXPECT_TRUE(view_test_h(i) == view_from_h(i));
} else {
EXPECT_TRUE(view_from_h(i) == ValueType{2});
EXPECT_TRUE(view_test_h(i) == new_value);
}
}
}
else {
throw std::runtime_error("invalid choice");
}
}
std::string value_type_to_string(int) { return "int"; }
std::string value_type_to_string(double) { return "double"; }
template <class ValueType>
struct EqualsTwoFunctor {
KOKKOS_INLINE_FUNCTION
bool operator()(const ValueType val) const { return (val == ValueType(2)); }
};
template <class Tag, class ValueType, class InfoType>
void run_single_scenario(const InfoType& scenario_info) {
const auto name = std::get<0>(scenario_info);
const std::size_t view_ext = std::get<1>(scenario_info);
// std::cout << "replace_copy_if: " << name << ", " <<
// view_tag_to_string(Tag{})
// << ", " << value_type_to_string(ValueType()) << std::endl;
ValueType new_value{43};
auto view_from =
create_view<ValueType>(Tag{}, view_ext, "replace_copy_if_from");
using pred_type = EqualsTwoFunctor<ValueType>;
{
fill_view(view_from, name);
auto view_dest =
create_view<ValueType>(Tag{}, view_ext, "replace_copy_if_dest");
auto rit = KE::replace_copy_if(exespace(), KE::cbegin(view_from),
KE::cend(view_from), KE::begin(view_dest),
pred_type(), new_value);
verify_data(name, view_from, view_dest, new_value);
EXPECT_TRUE(rit == (KE::begin(view_dest) + view_ext));
}
{
fill_view(view_from, name);
auto view_dest =
create_view<ValueType>(Tag{}, view_ext, "replace_copy_if_dest");
auto rit = KE::replace_copy_if("label", exespace(), KE::cbegin(view_from),
KE::cend(view_from), KE::begin(view_dest),
pred_type(), new_value);
verify_data(name, view_from, view_dest, new_value);
EXPECT_TRUE(rit == (KE::begin(view_dest) + view_ext));
}
{
fill_view(view_from, name);
auto view_dest =
create_view<ValueType>(Tag{}, view_ext, "replace_copy_if_dest");
auto rit = KE::replace_copy_if(exespace(), view_from, view_dest,
pred_type(), new_value);
verify_data(name, view_from, view_dest, new_value);
EXPECT_TRUE(rit == (KE::begin(view_dest) + view_ext));
}
{
fill_view(view_from, name);
auto view_dest =
create_view<ValueType>(Tag{}, view_ext, "replace_copy_if_dest");
auto rit = KE::replace_copy_if("label", exespace(), view_from, view_dest,
pred_type(), new_value);
verify_data(name, view_from, view_dest, new_value);
EXPECT_TRUE(rit == (KE::begin(view_dest) + view_ext));
}
Kokkos::fence();
}
template <class Tag, class ValueType>
void run_all_scenarios() {
const std::map<std::string, std::size_t> scenarios = {
{"empty", 0}, {"one-element-a", 1}, {"one-element-b", 1},
{"two-elements-a", 2}, {"two-elements-b", 2}, {"small-a", 9},
{"small-b", 13}, {"medium", 1103}, {"large", 101513}};
for (const auto& it : scenarios) {
run_single_scenario<Tag, ValueType>(it);
}
}
TEST(std_algorithms_replace_ops_test, replace_copy_if) {
run_all_scenarios<DynamicTag, int>();
run_all_scenarios<StridedThreeTag, int>();
run_all_scenarios<DynamicTag, double>();
run_all_scenarios<StridedThreeTag, double>();
}
} // namespace ReplaceCopyIf
} // namespace stdalgos
} // namespace Test

View File

@ -0,0 +1,257 @@
/*
//@HEADER
// ************************************************************************
//
// Kokkos v. 3.0
// Copyright (2020) 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.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the Corporation nor the names of the
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Questions? Contact Christian R. Trott (crtrott@sandia.gov)
//
// ************************************************************************
//@HEADER
*/
#include <TestStdAlgorithmsCommon.hpp>
#include <std_algorithms/Kokkos_BeginEnd.hpp>
#include <std_algorithms/Kokkos_ModifyingSequenceOperations.hpp>
#include <utility>
namespace Test {
namespace stdalgos {
namespace ReplaceIf {
namespace KE = Kokkos::Experimental;
template <class ValueType>
struct UnifDist;
template <>
struct UnifDist<double> {
using dist_type = std::uniform_real_distribution<double>;
std::mt19937 m_gen;
dist_type m_dist;
UnifDist() : m_dist(-20., 20.) { m_gen.seed(1034343); }
double operator()() { return m_dist(m_gen); }
};
template <>
struct UnifDist<int> {
using dist_type = std::uniform_int_distribution<int>;
std::mt19937 m_gen;
dist_type m_dist;
UnifDist() : m_dist(-100, 100) { m_gen.seed(1034343); }
int operator()() { return m_dist(m_gen); }
};
template <class ViewType>
void fill_view(ViewType dest_view, const std::string& name) {
using value_type = typename ViewType::value_type;
using exe_space = typename ViewType::execution_space;
const std::size_t ext = dest_view.extent(0);
using aux_view_t = Kokkos::View<value_type*, exe_space>;
aux_view_t aux_view("aux_view", ext);
auto v_h = create_mirror_view(Kokkos::HostSpace(), aux_view);
UnifDist<value_type> randObj;
if (name == "empty") {
// no op
}
else if (name == "one-element") {
v_h(0) = static_cast<value_type>(1);
}
else if (name == "two-elements-a") {
v_h(0) = static_cast<value_type>(1);
v_h(1) = static_cast<value_type>(2);
}
else if (name == "two-elements-b") {
v_h(0) = static_cast<value_type>(2);
v_h(1) = static_cast<value_type>(-1);
}
else if (name == "small-a") {
for (std::size_t i = 0; i < ext; ++i) {
v_h(i) = value_type{-5} + static_cast<value_type>(i + 1);
}
}
else if (name == "small-b") {
for (std::size_t i = 0; i < ext; ++i) {
v_h(i) = randObj();
}
v_h(5) = static_cast<value_type>(-2);
}
else if (name == "medium" || name == "large") {
for (std::size_t i = 0; i < ext; ++i) {
v_h(i) = randObj();
}
}
else {
throw std::runtime_error("invalid choice");
}
Kokkos::deep_copy(aux_view, v_h);
CopyFunctor<aux_view_t, ViewType> F1(aux_view, dest_view);
Kokkos::parallel_for("copy", dest_view.extent(0), F1);
}
// my own because std::replace_if is ONLY found with std=c++20
template <class ForwardIt, class UnaryPredicate, class T>
void my_host_replace_if(ForwardIt first, ForwardIt last, UnaryPredicate p,
const T& new_value) {
for (; first != last; ++first) {
if (p(*first)) {
*first = new_value;
}
}
}
template <class ViewType1, class ViewType2, class ValueType,
class PredicateType>
void verify_data(ViewType1 data_view, // contains data
ViewType2 test_view, // the view to test
ValueType new_value, PredicateType pred) {
//! always careful because views might not be deep copyable
auto data_view_dc = create_deep_copyable_compatible_clone(data_view);
auto data_view_h =
create_mirror_view_and_copy(Kokkos::HostSpace(), data_view_dc);
my_host_replace_if(KE::begin(data_view_h), KE::end(data_view_h), pred,
new_value);
auto test_view_dc = create_deep_copyable_compatible_clone(test_view);
auto test_view_h =
create_mirror_view_and_copy(Kokkos::HostSpace(), test_view_dc);
if (test_view_h.extent(0) > 0) {
for (std::size_t i = 0; i < test_view_h.extent(0); ++i) {
// std::cout << i << " " << std::setprecision(15)
// << data_view_dc(i) << " "
// << data_view_h(i) << " "
// << test_view_h(i) << std::endl;
EXPECT_TRUE(data_view_h(i) == test_view_h(i));
}
}
}
std::string value_type_to_string(int) { return "int"; }
std::string value_type_to_string(double) { return "double"; }
template <class Tag, class ValueType, class InfoType, class PredicateType>
void run_single_scenario(const InfoType& scenario_info, PredicateType pred) {
const auto name = std::get<0>(scenario_info);
const std::size_t view_ext = std::get<1>(scenario_info);
// std::cout << "replace_if: " << name << ", " << view_tag_to_string(Tag{})
// << ", " << value_type_to_string(ValueType()) << std::endl;
ValueType new_value{23};
auto view_with_data =
create_view<ValueType>(Tag{}, view_ext, "replace_if_v2");
auto view_to_test = create_view<ValueType>(Tag{}, view_ext, "replace_if_v1");
fill_view(view_with_data, name);
{
CopyFunctor<decltype(view_with_data), decltype(view_to_test)> F1(
view_with_data, view_to_test);
Kokkos::parallel_for("copy", view_to_test.extent(0), F1);
KE::replace_if(exespace(), KE::begin(view_to_test), KE::end(view_to_test),
pred, new_value);
verify_data(view_with_data, view_to_test, new_value, pred);
}
{
CopyFunctor<decltype(view_with_data), decltype(view_to_test)> F1(
view_with_data, view_to_test);
Kokkos::parallel_for("copy", view_to_test.extent(0), F1);
KE::replace_if("label", exespace(), KE::begin(view_to_test),
KE::end(view_to_test), pred, new_value);
verify_data(view_with_data, view_to_test, new_value, pred);
}
{
CopyFunctor<decltype(view_with_data), decltype(view_to_test)> F1(
view_with_data, view_to_test);
Kokkos::parallel_for("copy", view_to_test.extent(0), F1);
KE::replace_if(exespace(), view_to_test, pred, new_value);
verify_data(view_with_data, view_to_test, new_value, pred);
}
{
CopyFunctor<decltype(view_with_data), decltype(view_to_test)> F1(
view_with_data, view_to_test);
Kokkos::parallel_for("copy", view_to_test.extent(0), F1);
KE::replace_if("label", exespace(), view_to_test, pred, new_value);
verify_data(view_with_data, view_to_test, new_value, pred);
}
Kokkos::fence();
}
template <class Tag, class ValueType>
void run_all_scenarios() {
const std::map<std::string, std::size_t> scenarios = {
{"empty", 0}, {"one-element", 1}, {"two-elements-a", 2},
{"two-elements-b", 2}, {"small-a", 9}, {"small-b", 13},
{"medium", 1103}, {"large", 101513}};
for (const auto& it : scenarios) {
using pred_p_t = IsPositiveFunctor<ValueType>;
run_single_scenario<Tag, ValueType>(it, pred_p_t{});
using pred_n_t = IsNegativeFunctor<ValueType>;
run_single_scenario<Tag, ValueType>(it, pred_n_t{});
}
}
TEST(std_algorithms_replace_ops_test, replace_if) {
run_all_scenarios<DynamicTag, double>();
run_all_scenarios<StridedThreeTag, double>();
run_all_scenarios<DynamicTag, int>();
run_all_scenarios<StridedThreeTag, int>();
}
} // namespace ReplaceIf
} // namespace stdalgos
} // namespace Test

View File

@ -0,0 +1,180 @@
/*
//@HEADER
// ************************************************************************
//
// Kokkos v. 3.0
// Copyright (2020) 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.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the Corporation nor the names of the
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Questions? Contact Christian R. Trott (crtrott@sandia.gov)
//
// ************************************************************************
//@HEADER
*/
#include <TestStdAlgorithmsCommon.hpp>
#include <std_algorithms/Kokkos_BeginEnd.hpp>
#include <std_algorithms/Kokkos_ModifyingSequenceOperations.hpp>
#include <utility>
namespace Test {
namespace stdalgos {
namespace Reverse {
namespace KE = Kokkos::Experimental;
template <class ViewType>
void fill_view(ViewType dest_view, const std::string& name) {
using value_type = typename ViewType::value_type;
using exe_space = typename ViewType::execution_space;
const std::size_t ext = dest_view.extent(0);
using aux_view_t = Kokkos::View<value_type*, exe_space>;
aux_view_t aux_view("aux_view", ext);
auto v_h = create_mirror_view(Kokkos::HostSpace(), aux_view);
if (name == "empty") {
// no op
}
else if (name == "one-element-a") {
v_h(0) = static_cast<value_type>(1);
}
else if (name == "one-element-b") {
v_h(0) = static_cast<value_type>(2);
}
else if (name == "two-elements-a") {
v_h(0) = static_cast<value_type>(1);
v_h(1) = static_cast<value_type>(2);
}
else if (name == "two-elements-b") {
v_h(0) = static_cast<value_type>(2);
v_h(1) = static_cast<value_type>(-1);
}
else if (name == "small-a" || name == "small-b" || name == "medium" ||
name == "large") {
for (std::size_t i = 0; i < ext; ++i) {
v_h(i) = static_cast<value_type>(-11) + static_cast<value_type>(i);
}
}
else {
throw std::runtime_error("invalid choice");
}
Kokkos::deep_copy(aux_view, v_h);
CopyFunctor<aux_view_t, ViewType> F1(aux_view, dest_view);
Kokkos::parallel_for("copy", dest_view.extent(0), F1);
}
template <class ViewType1, class ViewType2>
void verify_data(ViewType1 test_view, ViewType2 orig_view) {
auto tv_h = create_host_space_copy(test_view);
auto ov_h = create_host_space_copy(orig_view);
const std::size_t ext = test_view.extent(0);
for (std::size_t i = 0; i < ext; ++i) {
EXPECT_TRUE(tv_h(i) == ov_h(ext - i - 1));
}
}
std::string value_type_to_string(int) { return "int"; }
std::string value_type_to_string(double) { return "double"; }
template <class Tag, class ValueType, class InfoType>
void run_single_scenario(const InfoType& scenario_info) {
const auto name = std::get<0>(scenario_info);
const std::size_t view_ext = std::get<1>(scenario_info);
// std::cout << "reverse: " << name << ", " << view_tag_to_string(Tag{}) << ",
// "
// << value_type_to_string(ValueType()) << std::endl;
auto test_view = create_view<ValueType>(Tag{}, view_ext, "reverse");
auto orig_view = create_view<ValueType>(Tag{}, view_ext, "reverse");
{
fill_view(test_view, name);
fill_view(orig_view, name);
KE::reverse(exespace(), KE::begin(test_view), KE::end(test_view));
verify_data(test_view, orig_view);
}
{
fill_view(test_view, name);
fill_view(orig_view, name);
KE::reverse("label", exespace(), KE::begin(test_view), KE::end(test_view));
verify_data(test_view, orig_view);
}
{
fill_view(test_view, name);
fill_view(orig_view, name);
KE::reverse(exespace(), test_view);
verify_data(test_view, orig_view);
}
{
fill_view(test_view, name);
fill_view(orig_view, name);
KE::reverse("label", exespace(), test_view);
verify_data(test_view, orig_view);
}
Kokkos::fence();
}
template <class Tag, class ValueType>
void run_all_scenarios() {
const std::map<std::string, std::size_t> scenarios = {
{"empty", 0}, {"one-element-a", 1}, {"one-element-b", 1},
{"two-elements-a", 2}, {"two-elements-b", 2}, {"small-a", 9},
{"small-b", 13}, {"medium", 1103}, {"large", 101513}};
for (const auto& it : scenarios) {
run_single_scenario<Tag, ValueType>(it);
}
}
TEST(std_algorithms_modseq_test, reverse) {
run_all_scenarios<DynamicTag, double>();
run_all_scenarios<StridedThreeTag, double>();
run_all_scenarios<DynamicTag, int>();
run_all_scenarios<StridedThreeTag, int>();
}
} // namespace Reverse
} // namespace stdalgos
} // namespace Test

View File

@ -0,0 +1,275 @@
/*
//@HEADER
// ************************************************************************
//
// Kokkos v. 3.0
// Copyright (2020) 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.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the Corporation nor the names of the
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Questions? Contact Christian R. Trott (crtrott@sandia.gov)
//
// ************************************************************************
//@HEADER
*/
#include <TestStdAlgorithmsCommon.hpp>
#include <std_algorithms/Kokkos_BeginEnd.hpp>
#include <std_algorithms/Kokkos_ModifyingSequenceOperations.hpp>
#include <utility>
#include <algorithm>
namespace Test {
namespace stdalgos {
namespace Rotate {
namespace KE = Kokkos::Experimental;
template <class ValueType>
struct UnifDist;
template <>
struct UnifDist<int> {
using dist_type = std::uniform_int_distribution<int>;
std::mt19937 m_gen;
dist_type m_dist;
UnifDist() : m_dist(-50, 50) { m_gen.seed(1034343); }
int operator()() { return m_dist(m_gen); }
};
template <>
struct UnifDist<double> {
using dist_type = std::uniform_real_distribution<double>;
std::mt19937 m_gen;
dist_type m_dist;
UnifDist() : m_dist(-90., 100.) { m_gen.seed(1034343); }
double operator()() { return m_dist(m_gen); }
};
template <class ViewType>
void fill_view(ViewType dest_view, const std::string& name) {
using value_type = typename ViewType::value_type;
using exe_space = typename ViewType::execution_space;
const std::size_t ext = dest_view.extent(0);
using aux_view_t = Kokkos::View<value_type*, exe_space>;
aux_view_t aux_view("aux_view", ext);
auto v_h = create_mirror_view(Kokkos::HostSpace(), aux_view);
if (name == "empty") {
// no op
}
else if (name == "one-element-a") {
v_h(0) = static_cast<value_type>(1);
}
else if (name == "one-element-b") {
v_h(0) = static_cast<value_type>(2);
}
else if (name == "two-elements-a") {
v_h(0) = static_cast<value_type>(1);
v_h(1) = static_cast<value_type>(2);
}
else if (name == "two-elements-b") {
v_h(0) = static_cast<value_type>(2);
v_h(1) = static_cast<value_type>(-1);
}
else if (name == "small-a") {
v_h(0) = static_cast<value_type>(0);
v_h(1) = static_cast<value_type>(1);
v_h(2) = static_cast<value_type>(1);
v_h(3) = static_cast<value_type>(-2);
v_h(4) = static_cast<value_type>(3);
v_h(5) = static_cast<value_type>(4);
v_h(6) = static_cast<value_type>(-40);
v_h(7) = static_cast<value_type>(4);
v_h(8) = static_cast<value_type>(5);
v_h(9) = static_cast<value_type>(62);
v_h(10) = static_cast<value_type>(6);
}
else if (name == "small-b") {
v_h(0) = static_cast<value_type>(1);
v_h(1) = static_cast<value_type>(1);
v_h(2) = static_cast<value_type>(-1);
v_h(3) = static_cast<value_type>(2);
v_h(4) = static_cast<value_type>(-3);
v_h(5) = static_cast<value_type>(4);
v_h(6) = static_cast<value_type>(4);
v_h(7) = static_cast<value_type>(24);
v_h(8) = static_cast<value_type>(5);
v_h(9) = static_cast<value_type>(-46);
v_h(10) = static_cast<value_type>(8);
v_h(11) = static_cast<value_type>(9);
v_h(12) = static_cast<value_type>(8);
}
else if (name == "medium" || name == "large") {
UnifDist<value_type> randObj;
for (std::size_t i = 0; i < ext; ++i) {
v_h(i) = randObj();
}
}
else {
throw std::runtime_error("invalid choice");
}
Kokkos::deep_copy(aux_view, v_h);
CopyFunctor<aux_view_t, ViewType> F1(aux_view, dest_view);
Kokkos::parallel_for("copy", dest_view.extent(0), F1);
}
template <class ViewType, class ResultIt, class ViewHostType>
void verify_data(ResultIt result_it, ViewType view, ViewHostType data_view_host,
std::size_t rotation_point) {
// run std::rotate
auto n_it = KE::begin(data_view_host) + rotation_point;
auto std_rit =
std::rotate(KE::begin(data_view_host), n_it, KE::end(data_view_host));
// make sure results match
const auto my_diff = result_it - KE::begin(view);
const auto std_diff = std_rit - KE::begin(data_view_host);
EXPECT_TRUE(my_diff == std_diff);
// check views match
auto view_h = create_host_space_copy(view);
const std::size_t ext = view_h.extent(0);
for (std::size_t i = 0; i < ext; ++i) {
EXPECT_TRUE(view_h(i) == data_view_host[i]);
// std::cout << "i= " << i << " "
// << "mine: " << view_h(i) << " "
// << "std: " << data_view_host(i)
// << '\n';
}
}
std::string value_type_to_string(int) { return "int"; }
std::string value_type_to_string(double) { return "double"; }
template <class Tag, class ValueType>
void print_scenario_details(const std::string& name,
std::size_t rotation_point) {
std::cout << "rotate: "
<< " at " << rotation_point << ", " << name << ", "
<< view_tag_to_string(Tag{}) << ", "
<< value_type_to_string(ValueType()) << std::endl;
}
template <class Tag, class ValueType, class InfoType>
void run_single_scenario(const InfoType& scenario_info,
std::size_t rotation_point) {
const auto name = std::get<0>(scenario_info);
const std::size_t view_ext = std::get<1>(scenario_info);
// print_scenario_details<Tag, ValueType>(name, rotation_point);
{
auto view = create_view<ValueType>(Tag{}, view_ext, "rotate_data_view");
fill_view(view, name);
// create host copy BEFORE rotate or view will be modified
auto view_h = create_host_space_copy(view);
auto n_it = KE::begin(view) + rotation_point;
auto rit = KE::rotate(exespace(), KE::begin(view), n_it, KE::end(view));
verify_data(rit, view, view_h, rotation_point);
}
{
auto view = create_view<ValueType>(Tag{}, view_ext, "rotate_data_view");
fill_view(view, name);
// create host copy BEFORE rotate or view will be modified
auto view_h = create_host_space_copy(view);
auto n_it = KE::begin(view) + rotation_point;
auto rit =
KE::rotate("label", exespace(), KE::begin(view), n_it, KE::end(view));
verify_data(rit, view, view_h, rotation_point);
}
{
auto view = create_view<ValueType>(Tag{}, view_ext, "rotate_data_view");
fill_view(view, name);
// create host copy BEFORE rotate or view will be modified
auto view_h = create_host_space_copy(view);
auto rit = KE::rotate(exespace(), view, rotation_point);
// verify_data(rit, view, view_h, rotation_point);
}
{
auto view = create_view<ValueType>(Tag{}, view_ext, "rotate_data_view");
fill_view(view, name);
// create host copy BEFORE rotate or view will be modified
auto view_h = create_host_space_copy(view);
auto rit = KE::rotate("label", exespace(), view, rotation_point);
verify_data(rit, view, view_h, rotation_point);
}
Kokkos::fence();
}
template <class Tag, class ValueType>
void run_all_scenarios() {
const std::map<std::string, std::size_t> scenarios = {
{"empty", 0}, {"one-element-a", 1}, {"one-element-b", 1},
{"two-elements-a", 2}, {"two-elements-b", 2}, {"small-a", 11},
{"small-b", 13}, {"medium", 21103}, {"large", 101513}};
std::vector<std::size_t> rotation_points = {0, 1, 2, 3, 8,
56, 101, 1003, 101501};
for (const auto& it : scenarios) {
for (const auto& it2 : rotation_points) {
// for each view scenario, we rotate at multiple points
// but only if the view has an extent that is >= rotation point
const auto view_ext = it.second;
if (view_ext >= it2) {
run_single_scenario<Tag, ValueType>(it, it2);
}
}
}
}
TEST(std_algorithms_mod_seq_ops, rotate) {
run_all_scenarios<DynamicTag, int>();
run_all_scenarios<StridedThreeTag, int>();
run_all_scenarios<DynamicTag, double>();
run_all_scenarios<StridedThreeTag, double>();
}
} // namespace Rotate
} // namespace stdalgos
} // namespace Test

View File

@ -0,0 +1,275 @@
/*
//@HEADER
// ************************************************************************
//
// Kokkos v. 3.0
// Copyright (2020) 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.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the Corporation nor the names of the
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Questions? Contact Christian R. Trott (crtrott@sandia.gov)
//
// ************************************************************************
//@HEADER
*/
#include <TestStdAlgorithmsCommon.hpp>
#include <std_algorithms/Kokkos_BeginEnd.hpp>
#include <std_algorithms/Kokkos_ModifyingSequenceOperations.hpp>
#include <utility>
#include <algorithm>
namespace Test {
namespace stdalgos {
namespace RotateCopy {
namespace KE = Kokkos::Experimental;
template <class ValueType>
struct UnifDist;
template <>
struct UnifDist<int> {
using dist_type = std::uniform_int_distribution<int>;
std::mt19937 m_gen;
dist_type m_dist;
UnifDist() : m_dist(-50, 50) { m_gen.seed(1034343); }
int operator()() { return m_dist(m_gen); }
};
template <>
struct UnifDist<double> {
using dist_type = std::uniform_real_distribution<double>;
std::mt19937 m_gen;
dist_type m_dist;
UnifDist() : m_dist(-90., 100.) { m_gen.seed(1034343); }
double operator()() { return m_dist(m_gen); }
};
template <class ViewType>
void fill_view(ViewType dest_view, const std::string& name) {
using value_type = typename ViewType::value_type;
using exe_space = typename ViewType::execution_space;
const std::size_t ext = dest_view.extent(0);
using aux_view_t = Kokkos::View<value_type*, exe_space>;
aux_view_t aux_view("aux_view", ext);
auto v_h = create_mirror_view(Kokkos::HostSpace(), aux_view);
if (name == "empty") {
// no op
}
else if (name == "one-element-a") {
v_h(0) = static_cast<value_type>(1);
}
else if (name == "one-element-b") {
v_h(0) = static_cast<value_type>(2);
}
else if (name == "two-elements-a") {
v_h(0) = static_cast<value_type>(1);
v_h(1) = static_cast<value_type>(2);
}
else if (name == "two-elements-b") {
v_h(0) = static_cast<value_type>(2);
v_h(1) = static_cast<value_type>(-1);
}
else if (name == "small-a") {
v_h(0) = static_cast<value_type>(0);
v_h(1) = static_cast<value_type>(1);
v_h(2) = static_cast<value_type>(1);
v_h(3) = static_cast<value_type>(2);
v_h(4) = static_cast<value_type>(3);
v_h(5) = static_cast<value_type>(4);
v_h(6) = static_cast<value_type>(4);
v_h(7) = static_cast<value_type>(4);
v_h(8) = static_cast<value_type>(5);
v_h(9) = static_cast<value_type>(6);
v_h(10) = static_cast<value_type>(6);
}
else if (name == "small-b") {
v_h(0) = static_cast<value_type>(1);
v_h(1) = static_cast<value_type>(1);
v_h(2) = static_cast<value_type>(1);
v_h(3) = static_cast<value_type>(2);
v_h(4) = static_cast<value_type>(3);
v_h(5) = static_cast<value_type>(4);
v_h(6) = static_cast<value_type>(4);
v_h(7) = static_cast<value_type>(4);
v_h(8) = static_cast<value_type>(5);
v_h(9) = static_cast<value_type>(6);
v_h(10) = static_cast<value_type>(8);
v_h(11) = static_cast<value_type>(9);
v_h(12) = static_cast<value_type>(8);
}
else if (name == "medium" || name == "large") {
UnifDist<value_type> randObj;
for (std::size_t i = 0; i < ext; ++i) {
v_h(i) = randObj();
}
}
else {
throw std::runtime_error("invalid choice");
}
Kokkos::deep_copy(aux_view, v_h);
CopyFunctor<aux_view_t, ViewType> F1(aux_view, dest_view);
Kokkos::parallel_for("copy", dest_view.extent(0), F1);
}
template <class ViewTypeFrom, class ViewTypeTest>
void verify_data(ViewTypeFrom view_from, ViewTypeTest view_test,
std::size_t rotation_point) {
auto view_from_h = create_host_space_copy(view_from);
auto view_test_h = create_host_space_copy(view_test);
const std::size_t ext = view_test_h.extent(0);
using value_type = typename ViewTypeTest::value_type;
std::vector<value_type> std_gold_h(ext);
auto first_n = KE::cbegin(view_from_h) + rotation_point;
std::rotate_copy(KE::cbegin(view_from_h), first_n, KE::cend(view_from_h),
std_gold_h.begin());
for (std::size_t i = 0; i < ext; ++i) {
EXPECT_TRUE(view_test_h(i) == std_gold_h[i]);
// std::cout << "i= " << i << " "
// << "from: " << view_from_h(i) << " "
// << "mine: " << view_test_h(i) << " "
// << "std: " << std_gold_h[i]
// << '\n';
}
}
std::string value_type_to_string(int) { return "int"; }
std::string value_type_to_string(double) { return "double"; }
template <class Tag, class ValueType>
void print_scenario_details(const std::string& name,
std::size_t rotation_point) {
std::cout << "rotate_copy: "
<< " at " << rotation_point << ", " << name << ", "
<< view_tag_to_string(Tag{}) << ", "
<< value_type_to_string(ValueType()) << std::endl;
}
template <class Tag, class ValueType, class InfoType>
void run_single_scenario(const InfoType& scenario_info,
std::size_t rotation_point) {
const auto name = std::get<0>(scenario_info);
const std::size_t view_ext = std::get<1>(scenario_info);
// print_scenario_details<Tag, ValueType>(name, rotation_point);
auto view_from = create_view<ValueType>(Tag{}, view_ext, "rotate_copy_from");
fill_view(view_from, name);
{
auto view_dest =
create_view<ValueType>(Tag{}, view_ext, "rotate_copy_dest");
auto n_it = KE::cbegin(view_from) + rotation_point;
auto rit = KE::rotate_copy(exespace(), KE::cbegin(view_from), n_it,
KE::cend(view_from), KE::begin(view_dest));
verify_data(view_from, view_dest, rotation_point);
EXPECT_TRUE(rit == (KE::begin(view_dest) + view_ext));
}
{
auto view_dest =
create_view<ValueType>(Tag{}, view_ext, "rotate_copy_dest");
auto n_it = KE::cbegin(view_from) + rotation_point;
auto rit = KE::rotate_copy("label", exespace(), KE::cbegin(view_from), n_it,
KE::cend(view_from), KE::begin(view_dest));
verify_data(view_from, view_dest, rotation_point);
EXPECT_TRUE(rit == (KE::begin(view_dest) + view_ext));
}
{
auto view_dest =
create_view<ValueType>(Tag{}, view_ext, "rotate_copy_dest");
auto rit =
KE::rotate_copy(exespace(), view_from, rotation_point, view_dest);
verify_data(view_from, view_dest, rotation_point);
EXPECT_TRUE(rit == (KE::begin(view_dest) + view_ext));
}
{
auto view_dest =
create_view<ValueType>(Tag{}, view_ext, "rotate_copy_dest");
auto rit = KE::rotate_copy("label", exespace(), view_from, rotation_point,
view_dest);
verify_data(view_from, view_dest, rotation_point);
EXPECT_TRUE(rit == (KE::begin(view_dest) + view_ext));
}
Kokkos::fence();
}
template <class Tag, class ValueType>
void run_all_scenarios() {
const std::map<std::string, std::size_t> scenarios = {
{"empty", 0}, {"one-element-a", 1}, {"one-element-b", 1},
{"two-elements-a", 2}, {"two-elements-b", 2}, {"small-a", 11},
{"small-b", 13}, {"medium", 21103}, {"large", 101513}};
std::vector<std::size_t> rotation_points = {0, 1, 2, 3, 8,
56, 101, 1003, 101501};
for (const auto& it : scenarios) {
for (const auto& it2 : rotation_points) {
// for each view scenario, we rotate at multiple points
// but only if the view has an extent that is >= rotation point
const auto view_ext = it.second;
if (view_ext >= it2) {
run_single_scenario<Tag, ValueType>(it, it2);
}
}
}
}
TEST(std_algorithms_mod_seq_ops, rotate_copy) {
run_all_scenarios<DynamicTag, int>();
run_all_scenarios<StridedThreeTag, int>();
run_all_scenarios<DynamicTag, double>();
run_all_scenarios<StridedThreeTag, double>();
}
} // namespace RotateCopy
} // namespace stdalgos
} // namespace Test

View File

@ -0,0 +1,235 @@
/*
//@HEADER
// ************************************************************************
//
// Kokkos v. 3.0
// Copyright (2020) 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.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the Corporation nor the names of the
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Questions? Contact Christian R. Trott (crtrott@sandia.gov)
//
// ************************************************************************
//@HEADER
*/
#include <gtest/gtest.h>
#include <TestStdAlgorithmsHelperFunctors.hpp>
#include <std_algorithms/Kokkos_BeginEnd.hpp>
#include <std_algorithms/Kokkos_MinMaxElementOperations.hpp>
namespace KE = Kokkos::Experimental;
namespace Test {
namespace stdalgos {
template <class ViewType>
void fill_view(ViewType dest_view) {
using value_type = typename ViewType::value_type;
using exe_space = typename ViewType::execution_space;
using aux_view_t = Kokkos::View<value_type*, exe_space>;
const std::size_t ext = dest_view.extent(0);
aux_view_t aux_view("aux_view", ext);
auto v_h = create_mirror_view(Kokkos::HostSpace(), aux_view);
for (std::size_t i = 0; i < ext; ++i) {
v_h(i) = (value_type)i;
}
v_h(ext / 2) = (value_type)-101;
Kokkos::deep_copy(aux_view, v_h);
CopyFunctor<aux_view_t, ViewType> F1(aux_view, dest_view);
Kokkos::parallel_for("copy", dest_view.extent(0), F1);
}
template <class ViewType, class IndexType, class ReducerType>
struct MyFunctor {
using red_value_type = typename ReducerType::value_type;
ViewType m_view;
ReducerType m_reducer;
KOKKOS_FUNCTION
void operator()(const IndexType i, red_value_type& red_value) const {
m_reducer.join(red_value, red_value_type{m_view(i), i});
}
KOKKOS_FUNCTION
MyFunctor(ViewType view, ReducerType reducer)
: m_view(view), m_reducer(std::move(reducer)) {}
};
TEST(scalar_vs_view_red, use_scalar) {
using exe_space = Kokkos::DefaultExecutionSpace;
using index_type = int;
using scalar_type = int;
using view_type = Kokkos::View<scalar_type*, exe_space>;
const auto ext = 10001;
view_type view("myview", ext);
fill_view(view);
using reducer_type = ::Kokkos::MinLoc<scalar_type, index_type>;
using red_result_type = typename reducer_type::value_type;
using func_type = MyFunctor<view_type, index_type, reducer_type>;
red_result_type result;
reducer_type reducer(result);
Kokkos::parallel_reduce("MinLocReduce",
Kokkos::RangePolicy<exe_space>(exe_space(), 0, ext),
func_type(view, reducer), reducer);
std::cout << " use_scalar = " << result.val << '\n';
}
template <class IteratorType, class ReducerType>
struct StdMyMinFunctor {
using index_type = typename IteratorType::difference_type;
using red_value_type = typename ReducerType::value_type;
IteratorType m_first;
ReducerType m_reducer;
KOKKOS_FUNCTION
void operator()(const index_type i, red_value_type& red_value) const {
m_reducer.join(red_value, red_value_type{m_first[i], i});
}
KOKKOS_FUNCTION
StdMyMinFunctor(IteratorType first, ReducerType reducer)
: m_first(std::move(first)), m_reducer(std::move(reducer)) {}
};
template <class ViewType, class ReducerType>
struct StdMyMinFunctor2 {
using red_value_type = typename ReducerType::value_type;
ViewType m_view;
ReducerType m_reducer;
KOKKOS_FUNCTION
void operator()(const std::size_t i, red_value_type& red_value) const {
m_reducer.join(red_value, red_value_type{m_view(i), i});
}
KOKKOS_FUNCTION
StdMyMinFunctor2(ViewType viewIn, ReducerType reducer)
: m_view(viewIn), m_reducer(std::move(reducer)) {}
};
template <class ExecutionSpace, class IteratorType>
IteratorType my_min_1(const ExecutionSpace& ex, IteratorType first,
IteratorType last) {
using index_type = typename IteratorType::difference_type;
using value_type = typename IteratorType::value_type;
using reducer_type =
Kokkos::MinFirstLoc<value_type, index_type, ExecutionSpace>;
using result_view_type = typename reducer_type::result_view_type;
using func_t = StdMyMinFunctor<IteratorType, reducer_type>;
result_view_type result("min_or_max_elem_impl_result");
reducer_type reducer(result);
const auto num_elements = Kokkos::Experimental::distance(first, last);
::Kokkos::parallel_reduce(
"label", Kokkos::RangePolicy<ExecutionSpace>(ex, 0, num_elements),
func_t(first, reducer), reducer);
const auto result_h =
::Kokkos::create_mirror_view_and_copy(::Kokkos::HostSpace(), result);
return first + result_h().loc;
}
template <class ExecutionSpace, class IteratorType>
IteratorType my_min_2(const ExecutionSpace& ex, IteratorType first,
IteratorType last) {
using index_type = typename IteratorType::difference_type;
using value_type = typename IteratorType::value_type;
using reducer_type = Kokkos::MinFirstLoc<value_type, index_type>;
using result_type = typename reducer_type::value_type;
using func_t = StdMyMinFunctor<IteratorType, reducer_type>;
result_type result;
reducer_type reducer(result);
const auto num_elements = Kokkos::Experimental::distance(first, last);
::Kokkos::parallel_reduce(
"label", Kokkos::RangePolicy<ExecutionSpace>(ex, 0, num_elements),
func_t(first, reducer), reducer);
return first + result.loc;
}
template <class ExecutionSpace, class ViewType>
std::size_t my_min_3(const ExecutionSpace& ex, ViewType view) {
using index_type = std::size_t;
using value_type = typename ViewType::value_type;
using reducer_type = Kokkos::MinFirstLoc<value_type, index_type>;
using result_type = typename reducer_type::value_type;
using func_t = StdMyMinFunctor2<ViewType, reducer_type>;
result_type result;
reducer_type reducer(result);
const auto num_elements = view.extent(0);
::Kokkos::parallel_reduce(
"label", Kokkos::RangePolicy<ExecutionSpace>(ex, 0, num_elements),
func_t(view, reducer), reducer);
return result.loc;
}
TEST(scalar_vs_view_red, my_min_it_use_result_view) {
using exe_space = Kokkos::DefaultExecutionSpace;
using view_type = Kokkos::View<int*, exe_space>;
view_type view("myview", 10001);
fill_view(view);
auto rit = my_min_1(exe_space(), KE::cbegin(view), KE::cend(view));
std::cout << " my_min_el = " << KE::distance(KE::cbegin(view), rit) << '\n';
}
TEST(scalar_vs_view_red, my_min_no_it_use_result_scalar) {
using exe_space = Kokkos::DefaultExecutionSpace;
using view_type = Kokkos::View<int*, exe_space>;
view_type view("myview", 10001);
fill_view(view);
auto ind = my_min_3(exe_space(), view);
std::cout << " my_min_el = " << ind << '\n';
}
TEST(scalar_vs_view_red, my_min_it_use_result_scalar) {
using exe_space = Kokkos::DefaultExecutionSpace;
using view_type = Kokkos::View<int*, exe_space>;
view_type view("myview", 10001);
fill_view(view);
auto rit = my_min_2(exe_space(), KE::cbegin(view), KE::cend(view));
std::cout << " my_min_el = " << KE::distance(KE::cbegin(view), rit) << '\n';
}
} // namespace stdalgos
} // namespace Test

View File

@ -0,0 +1,364 @@
/*
//@HEADER
// ************************************************************************
//
// Kokkos v. 3.0
// Copyright (2020) 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.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the Corporation nor the names of the
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Questions? Contact Christian R. Trott (crtrott@sandia.gov)
//
// ************************************************************************
//@HEADER
*/
#include <TestStdAlgorithmsCommon.hpp>
#include <std_algorithms/Kokkos_BeginEnd.hpp>
#include <std_algorithms/Kokkos_ModifyingSequenceOperations.hpp>
#include <utility>
namespace Test {
namespace stdalgos {
namespace Search {
namespace KE = Kokkos::Experimental;
template <class ValueType>
struct UnifDist;
template <>
struct UnifDist<int> {
using dist_type = std::uniform_int_distribution<int>;
std::mt19937 m_gen;
dist_type m_dist;
UnifDist() : m_dist(0, 20) { m_gen.seed(1034343); }
UnifDist(int a, int b) : m_dist(a, b) { m_gen.seed(234343); }
int operator()() { return m_dist(m_gen); }
};
template <class ViewType>
void fill_view(ViewType dest_view, const std::string& name) {
using value_type = typename ViewType::value_type;
using exe_space = typename ViewType::execution_space;
const std::size_t ext = dest_view.extent(0);
using aux_view_t = Kokkos::View<value_type*, exe_space>;
aux_view_t aux_view("aux_view", ext);
auto v_h = create_mirror_view(Kokkos::HostSpace(), aux_view);
if (name == "empty") {
// no op
}
else if (name == "one-element-a") {
v_h(0) = static_cast<value_type>(1);
}
else if (name == "one-element-b") {
v_h(0) = static_cast<value_type>(2);
}
else if (name == "two-elements-a") {
v_h(0) = static_cast<value_type>(1);
v_h(1) = static_cast<value_type>(2);
}
else if (name == "two-elements-b") {
v_h(0) = static_cast<value_type>(2);
v_h(1) = static_cast<value_type>(-1);
}
else if (name == "three-elements-a") {
v_h(0) = static_cast<value_type>(-1);
v_h(1) = static_cast<value_type>(2);
v_h(2) = static_cast<value_type>(2);
}
else if (name == "three-elements-b") {
v_h(0) = static_cast<value_type>(3);
v_h(1) = static_cast<value_type>(1);
v_h(2) = static_cast<value_type>(3);
}
else if (name == "four-elements-a") {
v_h(0) = static_cast<value_type>(-1);
v_h(1) = static_cast<value_type>(2);
v_h(2) = static_cast<value_type>(2);
v_h(3) = static_cast<value_type>(4);
}
else if (name == "four-elements-b") {
v_h(0) = static_cast<value_type>(1);
v_h(1) = static_cast<value_type>(1);
v_h(2) = static_cast<value_type>(1);
v_h(3) = static_cast<value_type>(1);
}
else if (name == "small-a") {
v_h(0) = static_cast<value_type>(0);
v_h(1) = static_cast<value_type>(4);
v_h(2) = static_cast<value_type>(1);
v_h(3) = static_cast<value_type>(2);
v_h(4) = static_cast<value_type>(-1);
v_h(5) = static_cast<value_type>(4);
v_h(6) = static_cast<value_type>(1);
v_h(7) = static_cast<value_type>(2);
v_h(8) = static_cast<value_type>(2);
v_h(9) = static_cast<value_type>(4);
v_h(10) = static_cast<value_type>(1);
}
else if (name == "small-b") {
v_h(0) = static_cast<value_type>(1);
v_h(1) = static_cast<value_type>(2);
v_h(2) = static_cast<value_type>(3);
v_h(3) = static_cast<value_type>(1);
v_h(4) = static_cast<value_type>(-1);
v_h(5) = static_cast<value_type>(-2);
v_h(6) = static_cast<value_type>(0);
v_h(7) = static_cast<value_type>(1);
v_h(8) = static_cast<value_type>(2);
v_h(9) = static_cast<value_type>(2);
v_h(10) = static_cast<value_type>(5);
v_h(11) = static_cast<value_type>(9);
v_h(12) = static_cast<value_type>(8);
}
else {
UnifDist<value_type> randObj;
for (std::size_t i = 0; i < ext; ++i) {
v_h(i) = randObj();
}
}
Kokkos::deep_copy(aux_view, v_h);
CopyFunctor<aux_view_t, ViewType> F1(aux_view, dest_view);
Kokkos::parallel_for("copy", dest_view.extent(0), F1);
}
template <class ViewType>
auto create_seq_to_search(ViewType data_view, std::size_t seq_extent) {
// for the search, we need to specify a sequence that we search for
// within the original view/range.
// to do this, rather than doing something purely random,
// we use the view with the data, and select a subsequence.
auto data_view_h = create_host_space_copy(data_view);
const auto data_view_extent = data_view.extent(0);
using value_type = typename ViewType::value_type;
using exe_space = typename ViewType::execution_space;
using seq_view_t = Kokkos::View<value_type*, exe_space>;
seq_view_t seq_view("seq_view", seq_extent);
auto seq_view_h = create_mirror_view(Kokkos::HostSpace(), seq_view);
// when the target sequence is of same size as view, just fill
// sequeunce with all values of the view
if (seq_extent == data_view_extent) {
for (std::size_t i = 0; i < seq_extent; ++i) {
seq_view_h(i) = data_view_h(i);
}
} else {
// if target sequence to fill is smaller, then we need to pick
// a starting point to copy data from to make the the sequence.
// we pick randomly between 0 and data_view_extent - seq_extent.
// and fill the sequeunce data with the values copied from data view.
using dist_type = std::uniform_int_distribution<int>;
std::random_device r;
// from this:
// https://stackoverflow.com/questions/34490599/c11-how-to-set-seed-using-random
std::seed_seq seed{r(), r(), r(), r(), r(), r()};
std::mt19937 gen(seed);
dist_type dist(0, data_view_extent - seq_extent);
const auto start = dist(gen);
// std::cout << "start= " << start << "\n";
for (std::size_t i = 0; i < seq_extent; ++i) {
seq_view_h(i) = data_view_h(start + i);
// std::cout << "i= " << i << " " << seq_view_h(i) << "\n";
}
}
Kokkos::deep_copy(seq_view, seq_view_h);
return seq_view;
}
// search is only avai from c++17, so I have to put it here
template <class ForwardIt1, class ForwardIt2, class BinaryPredicate>
ForwardIt1 my_std_search(ForwardIt1 first, ForwardIt1 last, ForwardIt2 s_first,
ForwardIt2 s_last, BinaryPredicate p) {
for (;; ++first) {
ForwardIt1 it = first;
for (ForwardIt2 s_it = s_first;; ++it, ++s_it) {
if (s_it == s_last) {
return first;
}
if (it == last) {
return last;
}
if (!p(*it, *s_it)) {
break;
}
}
}
}
// search is only avai from c++17, so I have to put it here
template <class ForwardIt1, class ForwardIt2>
ForwardIt1 my_std_search(ForwardIt1 first, ForwardIt1 last, ForwardIt2 s_first,
ForwardIt2 s_last) {
using value_type1 = typename ForwardIt1::value_type;
using value_type2 = typename ForwardIt2::value_type;
using pred_t = IsEqualFunctor<value_type1, value_type2>;
return my_std_search(first, last, s_first, s_last, pred_t());
}
std::string value_type_to_string(int) { return "int"; }
std::string value_type_to_string(double) { return "double"; }
template <class Tag, class ValueType>
void print_scenario_details(const std::string& name, std::size_t seq_ext) {
std::cout << "search: default predicate: " << name << ", "
<< "search_seq_ext = " << seq_ext << ", "
<< view_tag_to_string(Tag{}) << " "
<< value_type_to_string(ValueType()) << std::endl;
}
template <class Tag, class ValueType, class Predicate>
void print_scenario_details(const std::string& name, std::size_t seq_ext,
Predicate pred) {
(void)pred;
std::cout << "search: custom predicate: " << name << ", "
<< "search_seq_ext = " << seq_ext << ", "
<< view_tag_to_string(Tag{}) << " "
<< value_type_to_string(ValueType()) << std::endl;
}
template <class Tag, class ValueType, class InfoType, class... Args>
void run_single_scenario(const InfoType& scenario_info, std::size_t seq_ext,
Args... args) {
const auto name = std::get<0>(scenario_info);
const std::size_t view_ext = std::get<1>(scenario_info);
// print_scenario_details<Tag, ValueType>(name, seq_ext, args...);
auto view = create_view<ValueType>(Tag{}, view_ext, "search_test_view");
fill_view(view, name);
auto s_view = create_seq_to_search(view, seq_ext);
// run std
auto view_h = create_host_space_copy(view);
auto s_view_h = create_host_space_copy(s_view);
auto stdrit =
my_std_search(KE::cbegin(view_h), KE::cend(view_h), KE::cbegin(s_view_h),
KE::cend(s_view_h), args...);
{
auto myrit = KE::search(exespace(), KE::cbegin(view), KE::cend(view),
KE::cbegin(s_view), KE::cend(s_view), args...);
const auto mydiff = myrit - KE::cbegin(view);
const auto stddiff = stdrit - KE::cbegin(view_h);
EXPECT_TRUE(mydiff == stddiff);
}
{
auto myrit =
KE::search("label", exespace(), KE::cbegin(view), KE::cend(view),
KE::cbegin(s_view), KE::cend(s_view), args...);
const auto mydiff = myrit - KE::cbegin(view);
const auto stddiff = stdrit - KE::cbegin(view_h);
EXPECT_TRUE(mydiff == stddiff);
}
{
auto myrit = KE::search(exespace(), view, s_view, args...);
const auto mydiff = myrit - KE::begin(view);
const auto stddiff = stdrit - KE::cbegin(view_h);
EXPECT_TRUE(mydiff == stddiff);
}
{
auto myrit = KE::search("label", exespace(), view, s_view, args...);
const auto mydiff = myrit - KE::begin(view);
const auto stddiff = stdrit - KE::cbegin(view_h);
EXPECT_TRUE(mydiff == stddiff);
}
Kokkos::fence();
}
template <class Tag, class ValueType>
void run_all_scenarios() {
const std::map<std::string, std::size_t> scenarios = {{"empty", 0},
{"one-element-a", 1},
{"one-element-b", 1},
{"two-elements-a", 2},
{"two-elements-b", 2},
{"three-elements-a", 3},
{"three-elements-b", 3},
{"four-elements-a", 4},
{"four-elements-b", 4},
{"small-a", 11},
{"small-b", 13},
{"medium-a", 11103},
{"medium-b", 21103},
{"large-a", 101513},
{"large-b", 100111}};
const std::vector<std::size_t> seq_extents = {
0, 1, 2, 3, 4, 5, 8, 11, 15, 31, 113, 523, 1035, 11103};
// for each scenario we want to run "search"
// for a set of sequences of various extents
for (const auto& it : scenarios) {
for (const auto& it2 : seq_extents) {
// only run if view is larger or equal than sequence to search for
if (it.second >= it2) {
run_single_scenario<Tag, ValueType>(it, it2);
using func_t = IsEqualFunctor<ValueType>;
run_single_scenario<Tag, ValueType>(it, it2, func_t());
}
}
}
}
TEST(std_algorithms_non_mod_seq_ops, search) {
run_all_scenarios<DynamicTag, int>();
run_all_scenarios<StridedThreeTag, int>();
}
} // namespace Search
} // namespace stdalgos
} // namespace Test

View File

@ -0,0 +1,336 @@
/*
//@HEADER
// ************************************************************************
//
// Kokkos v. 3.0
// Copyright (2020) 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.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the Corporation nor the names of the
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Questions? Contact Christian R. Trott (crtrott@sandia.gov)
//
// ************************************************************************
//@HEADER
*/
#include <TestStdAlgorithmsCommon.hpp>
#include <std_algorithms/Kokkos_BeginEnd.hpp>
#include <std_algorithms/Kokkos_ModifyingSequenceOperations.hpp>
#include <utility>
namespace Test {
namespace stdalgos {
namespace Search_n {
namespace KE = Kokkos::Experimental;
// search_n is only available from c++20, so I have to put it here
template <class ForwardIt, class Size, class T, class BinaryPredicate>
ForwardIt my_std_search_n(ForwardIt first, ForwardIt last, Size count,
const T& value, BinaryPredicate p) {
if (count <= 0) {
return first;
}
for (; first != last; ++first) {
if (!p(*first, value)) {
continue;
}
ForwardIt candidate = first;
Size cur_count = 0;
while (true) {
++cur_count;
if (cur_count >= count) {
// success
return candidate;
}
++first;
if (first == last) {
// exhausted the list
return last;
}
if (!p(*first, value)) {
// too few in a row
break;
}
}
}
return last;
}
template <class ForwardIt, class Size, class T>
ForwardIt my_std_search_n(ForwardIt first, ForwardIt last, Size count,
const T& value) {
using iter_value_type = typename ForwardIt::value_type;
using p_type = IsEqualFunctor<iter_value_type, T>;
return my_std_search_n(first, last, count, value, p_type());
}
std::string value_type_to_string(int) { return "int"; }
std::string value_type_to_string(double) { return "double"; }
template <class ValueType>
struct UnifDist;
template <>
struct UnifDist<int> {
using dist_type = std::uniform_int_distribution<int>;
std::mt19937 m_gen;
dist_type m_dist;
UnifDist() : m_dist(0, 20) { m_gen.seed(1034343); }
UnifDist(int a, int b) : m_dist(a, b) { m_gen.seed(234343); }
int operator()() { return m_dist(m_gen); }
};
template <class ViewType, class ValueType>
void fill_view(ViewType dest_view, ValueType value, std::size_t count,
const std::string& where_to_place_count_values) {
using value_type = typename ViewType::value_type;
using exe_space = typename ViewType::execution_space;
const std::size_t ext = dest_view.extent(0);
using aux_view_t = Kokkos::View<value_type*, exe_space>;
aux_view_t aux_view("aux_view", ext);
auto v_h = create_mirror_view(Kokkos::HostSpace(), aux_view);
// fill with something
for (std::size_t i = 0; i < ext; ++i) {
v_h(i) = 15;
}
if (where_to_place_count_values == "none") {
// do nothing
}
else if (where_to_place_count_values == "left") {
for (std::size_t i = 0; i < count; ++i) {
v_h(i) = value;
}
}
else if (where_to_place_count_values == "left_and_1567") {
for (std::size_t i = 0; i < count; ++i) {
v_h(i) = value;
}
for (std::size_t i = 0; i < count; ++i) {
v_h(1567 + i) = value;
}
}
else if (where_to_place_count_values == "random") {
// find a random location to start filling view
using dist_type = std::uniform_int_distribution<int>;
std::random_device r;
// from this:
// https://stackoverflow.com/questions/34490599/c11-how-to-set-seed-using-random
std::seed_seq seed{r(), r(), r(), r(), r(), r()};
std::mt19937 gen(seed);
dist_type dist(0, ext - count);
const auto start_at = dist(gen);
// std::cout << "start_at " << start_at << std::endl;
for (std::size_t i = 0; i < count; ++i) {
v_h(start_at + i) = value;
}
}
else if (where_to_place_count_values == "11133_and_right") {
for (std::size_t i = 0; i < count; ++i) {
v_h(11133 + i) = value;
}
for (std::size_t i = 0; i < count; ++i) {
v_h(ext - count + i) = value;
}
}
else if (where_to_place_count_values == "right") {
for (std::size_t i = 0; i < count; ++i) {
v_h(ext - count + i) = value;
}
}
else {
throw std::runtime_error("Kokkos: test: search_n: this should not happen");
}
Kokkos::deep_copy(aux_view, v_h);
CopyFunctor<aux_view_t, ViewType> F1(aux_view, dest_view);
Kokkos::parallel_for("copy", dest_view.extent(0), F1);
}
template <class Tag, class ValueType>
void print_scenario_details(const std::string& name, std::size_t count,
const std::string& where_to_place_count_values) {
std::cout << "search_n: default predicate: " << name << ", "
<< "count = " << count << ", " << where_to_place_count_values
<< ", " << view_tag_to_string(Tag{}) << " "
<< value_type_to_string(ValueType()) << std::endl;
}
template <class Tag, class ValueType, class Predicate>
void print_scenario_details(const std::string& name, std::size_t count,
const std::string& where_to_place_count_values,
Predicate pred) {
(void)pred;
std::cout << "search_n: custom predicate: " << name << ", "
<< "count = " << count << ", " << where_to_place_count_values
<< ", " << view_tag_to_string(Tag{}) << " "
<< value_type_to_string(ValueType()) << std::endl;
}
template <class Tag, class ValueType, class InfoType, class... Args>
void run_single_scenario(const InfoType& scenario_info, std::size_t count,
ValueType value, Args... args) {
const auto name = std::get<0>(scenario_info);
const std::size_t view_ext = std::get<1>(scenario_info);
const auto count_place = std::get<2>(scenario_info);
// print_scenario_details<Tag, ValueType>(name, count, count_place, args...);
auto view = create_view<ValueType>(Tag{}, view_ext, "search_n_test_view");
fill_view(view, value, count, count_place);
// run std
auto view_h = create_host_space_copy(view);
auto stdrit = my_std_search_n(KE::cbegin(view_h), KE::cend(view_h), count,
value, args...);
const auto stddiff = stdrit - KE::cbegin(view_h);
{
auto myrit = KE::search_n(exespace(), KE::cbegin(view), KE::cend(view),
count, value, args...);
const auto mydiff = myrit - KE::cbegin(view);
EXPECT_TRUE(mydiff == stddiff);
}
{
auto myrit = KE::search_n("label", exespace(), KE::cbegin(view),
KE::cend(view), count, value, args...);
const auto mydiff = myrit - KE::cbegin(view);
EXPECT_TRUE(mydiff == stddiff);
}
{
auto myrit = KE::search_n("label", exespace(), view, count, value, args...);
const auto mydiff = myrit - KE::begin(view);
EXPECT_TRUE(mydiff == stddiff);
}
{
auto myrit = KE::search_n(exespace(), view, count, value, args...);
const auto mydiff = myrit - KE::begin(view);
EXPECT_TRUE(mydiff == stddiff);
}
Kokkos::fence();
}
template <class Tag, class ValueType>
void run_all_scenarios() {
using scenario_t = std::tuple<std::string, std::size_t, std::string>;
std::vector<scenario_t> scenarios(31);
scenarios[0] = scenario_t("empty", 0u, "none");
scenarios[1] = scenario_t("one-element-a", 1u, "none");
scenarios[2] = scenario_t("one-element-b", 1u, "left");
scenarios[3] = scenario_t("two-elements-a", 2u, "none");
scenarios[4] = scenario_t("two-elements-b", 2u, "left");
scenarios[5] = scenario_t("two-elements-c", 2u, "right");
scenarios[6] = scenario_t("three-elements-a", 3u, "none");
scenarios[7] = scenario_t("three-elements-b", 3u, "left");
scenarios[8] = scenario_t("three-elements-c", 3u, "random");
scenarios[9] = scenario_t("three-elements-d", 3u, "right");
scenarios[10] = scenario_t("four-elements-a", 4u, "none");
scenarios[11] = scenario_t("four-elements-b", 4u, "left");
scenarios[12] = scenario_t("four-elements-c", 4u, "random");
scenarios[13] = scenario_t("four-elements-d", 4u, "right");
scenarios[14] = scenario_t("small-a", 13u, "none");
scenarios[15] = scenario_t("small-b", 13u, "left");
scenarios[16] = scenario_t("small-c", 13u, "random");
scenarios[17] = scenario_t("small-d", 13u, "right");
scenarios[18] = scenario_t("small-e", 131u, "none");
scenarios[19] = scenario_t("small-f", 131u, "left");
scenarios[20] = scenario_t("small-g", 131u, "random");
scenarios[21] = scenario_t("small-h", 131u, "right");
scenarios[22] = scenario_t("medium-a", 21103u, "none");
scenarios[22] = scenario_t("medium-b", 21103u, "left");
scenarios[23] = scenario_t("medium-c", 21103u, "random");
scenarios[24] = scenario_t("medium-d", 21103u, "right");
scenarios[25] = scenario_t("medium-e", 21103u, "left_and_1567");
scenarios[26] = scenario_t("medium-f", 21103u, "11133_and_right");
scenarios[27] = scenario_t("large-a", 101333u, "none");
scenarios[28] = scenario_t("large-b", 101333u, "left");
scenarios[29] = scenario_t("large-c", 101333u, "random");
scenarios[30] = scenario_t("large-d", 101333u, "right");
const std::vector<std::size_t> counts = {1, 2, 3, 4, 5, 8,
11, 13, 31, 131, 523};
const ValueType target_value = 3;
// for each view scenario, run "search_n" for multiple counts
for (const auto& it : scenarios) {
const std::size_t view_ext = std::get<1>(it);
if (view_ext == 0) {
run_single_scenario<Tag, ValueType>(it, 0, target_value);
} else {
for (const auto& it2 : counts) {
// only run if view is larger or equal than count
if (view_ext >= it2) {
run_single_scenario<Tag, ValueType>(it, it2, target_value);
using func_t = IsEqualFunctor<ValueType>;
run_single_scenario<Tag, ValueType>(it, it2, target_value, func_t());
}
}
}
}
}
TEST(std_algorithms_non_mod_seq_ops, search_n) {
run_all_scenarios<DynamicTag, int>();
run_all_scenarios<StridedThreeTag, int>();
}
} // namespace Search_n
} // namespace stdalgos
} // namespace Test

View File

@ -0,0 +1,243 @@
/*
//@HEADER
// ************************************************************************
//
// Kokkos v. 3.0
// Copyright (2020) 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.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the Corporation nor the names of the
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Questions? Contact Christian R. Trott (crtrott@sandia.gov)
//
// ************************************************************************
//@HEADER
*/
#include <TestStdAlgorithmsCommon.hpp>
#include <std_algorithms/Kokkos_BeginEnd.hpp>
#include <std_algorithms/Kokkos_ModifyingSequenceOperations.hpp>
#include <utility>
#include <algorithm>
namespace Test {
namespace stdalgos {
namespace ShiftLeft {
namespace KE = Kokkos::Experimental;
template <class ValueType>
struct UnifDist;
template <>
struct UnifDist<int> {
using dist_type = std::uniform_int_distribution<int>;
std::mt19937 m_gen;
dist_type m_dist;
UnifDist() : m_dist(-50, 50) { m_gen.seed(1034343); }
int operator()() { return m_dist(m_gen); }
};
template <>
struct UnifDist<double> {
using dist_type = std::uniform_real_distribution<double>;
std::mt19937 m_gen;
dist_type m_dist;
UnifDist() : m_dist(-90., 100.) { m_gen.seed(1034343); }
double operator()() { return m_dist(m_gen); }
};
template <class ViewType>
void fill_view(ViewType dest_view, const std::string& name) {
using value_type = typename ViewType::value_type;
using exe_space = typename ViewType::execution_space;
const std::size_t ext = dest_view.extent(0);
using aux_view_t = Kokkos::View<value_type*, exe_space>;
aux_view_t aux_view("aux_view", ext);
auto v_h = create_mirror_view(Kokkos::HostSpace(), aux_view);
if (name == "empty") {
// no op
}
else {
UnifDist<value_type> randObj;
for (std::size_t i = 0; i < ext; ++i) {
v_h(i) = randObj();
}
}
Kokkos::deep_copy(aux_view, v_h);
CopyFunctor<aux_view_t, ViewType> F1(aux_view, dest_view);
Kokkos::parallel_for("copy", dest_view.extent(0), F1);
}
template <class ForwardIterator>
ForwardIterator my_std_shift_left(
ForwardIterator first, ForwardIterator last,
typename std::iterator_traits<ForwardIterator>::difference_type n) {
// copied from
// https://github.com/llvm/llvm-project/blob/main/libcxx/include/__algorithm/shift_left.h
if (n == 0) {
return last;
}
ForwardIterator m = first;
for (; n > 0; --n) {
if (m == last) {
return first;
}
++m;
}
return std::move(m, last, first);
}
template <class ViewType, class ResultIt, class ViewHostType>
void verify_data(ResultIt result_it, ViewType view, ViewHostType data_view_host,
std::size_t shift_value) {
auto std_rit = my_std_shift_left(KE::begin(data_view_host),
KE::end(data_view_host), shift_value);
// make sure results match
const auto my_diff = result_it - KE::begin(view);
const auto std_diff = std_rit - KE::begin(data_view_host);
EXPECT_TRUE(my_diff == std_diff);
// check views match
auto view_h = create_host_space_copy(view);
for (std::size_t i = 0; i < (std::size_t)my_diff; ++i) {
EXPECT_TRUE(view_h(i) == data_view_host[i]);
// std::cout << "i= " << i << " "
// << "mine: " << view_h(i) << " "
// << "std: " << data_view_host(i)
// << '\n';
}
}
std::string value_type_to_string(int) { return "int"; }
std::string value_type_to_string(double) { return "double"; }
template <class Tag, class ValueType>
void print_scenario_details(const std::string& name, std::size_t shift_value) {
std::cout << "shift_left: "
<< " by " << shift_value << ", " << name << ", "
<< view_tag_to_string(Tag{}) << ", "
<< value_type_to_string(ValueType()) << std::endl;
}
template <class Tag, class ValueType, class InfoType>
void run_single_scenario(const InfoType& scenario_info,
std::size_t shift_value) {
const auto name = std::get<0>(scenario_info);
const std::size_t view_ext = std::get<1>(scenario_info);
// print_scenario_details<Tag, ValueType>(name, shift_value);
{
auto view = create_view<ValueType>(Tag{}, view_ext, "shift_left_data_view");
fill_view(view, name);
// create host copy BEFORE shift_left or view will be modified
auto view_h = create_host_space_copy(view);
auto rit =
KE::shift_left(exespace(), KE::begin(view), KE::end(view), shift_value);
verify_data(rit, view, view_h, shift_value);
}
{
auto view = create_view<ValueType>(Tag{}, view_ext, "shift_left_data_view");
fill_view(view, name);
// create host copy BEFORE shift_left or view will be modified
auto view_h = create_host_space_copy(view);
auto rit = KE::shift_left("label", exespace(), KE::begin(view),
KE::end(view), shift_value);
verify_data(rit, view, view_h, shift_value);
}
{
auto view = create_view<ValueType>(Tag{}, view_ext, "shift_left_data_view");
fill_view(view, name);
// create host copy BEFORE shift_left or view will be modified
auto view_h = create_host_space_copy(view);
auto rit = KE::shift_left(exespace(), view, shift_value);
verify_data(rit, view, view_h, shift_value);
}
{
auto view = create_view<ValueType>(Tag{}, view_ext, "shift_left_data_view");
fill_view(view, name);
// create host copy BEFORE shift_left or view will be modified
auto view_h = create_host_space_copy(view);
auto rit = KE::shift_left("label", exespace(), view, shift_value);
verify_data(rit, view, view_h, shift_value);
}
Kokkos::fence();
}
template <class Tag, class ValueType>
void run_all_scenarios() {
const std::map<std::string, std::size_t> scenarios = {{"empty", 0},
{"one-element-a", 1},
{"one-element-b", 1},
{"two-elements-a", 2},
{"two-elements-b", 2},
{"three-elements-a", 3},
{"three-elements-b", 3},
{"small-a", 11},
{"small-b", 13},
{"medium", 21103},
{"large", 101513}};
// a shift value MUST be non-negative but it does not matter
// if it is larger than the view, the algorithm is supposed
// to handle that case too
std::vector<std::size_t> shifts = {0, 1, 2, 3, 8, 56, 101, 1003, 101501};
for (const auto& it : scenarios) {
for (const auto& it2 : shifts) {
run_single_scenario<Tag, ValueType>(it, it2);
}
}
}
TEST(std_algorithms_mod_seq_ops, shift_left) {
run_all_scenarios<DynamicTag, int>();
run_all_scenarios<StridedThreeTag, int>();
run_all_scenarios<DynamicTag, double>();
run_all_scenarios<StridedThreeTag, double>();
}
} // namespace ShiftLeft
} // namespace stdalgos
} // namespace Test

View File

@ -0,0 +1,247 @@
/*
//@HEADER
// ************************************************************************
//
// Kokkos v. 3.0
// Copyright (2020) 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.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the Corporation nor the names of the
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Questions? Contact Christian R. Trott (crtrott@sandia.gov)
//
// ************************************************************************
//@HEADER
*/
#include <TestStdAlgorithmsCommon.hpp>
#include <std_algorithms/Kokkos_BeginEnd.hpp>
#include <std_algorithms/Kokkos_ModifyingSequenceOperations.hpp>
#include <utility>
#include <algorithm>
namespace Test {
namespace stdalgos {
namespace ShiftRight {
namespace KE = Kokkos::Experimental;
template <class ValueType>
struct UnifDist;
template <>
struct UnifDist<int> {
using dist_type = std::uniform_int_distribution<int>;
std::mt19937 m_gen;
dist_type m_dist;
UnifDist() : m_dist(-50, 50) { m_gen.seed(1034343); }
int operator()() { return m_dist(m_gen); }
};
template <>
struct UnifDist<double> {
using dist_type = std::uniform_real_distribution<double>;
std::mt19937 m_gen;
dist_type m_dist;
UnifDist() : m_dist(-90., 100.) { m_gen.seed(1034343); }
double operator()() { return m_dist(m_gen); }
};
template <class ViewType>
void fill_view(ViewType dest_view, const std::string& name) {
using value_type = typename ViewType::value_type;
using exe_space = typename ViewType::execution_space;
const std::size_t ext = dest_view.extent(0);
using aux_view_t = Kokkos::View<value_type*, exe_space>;
aux_view_t aux_view("aux_view", ext);
auto v_h = create_mirror_view(Kokkos::HostSpace(), aux_view);
if (name == "empty") {
// no op
}
else {
UnifDist<value_type> randObj;
for (std::size_t i = 0; i < ext; ++i) {
v_h(i) = randObj();
}
}
Kokkos::deep_copy(aux_view, v_h);
CopyFunctor<aux_view_t, ViewType> F1(aux_view, dest_view);
Kokkos::parallel_for("copy", dest_view.extent(0), F1);
}
template <class ForwardIterator>
ForwardIterator my_std_shift_right(
ForwardIterator first, ForwardIterator last,
typename std::iterator_traits<ForwardIterator>::difference_type n) {
// copied from
// https://github.com/llvm/llvm-project/blob/main/libcxx/include/__algorithm/shift_right.h
if (n == 0) {
return first;
}
decltype(n) d = last - first;
if (n >= d) {
return last;
}
ForwardIterator m = first + (d - n);
return std::move_backward(first, m, last);
}
template <class ViewType, class ResultIt, class ViewHostType>
void verify_data(ResultIt result_it, ViewType view, ViewHostType data_view_host,
std::size_t shift_value) {
auto std_rit = my_std_shift_right(KE::begin(data_view_host),
KE::end(data_view_host), shift_value);
// make sure results match
const auto my_diff = KE::end(view) - result_it;
const auto std_diff = KE::end(data_view_host) - std_rit;
EXPECT_TRUE(my_diff == std_diff);
// check views match
auto view_h = create_host_space_copy(view);
auto it1 = KE::cbegin(view_h);
auto it2 = KE::cbegin(data_view_host);
for (std::size_t i = 0; i < (std::size_t)my_diff; ++i) {
EXPECT_TRUE(it1[i] == it2[i]);
// std::cout << "i= " << i << " "
// << "mine: " << it1[i] << " "
// << "std: " << it2[i]
// << '\n';
}
}
std::string value_type_to_string(int) { return "int"; }
std::string value_type_to_string(double) { return "double"; }
template <class Tag, class ValueType>
void print_scenario_details(const std::string& name, std::size_t shift_value) {
std::cout << "shift_right: "
<< " by " << shift_value << ", " << name << ", "
<< view_tag_to_string(Tag{}) << ", "
<< value_type_to_string(ValueType()) << std::endl;
}
template <class Tag, class ValueType, class InfoType>
void run_single_scenario(const InfoType& scenario_info,
std::size_t shift_value) {
const auto name = std::get<0>(scenario_info);
const std::size_t view_ext = std::get<1>(scenario_info);
// print_scenario_details<Tag, ValueType>(name, shift_value);
{
auto view =
create_view<ValueType>(Tag{}, view_ext, "shift_right_data_view");
fill_view(view, name);
// create host copy BEFORE shift_right or view will be modified
auto view_h = create_host_space_copy(view);
auto rit = KE::shift_right(exespace(), KE::begin(view), KE::end(view),
shift_value);
verify_data(rit, view, view_h, shift_value);
}
{
auto view =
create_view<ValueType>(Tag{}, view_ext, "shift_right_data_view");
fill_view(view, name);
// create host copy BEFORE shift_right or view will be modified
auto view_h = create_host_space_copy(view);
auto rit = KE::shift_right("label", exespace(), KE::begin(view),
KE::end(view), shift_value);
verify_data(rit, view, view_h, shift_value);
}
{
auto view =
create_view<ValueType>(Tag{}, view_ext, "shift_right_data_view");
fill_view(view, name);
// create host copy BEFORE shift_right or view will be modified
auto view_h = create_host_space_copy(view);
auto rit = KE::shift_right(exespace(), view, shift_value);
verify_data(rit, view, view_h, shift_value);
}
{
auto view =
create_view<ValueType>(Tag{}, view_ext, "shift_right_data_view");
fill_view(view, name);
// create host copy BEFORE shift_right or view will be modified
auto view_h = create_host_space_copy(view);
auto rit = KE::shift_right("label", exespace(), view, shift_value);
verify_data(rit, view, view_h, shift_value);
}
Kokkos::fence();
}
template <class Tag, class ValueType>
void run_all_scenarios() {
const std::map<std::string, std::size_t> scenarios = {{"empty", 0},
{"one-element-a", 1},
{"one-element-b", 1},
{"two-elements-a", 2},
{"two-elements-b", 2},
{"three-elements-a", 3},
{"three-elements-b", 3},
{"small-a", 11},
{"small-b", 13},
{"medium", 21103},
{"large", 101513}};
// a shift value MUST be non-negative but it does not matter
// if it is larger than the view, the algorithm is supposed
// to handle that case too
std::vector<std::size_t> shifts = {0, 1, 2, 3, 8, 56, 101, 1003, 101501};
for (const auto& it : scenarios) {
for (const auto& it2 : shifts) {
run_single_scenario<Tag, ValueType>(it, it2);
}
}
}
TEST(std_algorithms_mod_seq_ops, shift_right) {
run_all_scenarios<DynamicTag, int>();
run_all_scenarios<StridedThreeTag, int>();
run_all_scenarios<DynamicTag, double>();
run_all_scenarios<StridedThreeTag, double>();
}
} // namespace ShiftRight
} // namespace stdalgos
} // namespace Test

View File

@ -0,0 +1,320 @@
/*
//@HEADER
// ************************************************************************
//
// Kokkos v. 3.0
// Copyright (2020) 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.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the Corporation nor the names of the
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Questions? Contact Christian R. Trott (crtrott@sandia.gov)
//
// ************************************************************************
//@HEADER
*/
#include <TestStdAlgorithmsCommon.hpp>
#include <std_algorithms/Kokkos_BeginEnd.hpp>
#include <std_algorithms/Kokkos_Numeric.hpp>
#include <utility>
namespace Test {
namespace stdalgos {
namespace TransformEScan {
namespace KE = Kokkos::Experimental;
template <class ValueType>
struct UnifDist;
template <>
struct UnifDist<double> {
using dist_type = std::uniform_real_distribution<double>;
std::mt19937 m_gen;
dist_type m_dist;
UnifDist() : m_dist(0.05, 1.2) { m_gen.seed(1034343); }
double operator()() { return m_dist(m_gen); }
};
template <>
struct UnifDist<int> {
using dist_type = std::uniform_int_distribution<int>;
std::mt19937 m_gen;
dist_type m_dist;
UnifDist() : m_dist(1, 3) { m_gen.seed(1034343); }
int operator()() { return m_dist(m_gen); }
};
template <class ViewType>
void fill_zero(ViewType view) {
Kokkos::parallel_for(view.extent(0), FillZeroFunctor<ViewType>(view));
}
template <class ViewType>
void fill_view(ViewType dest_view, const std::string& name) {
using value_type = typename ViewType::value_type;
using exe_space = typename ViewType::execution_space;
const std::size_t ext = dest_view.extent(0);
using aux_view_t = Kokkos::View<value_type*, exe_space>;
aux_view_t aux_view("aux_view", ext);
auto v_h = create_mirror_view(Kokkos::HostSpace(), aux_view);
UnifDist<value_type> randObj;
if (name == "empty") {
// no op
}
else if (name == "one-element") {
assert(v_h.extent(0) == 1);
v_h(0) = static_cast<value_type>(1);
}
else if (name == "two-elements-a") {
assert(v_h.extent(0) == 2);
v_h(0) = static_cast<value_type>(1);
v_h(1) = static_cast<value_type>(2);
}
else if (name == "two-elements-b") {
assert(v_h.extent(0) == 2);
v_h(0) = static_cast<value_type>(2);
v_h(1) = static_cast<value_type>(-1);
}
else if (name == "small-a") {
assert(v_h.extent(0) == 9);
v_h(0) = static_cast<value_type>(3);
v_h(1) = static_cast<value_type>(1);
v_h(2) = static_cast<value_type>(4);
v_h(3) = static_cast<value_type>(1);
v_h(4) = static_cast<value_type>(5);
v_h(5) = static_cast<value_type>(9);
v_h(6) = static_cast<value_type>(2);
v_h(7) = static_cast<value_type>(6);
v_h(8) = static_cast<value_type>(2);
}
else if (name == "small-b") {
assert(v_h.extent(0) >= 6);
for (std::size_t i = 0; i < ext; ++i) {
v_h(i) = randObj();
}
v_h(5) = static_cast<value_type>(-2);
}
else if (name == "medium" || name == "large") {
for (std::size_t i = 0; i < ext; ++i) {
v_h(i) = randObj();
}
}
else {
throw std::runtime_error("invalid choice");
}
Kokkos::deep_copy(aux_view, v_h);
CopyFunctor<aux_view_t, ViewType> F1(aux_view, dest_view);
Kokkos::parallel_for("copy", dest_view.extent(0), F1);
}
// I had to write my own because std::transform_exclusive_scan is ONLY found
// with std=c++17
template <class it1, class it2, class ValType, class BopType, class UopType>
void my_host_transform_exclusive_scan(it1 first, it1 last, it2 dest,
ValType init, BopType bop, UopType uop) {
const auto num_elements = last - first;
if (num_elements > 0) {
while (first < last - 1) {
*(dest++) = init;
init = bop(uop(*(first++)), init);
}
*dest = init;
}
}
template <class ViewType1, class ViewType2, class ValueType, class BinaryOp,
class UnaryOp>
void verify_data(ViewType1 data_view, // contains data
ViewType2 test_view, // the view to test
ValueType init_value, BinaryOp bop, UnaryOp uop) {
//! always careful because views might not be deep copyable
auto data_view_dc = create_deep_copyable_compatible_clone(data_view);
auto data_view_h =
create_mirror_view_and_copy(Kokkos::HostSpace(), data_view_dc);
using gold_view_value_type = typename ViewType2::value_type;
Kokkos::View<gold_view_value_type*, Kokkos::HostSpace> gold_h(
"goldh", data_view.extent(0));
my_host_transform_exclusive_scan(KE::cbegin(data_view_h),
KE::cend(data_view_h), KE::begin(gold_h),
init_value, bop, uop);
auto test_view_dc = create_deep_copyable_compatible_clone(test_view);
auto test_view_h =
create_mirror_view_and_copy(Kokkos::HostSpace(), test_view_dc);
if (test_view_h.extent(0) > 0) {
for (std::size_t i = 0; i < test_view_h.extent(0); ++i) {
// std::cout << i << " " << std::setprecision(15) << data_view_h(i) << " "
// << gold_h(i) << " " << test_view_h(i) << " "
// << std::abs(gold_h(i) - test_view_h(i)) << std::endl;
if (std::is_same<gold_view_value_type, int>::value) {
EXPECT_TRUE(gold_h(i) == test_view_h(i));
} else {
const auto error = std::abs(gold_h(i) - test_view_h(i));
if (error > 1e-10) {
std::cout << i << " " << std::setprecision(15) << data_view_h(i)
<< " " << gold_h(i) << " " << test_view_h(i) << " "
<< std::abs(gold_h(i) - test_view_h(i)) << std::endl;
}
EXPECT_TRUE(error < 1e-10);
}
}
// std::cout << " last el: " << test_view_h(test_view_h.extent(0)-1) <<
// std::endl;
}
}
template <class ValueType>
struct TimesTwoUnaryFunctor {
KOKKOS_INLINE_FUNCTION
ValueType operator()(const ValueType& a) const { return (a * ValueType(2)); }
};
template <class ValueType>
struct SumBinaryFunctor {
KOKKOS_INLINE_FUNCTION
ValueType operator()(const ValueType& a, const ValueType& b) const {
return (a + b);
}
KOKKOS_INLINE_FUNCTION
ValueType operator()(const volatile ValueType& a,
const volatile ValueType& b) const {
return (a + b);
}
};
std::string value_type_to_string(int) { return "int"; }
std::string value_type_to_string(double) { return "double"; }
template <class Tag, class ValueType, class InfoType, class BinaryOp,
class UnaryOp>
void run_single_scenario(const InfoType& scenario_info, ValueType init_value,
BinaryOp bop, UnaryOp uop) {
const auto name = std::get<0>(scenario_info);
const std::size_t view_ext = std::get<1>(scenario_info);
// std::cout << "transform_exclusive_scan custom op: " << name << ", "
// << view_tag_to_string(Tag{}) << ", "
// << value_type_to_string(ValueType()) << ", "
// << "init = " << init_value << std::endl;
auto view_dest =
create_view<ValueType>(Tag{}, view_ext, "transform_exclusive_scan");
auto view_from =
create_view<ValueType>(Tag{}, view_ext, "transform_exclusive_scan");
fill_view(view_from, name);
{
fill_zero(view_dest);
auto r = KE::transform_exclusive_scan(
exespace(), KE::cbegin(view_from), KE::cend(view_from),
KE::begin(view_dest), init_value, bop, uop);
EXPECT_TRUE(r == KE::end(view_dest));
verify_data(view_from, view_dest, init_value, bop, uop);
}
{
fill_zero(view_dest);
auto r = KE::transform_exclusive_scan(
"label", exespace(), KE::cbegin(view_from), KE::cend(view_from),
KE::begin(view_dest), init_value, bop, uop);
EXPECT_TRUE(r == KE::end(view_dest));
verify_data(view_from, view_dest, init_value, bop, uop);
}
{
fill_zero(view_dest);
auto r = KE::transform_exclusive_scan(exespace(), view_from, view_dest,
init_value, bop, uop);
EXPECT_TRUE(r == KE::end(view_dest));
verify_data(view_from, view_dest, init_value, bop, uop);
}
{
fill_zero(view_dest);
auto r = KE::transform_exclusive_scan("label", exespace(), view_from,
view_dest, init_value, bop, uop);
EXPECT_TRUE(r == KE::end(view_dest));
verify_data(view_from, view_dest, init_value, bop, uop);
}
Kokkos::fence();
}
template <class Tag, class ValueType>
void run_all_scenarios() {
const std::map<std::string, std::size_t> scenarios = {
{"empty", 0}, {"one-element", 1}, {"two-elements-a", 2},
{"two-elements-b", 2}, {"small-a", 9}, {"small-b", 13},
{"medium", 1103}, {"large", 10513}};
for (const auto& it : scenarios) {
using uop_t = TimesTwoUnaryFunctor<ValueType>;
using bop_t = SumBinaryFunctor<ValueType>;
run_single_scenario<Tag, ValueType>(it, ValueType{0}, bop_t(), uop_t());
run_single_scenario<Tag, ValueType>(it, ValueType{1}, bop_t(), uop_t());
run_single_scenario<Tag, ValueType>(it, ValueType{-2}, bop_t(), uop_t());
run_single_scenario<Tag, ValueType>(it, ValueType{3}, bop_t(), uop_t());
}
}
#if not defined KOKKOS_ENABLE_OPENMPTARGET
TEST(std_algorithms_numeric_ops_test, transform_exclusive_scan) {
run_all_scenarios<DynamicTag, double>();
run_all_scenarios<StridedThreeTag, double>();
run_all_scenarios<DynamicTag, int>();
run_all_scenarios<StridedThreeTag, int>();
}
#endif
} // namespace TransformEScan
} // namespace stdalgos
} // namespace Test

View File

@ -0,0 +1,347 @@
/*
//@HEADER
// ************************************************************************
//
// Kokkos v. 3.0
// Copyright (2020) 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.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the Corporation nor the names of the
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Questions? Contact Christian R. Trott (crtrott@sandia.gov)
//
// ************************************************************************
//@HEADER
*/
#include <TestStdAlgorithmsCommon.hpp>
#include <std_algorithms/Kokkos_BeginEnd.hpp>
#include <std_algorithms/Kokkos_Numeric.hpp>
#include <utility>
namespace Test {
namespace stdalgos {
namespace TransformIncScan {
namespace KE = Kokkos::Experimental;
template <class ValueType>
struct UnifDist;
template <>
struct UnifDist<double> {
using dist_type = std::uniform_real_distribution<double>;
std::mt19937 m_gen;
dist_type m_dist;
UnifDist() : m_dist(0.05, 1.2) { m_gen.seed(1034343); }
double operator()() { return m_dist(m_gen); }
};
template <>
struct UnifDist<int> {
using dist_type = std::uniform_int_distribution<int>;
std::mt19937 m_gen;
dist_type m_dist;
UnifDist() : m_dist(1, 3) { m_gen.seed(1034343); }
int operator()() { return m_dist(m_gen); }
};
template <class ViewType>
void fill_zero(ViewType view) {
Kokkos::parallel_for(view.extent(0), FillZeroFunctor<ViewType>(view));
}
template <class ViewType>
void fill_view(ViewType dest_view, const std::string& name) {
using value_type = typename ViewType::value_type;
using exe_space = typename ViewType::execution_space;
const std::size_t ext = dest_view.extent(0);
using aux_view_t = Kokkos::View<value_type*, exe_space>;
aux_view_t aux_view("aux_view", ext);
auto v_h = create_mirror_view(Kokkos::HostSpace(), aux_view);
UnifDist<value_type> randObj;
if (name == "empty") {
// no op
}
else if (name == "one-element") {
assert(v_h.extent(0) == 1);
v_h(0) = static_cast<value_type>(1);
}
else if (name == "two-elements-a") {
assert(v_h.extent(0) == 2);
v_h(0) = static_cast<value_type>(1);
v_h(1) = static_cast<value_type>(2);
}
else if (name == "two-elements-b") {
assert(v_h.extent(0) == 2);
v_h(0) = static_cast<value_type>(2);
v_h(1) = static_cast<value_type>(-1);
}
else if (name == "small-a") {
assert(v_h.extent(0) == 9);
v_h(0) = static_cast<value_type>(3);
v_h(1) = static_cast<value_type>(1);
v_h(2) = static_cast<value_type>(4);
v_h(3) = static_cast<value_type>(1);
v_h(4) = static_cast<value_type>(5);
v_h(5) = static_cast<value_type>(9);
v_h(6) = static_cast<value_type>(2);
v_h(7) = static_cast<value_type>(6);
v_h(8) = static_cast<value_type>(2);
}
else if (name == "small-b") {
assert(v_h.extent(0) >= 6);
for (std::size_t i = 0; i < ext; ++i) {
v_h(i) = randObj();
}
v_h(5) = static_cast<value_type>(-2);
}
else if (name == "medium" || name == "large") {
for (std::size_t i = 0; i < ext; ++i) {
v_h(i) = randObj();
}
}
else {
throw std::runtime_error("invalid choice");
}
Kokkos::deep_copy(aux_view, v_h);
CopyFunctor<aux_view_t, ViewType> F1(aux_view, dest_view);
Kokkos::parallel_for("copy", dest_view.extent(0), F1);
}
// I had to write my own because std::transform_inclusive_scan is ONLY found
// with std=c++17
template <class it1, class it2, class BopType, class UopType>
void my_host_transform_inclusive_scan(it1 first, it1 last, it2 dest,
BopType bop, UopType uop) {
if (first != last) {
auto init = uop(*first);
*dest = init;
while (++first < last) {
init = bop(uop(*first), init);
*(++dest) = init;
}
}
}
template <class it1, class it2, class ValType, class BopType, class UopType>
void my_host_transform_inclusive_scan(it1 first, it1 last, it2 dest,
BopType bop, UopType uop, ValType init) {
if (first != last) {
init = bop(uop(*first), init);
*dest = init;
while (++first < last) {
init = bop(uop(*first), init);
*(++dest) = init;
}
}
}
template <class ViewType1, class ViewType2, class... Args>
void verify_data(ViewType1 data_view, // contains data
ViewType2 test_view, // the view to test
Args... args /* by value on purpose*/) {
//! always careful because views might not be deep copyable
auto data_view_dc = create_deep_copyable_compatible_clone(data_view);
auto data_view_h =
create_mirror_view_and_copy(Kokkos::HostSpace(), data_view_dc);
using gold_view_value_type = typename ViewType2::value_type;
Kokkos::View<gold_view_value_type*, Kokkos::HostSpace> gold_h(
"goldh", data_view.extent(0));
my_host_transform_inclusive_scan(KE::cbegin(data_view_h),
KE::cend(data_view_h), KE::begin(gold_h),
args...);
auto test_view_dc = create_deep_copyable_compatible_clone(test_view);
auto test_view_h =
create_mirror_view_and_copy(Kokkos::HostSpace(), test_view_dc);
if (test_view_h.extent(0) > 0) {
for (std::size_t i = 0; i < test_view_h.extent(0); ++i) {
// std::cout << i << " " << std::setprecision(15) << data_view_h(i) << " "
// << gold_h(i) << " " << test_view_h(i) << " "
// << std::abs(gold_h(i) - test_view_h(i)) << std::endl;
if (std::is_same<gold_view_value_type, int>::value) {
EXPECT_TRUE(gold_h(i) == test_view_h(i));
} else {
const auto error = std::abs(gold_h(i) - test_view_h(i));
if (error > 1e-10) {
std::cout << i << " " << std::setprecision(15) << data_view_h(i)
<< " " << gold_h(i) << " " << test_view_h(i) << " "
<< std::abs(gold_h(i) - test_view_h(i)) << std::endl;
}
EXPECT_TRUE(error < 1e-10);
}
}
// std::cout << " last el: " << test_view_h(test_view_h.extent(0)-1) <<
// std::endl;
}
}
template <class ValueType>
struct TimesTwoUnaryFunctor {
KOKKOS_INLINE_FUNCTION
ValueType operator()(const ValueType& a) const { return (a * ValueType(2)); }
};
template <class ValueType>
struct SumBinaryFunctor {
KOKKOS_INLINE_FUNCTION
ValueType operator()(const ValueType& a, const ValueType& b) const {
return (a + b);
}
KOKKOS_INLINE_FUNCTION
ValueType operator()(const volatile ValueType& a,
const volatile ValueType& b) const {
return (a + b);
}
};
std::string value_type_to_string(int) { return "int"; }
std::string value_type_to_string(double) { return "double"; }
template <class Tag, class BopT, class UopT>
void print_scenario_details(const std::string& name, BopT bop, UopT uop) {
(void)bop;
(void)uop;
std::cout << "transform_inclusive_scan: " << name << ", "
<< view_tag_to_string(Tag{}) << std::endl;
}
template <class Tag, class BopT, class UopT, class ValueType>
void print_scenario_details(const std::string& name, BopT bop, UopT uop,
ValueType init_value) {
(void)bop;
(void)uop;
std::cout << "transform_inclusive_scan: " << name << ", "
<< view_tag_to_string(Tag{}) << ", "
<< "init = " << init_value << std::endl;
}
template <class Tag, class ValueType, class InfoType, class... Args>
void run_single_scenario(const InfoType& scenario_info,
Args... args /* by value on purpose*/) {
const auto name = std::get<0>(scenario_info);
const std::size_t view_ext = std::get<1>(scenario_info);
// print_scenario_details<Tag>(name, args...);
auto view_dest =
create_view<ValueType>(Tag{}, view_ext, "transform_inclusive_scan");
auto view_from =
create_view<ValueType>(Tag{}, view_ext, "transform_inclusive_scan");
fill_view(view_from, name);
{
fill_zero(view_dest);
auto r = KE::transform_inclusive_scan(exespace(), KE::cbegin(view_from),
KE::cend(view_from),
KE::begin(view_dest), args...);
EXPECT_TRUE(r == KE::end(view_dest));
verify_data(view_from, view_dest, args...);
}
{
fill_zero(view_dest);
auto r = KE::transform_inclusive_scan(
"label", exespace(), KE::cbegin(view_from), KE::cend(view_from),
KE::begin(view_dest), args...);
EXPECT_TRUE(r == KE::end(view_dest));
verify_data(view_from, view_dest, args...);
}
{
fill_zero(view_dest);
auto r =
KE::transform_inclusive_scan(exespace(), view_from, view_dest, args...);
EXPECT_TRUE(r == KE::end(view_dest));
verify_data(view_from, view_dest, args...);
}
{
fill_zero(view_dest);
auto r = KE::transform_inclusive_scan("label", exespace(), view_from,
view_dest, args...);
EXPECT_TRUE(r == KE::end(view_dest));
verify_data(view_from, view_dest, args...);
}
Kokkos::fence();
}
template <class Tag, class ValueType>
void run_all_scenarios() {
const std::map<std::string, std::size_t> scenarios = {
{"empty", 0}, {"one-element", 1}, {"two-elements-a", 2},
{"two-elements-b", 2}, {"small-a", 9}, {"small-b", 13},
{"medium", 1103}, {"large", 10513}};
for (const auto& it : scenarios) {
using uop_t = TimesTwoUnaryFunctor<ValueType>;
using bop_t = SumBinaryFunctor<ValueType>;
run_single_scenario<Tag, ValueType>(it, bop_t(), uop_t());
run_single_scenario<Tag, ValueType>(it, bop_t(), uop_t(), ValueType{0});
run_single_scenario<Tag, ValueType>(it, bop_t(), uop_t(), ValueType{1});
run_single_scenario<Tag, ValueType>(it, bop_t(), uop_t(), ValueType{2});
run_single_scenario<Tag, ValueType>(it, bop_t(), uop_t(), ValueType{-1});
run_single_scenario<Tag, ValueType>(it, bop_t(), uop_t(), ValueType{-2});
}
}
#if not defined KOKKOS_ENABLE_OPENMPTARGET
TEST(std_algorithms_numeric_ops_test, transform_inclusive_scan) {
run_all_scenarios<DynamicTag, double>();
// run_all_scenarios<StridedThreeTag, double>();
// run_all_scenarios<DynamicTag, int>();
// run_all_scenarios<StridedThreeTag, int>();
}
#endif
} // namespace TransformIncScan
} // namespace stdalgos
} // namespace Test

View File

@ -0,0 +1,174 @@
/*
//@HEADER
// ************************************************************************
//
// Kokkos v. 3.0
// Copyright (2020) 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.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the Corporation nor the names of the
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Questions? Contact Christian R. Trott (crtrott@sandia.gov)
//
// ************************************************************************
//@HEADER
*/
#include <TestStdAlgorithmsCommon.hpp>
#include <std_algorithms/Kokkos_BeginEnd.hpp>
#include <std_algorithms/Kokkos_ModifyingSequenceOperations.hpp>
#include <utility>
namespace Test {
namespace stdalgos {
namespace TransformUnaryOp {
namespace KE = Kokkos::Experimental;
std::string value_type_to_string(int) { return "int"; }
std::string value_type_to_string(double) { return "double"; }
template <class ViewType>
void fill_view(ViewType dest_view) {
using value_type = typename ViewType::value_type;
using exe_space = typename ViewType::execution_space;
const std::size_t ext = dest_view.extent(0);
using aux_view_t = Kokkos::View<value_type*, exe_space>;
aux_view_t aux_view("aux_view", ext);
auto v_h = create_mirror_view(Kokkos::HostSpace(), aux_view);
for (std::size_t i = 0; i < ext; ++i) {
v_h(i) = static_cast<value_type>(i);
}
Kokkos::deep_copy(aux_view, v_h);
CopyFunctor<aux_view_t, ViewType> F1(aux_view, dest_view);
Kokkos::parallel_for("copy", dest_view.extent(0), F1);
}
template <class ViewTypeFrom, class ViewTypeTest>
void verify_data(ViewTypeFrom view_from, ViewTypeTest view_test) {
using value_type = typename ViewTypeFrom::value_type;
//! always careful because views might not be deep copyable
auto view_test_dc = create_deep_copyable_compatible_clone(view_test);
auto view_test_h =
create_mirror_view_and_copy(Kokkos::HostSpace(), view_test_dc);
auto view_from_dc = create_deep_copyable_compatible_clone(view_from);
auto view_from_h =
create_mirror_view_and_copy(Kokkos::HostSpace(), view_from_dc);
for (std::size_t i = 0; i < view_test_h.extent(0); ++i) {
EXPECT_TRUE(view_test_h(i) == view_from_h(i) + value_type(1));
}
}
template <class ValueType>
struct TransformFunctor {
KOKKOS_INLINE_FUNCTION
ValueType operator()(const ValueType& val) const {
return val + ValueType(1);
}
};
template <class Tag, class ValueType, class InfoType>
void run_single_scenario(const InfoType& scenario_info) {
const auto name = std::get<0>(scenario_info);
const std::size_t view_ext = std::get<1>(scenario_info);
// std::cout << "transform_unary_op: " << name << ", "
// << view_tag_to_string(Tag{}) << ", "
// << value_type_to_string(ValueType()) << std::endl;
auto view_from =
create_view<ValueType>(Tag{}, view_ext, "transform_uop_from");
fill_view(view_from);
TransformFunctor<ValueType> unOp;
{
auto view_dest =
create_view<ValueType>(Tag{}, view_ext, "transform_uop_dest");
auto r1 = KE::transform(exespace(), KE::begin(view_from),
KE::end(view_from), KE::begin(view_dest), unOp);
verify_data(view_from, view_dest);
EXPECT_EQ(r1, KE::end(view_dest));
}
{
auto view_dest =
create_view<ValueType>(Tag{}, view_ext, "transform_uop_dest");
auto r1 = KE::transform("label", exespace(), KE::begin(view_from),
KE::end(view_from), KE::begin(view_dest), unOp);
verify_data(view_from, view_dest);
EXPECT_EQ(r1, KE::end(view_dest));
}
{
auto view_dest =
create_view<ValueType>(Tag{}, view_ext, "transform_uop_dest");
auto r1 = KE::transform(exespace(), view_from, view_dest, unOp);
verify_data(view_from, view_dest);
EXPECT_EQ(r1, KE::end(view_dest));
}
{
auto view_dest =
create_view<ValueType>(Tag{}, view_ext, "transform_uop_dest");
auto r1 = KE::transform("label", exespace(), view_from, view_dest, unOp);
verify_data(view_from, view_dest);
EXPECT_EQ(r1, KE::end(view_dest));
}
Kokkos::fence();
}
template <class Tag, class ValueType>
void run_all_scenarios() {
const std::map<std::string, std::size_t> scenarios = {
{"empty", 0}, {"one-element-a", 1}, {"one-element-b", 1},
{"two-elements-a", 2}, {"two-elements-b", 2}, {"small-a", 9},
{"small-b", 13}, {"medium", 1103}, {"large", 101513}};
for (const auto& it : scenarios) {
run_single_scenario<Tag, ValueType>(it);
}
}
TEST(std_algorithms_transform_ops_test, transform_unary_op) {
run_all_scenarios<DynamicTag, int>();
run_all_scenarios<StridedThreeTag, int>();
run_all_scenarios<DynamicTag, double>();
run_all_scenarios<StridedThreeTag, double>();
}
} // namespace TransformUnaryOp
} // namespace stdalgos
} // namespace Test

View File

@ -0,0 +1,312 @@
/*
//@HEADER
// ************************************************************************
//
// Kokkos v. 3.0
// Copyright (2020) 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.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the Corporation nor the names of the
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Questions? Contact Christian R. Trott (crtrott@sandia.gov)
//
// ************************************************************************
//@HEADER
*/
#include <TestStdAlgorithmsCommon.hpp>
#include <std_algorithms/Kokkos_BeginEnd.hpp>
#include <std_algorithms/Kokkos_ModifyingSequenceOperations.hpp>
#include <utility>
#include <algorithm>
namespace Test {
namespace stdalgos {
namespace Unique {
namespace KE = Kokkos::Experimental;
template <class ValueType>
struct UnifDist;
template <>
struct UnifDist<int> {
using dist_type = std::uniform_int_distribution<int>;
std::mt19937 m_gen;
dist_type m_dist;
UnifDist() : m_dist(2, 7) { m_gen.seed(1034343); }
int operator()() { return m_dist(m_gen); }
};
template <class ViewType>
void fill_view(ViewType dest_view, const std::string& name) {
using value_type = typename ViewType::value_type;
using exe_space = typename ViewType::execution_space;
const std::size_t ext = dest_view.extent(0);
using aux_view_t = Kokkos::View<value_type*, exe_space>;
aux_view_t aux_view("aux_view", ext);
auto v_h = create_mirror_view(Kokkos::HostSpace(), aux_view);
if (name == "empty") {
// no op
}
else if (name == "one-element-a") {
v_h(0) = static_cast<value_type>(1);
}
else if (name == "one-element-b") {
v_h(0) = static_cast<value_type>(2);
}
else if (name == "two-elements-a") {
v_h(0) = static_cast<value_type>(1);
v_h(1) = static_cast<value_type>(2);
}
else if (name == "two-elements-b") {
v_h(0) = static_cast<value_type>(2);
v_h(1) = static_cast<value_type>(-1);
}
else if (name == "small-a") {
v_h(0) = static_cast<value_type>(0);
v_h(1) = static_cast<value_type>(1);
v_h(2) = static_cast<value_type>(3);
v_h(3) = static_cast<value_type>(2);
v_h(4) = static_cast<value_type>(2);
v_h(5) = static_cast<value_type>(4);
v_h(6) = static_cast<value_type>(4);
v_h(7) = static_cast<value_type>(4);
v_h(8) = static_cast<value_type>(5);
v_h(9) = static_cast<value_type>(6);
v_h(10) = static_cast<value_type>(6);
}
else if (name == "small-b") {
v_h(0) = static_cast<value_type>(1);
v_h(1) = static_cast<value_type>(1);
v_h(2) = static_cast<value_type>(1);
v_h(3) = static_cast<value_type>(2);
v_h(4) = static_cast<value_type>(3);
v_h(5) = static_cast<value_type>(4);
v_h(6) = static_cast<value_type>(4);
v_h(7) = static_cast<value_type>(4);
v_h(8) = static_cast<value_type>(5);
v_h(9) = static_cast<value_type>(6);
v_h(10) = static_cast<value_type>(8);
v_h(11) = static_cast<value_type>(9);
v_h(12) = static_cast<value_type>(8);
}
else if (name == "medium-a") {
// beginning just contains increasing values
for (std::size_t i = 0; i < 1000; ++i) {
v_h(i) = static_cast<value_type>(i);
}
// then use random
UnifDist<value_type> randObj;
for (std::size_t i = 1000; i < ext; ++i) {
v_h(i) = randObj();
}
}
else if (name == "medium-b") {
for (std::size_t i = 0; i < 1000; ++i) {
v_h(i) = static_cast<value_type>(22);
}
for (std::size_t i = 1000; i < ext; ++i) {
v_h(i) = static_cast<value_type>(44);
}
}
else if (name == "large-a") {
// put equal elements at the end
for (std::size_t i = 0; i < ext; ++i) {
v_h(i) = static_cast<value_type>(i);
}
v_h(ext - 3) = static_cast<value_type>(44);
v_h(ext - 2) = static_cast<value_type>(44);
v_h(ext - 1) = static_cast<value_type>(44);
}
else if (name == "large-b") {
UnifDist<value_type> randObj;
for (std::size_t i = 0; i < ext; ++i) {
v_h(i) = randObj();
}
}
else {
throw std::runtime_error("invalid choice");
}
Kokkos::deep_copy(aux_view, v_h);
CopyFunctor<aux_view_t, ViewType> F1(aux_view, dest_view);
Kokkos::parallel_for("copy", dest_view.extent(0), F1);
}
template <class ResultIt, class ViewType1, class ViewType2, class... Args>
void verify_data(const std::string& name, ResultIt my_result_it,
ViewType1 view_test, ViewType2 data_v_h, Args... args) {
// run std unique on host data
auto std_r = std::unique(KE::begin(data_v_h), KE::end(data_v_h), args...);
//
// check the returned iterator is correct
//
const auto std_diff = (std::size_t)(std_r - KE::begin(data_v_h));
const auto my_diff = (std::size_t)(my_result_it - KE::begin(view_test));
EXPECT_TRUE(my_diff == std_diff);
//
// check the data in the view
//
// Note that we need to stop after std_diff because
// after that values are unspecified, see std::unique
auto view_test_h = create_host_space_copy(view_test);
for (std::size_t i = 0; i < std_diff; ++i) {
// std::cout << "i = " << i
// << " my = " << view_test_h(i) << " "
// << " std = " << data_v_h(i)
// << '\n';
EXPECT_TRUE(view_test_h(i) == data_v_h(i));
}
if (name == "medium-b") {
using value_type = typename ViewType1::value_type;
EXPECT_TRUE(my_diff == (std::size_t)2);
EXPECT_TRUE(view_test_h(0) == (value_type)22);
EXPECT_TRUE(view_test_h(1) == (value_type)44);
}
}
std::string value_type_to_string(int) { return "int"; }
std::string value_type_to_string(double) { return "double"; }
template <class Tag, class ValueType>
void print_scenario_details(const std::string& name) {
std::cout << "unique: default predicate: " << name << ", "
<< view_tag_to_string(Tag{}) << " "
<< value_type_to_string(ValueType()) << '\n';
}
template <class Tag, class ValueType, class Predicate>
void print_scenario_details(const std::string& name, Predicate pred) {
(void)pred;
std::cout << "unique: custom predicate: " << name << ", "
<< view_tag_to_string(Tag{}) << " "
<< value_type_to_string(ValueType()) << '\n';
}
template <class Tag, class ValueType, class InfoType, class... Args>
void run_single_scenario(const InfoType& scenario_info, Args... args) {
const auto name = std::get<0>(scenario_info);
const std::size_t view_ext = std::get<1>(scenario_info);
// print_scenario_details<Tag, ValueType>(name, args...);
auto test_view = create_view<ValueType>(Tag{}, view_ext, "unique_test_view");
{
fill_view(test_view, name);
// make host copy BEFORE running unique on it since unique modifies it
auto data_h = create_host_space_copy(test_view);
// run unique
auto rit = KE::unique(exespace(), KE::begin(test_view), KE::end(test_view),
args...);
// verify
verify_data(name, rit, test_view, data_h, args...);
}
{
fill_view(test_view, name);
// make host copy BEFORE running unique on it since unique modifies it
auto data_h = create_host_space_copy(test_view);
// run unique
auto rit = KE::unique("label", exespace(), KE::begin(test_view),
KE::end(test_view), args...);
// verify
verify_data(name, rit, test_view, data_h, args...);
}
{
fill_view(test_view, name);
// make host copy BEFORE running unique on it since unique modifies it
auto data_h = create_host_space_copy(test_view);
// run unique
auto rit = KE::unique(exespace(), test_view, args...);
// verify
verify_data(name, rit, test_view, data_h, args...);
}
{
fill_view(test_view, name);
// make host copy BEFORE running unique on it since unique modifies it
auto data_h = create_host_space_copy(test_view);
// run unique
auto rit = KE::unique("label", exespace(), test_view, args...);
// verify
verify_data(name, rit, test_view, data_h, args...);
}
Kokkos::fence();
}
template <class Tag, class ValueType>
void run_all_scenarios() {
const std::map<std::string, std::size_t> scenarios = {
{"empty", 0}, {"one-element-a", 1}, {"one-element-b", 1},
{"two-elements-a", 2}, {"two-elements-b", 2}, {"small-a", 11},
{"small-b", 13}, {"medium-a", 11103}, {"medium-b", 21103},
{"large-a", 101513}, {"large-b", 100111}};
for (const auto& it : scenarios) {
run_single_scenario<Tag, ValueType>(it);
using func_t = IsEqualFunctor<ValueType>;
run_single_scenario<Tag, ValueType>(it, func_t());
}
}
TEST(std_algorithms_mod_seq_ops, unique) {
run_all_scenarios<DynamicTag, int>();
run_all_scenarios<StridedThreeTag, int>();
}
} // namespace Unique
} // namespace stdalgos
} // namespace Test

View File

@ -0,0 +1,361 @@
/*
//@HEADER
// ************************************************************************
//
// Kokkos v. 3.0
// Copyright (2020) 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.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the Corporation nor the names of the
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Questions? Contact Christian R. Trott (crtrott@sandia.gov)
//
// ************************************************************************
//@HEADER
*/
#include <TestStdAlgorithmsCommon.hpp>
#include <std_algorithms/Kokkos_BeginEnd.hpp>
#include <std_algorithms/Kokkos_ModifyingSequenceOperations.hpp>
#include <utility>
namespace Test {
namespace stdalgos {
namespace UniqueCopy {
namespace KE = Kokkos::Experimental;
// impl is here for std because it is only avail from c++>=17
template <class InputIterator, class OutputIterator, class BinaryPredicate>
auto my_unique_copy(InputIterator first, InputIterator last,
OutputIterator result, BinaryPredicate pred) {
if (first != last) {
typename OutputIterator::value_type t(*first);
*result = t;
++result;
while (++first != last) {
if (!pred(t, *first)) {
t = *first;
*result = t;
++result;
}
}
}
return result;
}
template <class InputIterator, class OutputIterator>
auto my_unique_copy(InputIterator first, InputIterator last,
OutputIterator result) {
using value_type = typename OutputIterator::value_type;
using func_t = IsEqualFunctor<value_type>;
return my_unique_copy(first, last, result, func_t());
}
template <class ValueType>
struct UnifDist;
template <>
struct UnifDist<int> {
using dist_type = std::uniform_int_distribution<int>;
std::mt19937 m_gen;
dist_type m_dist;
UnifDist() : m_dist(2, 7) { m_gen.seed(1034343); }
int operator()() { return m_dist(m_gen); }
};
template <class ViewType>
std::size_t fill_view(ViewType dest_view, const std::string& name) {
using value_type = typename ViewType::value_type;
using exe_space = typename ViewType::execution_space;
const std::size_t ext = dest_view.extent(0);
using aux_view_t = Kokkos::View<value_type*, exe_space>;
aux_view_t aux_view("aux_view", ext);
auto v_h = create_mirror_view(Kokkos::HostSpace(), aux_view);
std::size_t count = 0;
if (name == "empty") {
// no op
}
else if (name == "one-element-a") {
v_h(0) = static_cast<value_type>(1);
count = 1;
}
else if (name == "one-element-b") {
v_h(0) = static_cast<value_type>(2);
count = 1;
}
else if (name == "two-elements-a") {
v_h(0) = static_cast<value_type>(1);
v_h(1) = static_cast<value_type>(2);
count = 2;
}
else if (name == "two-elements-b") {
v_h(0) = static_cast<value_type>(2);
v_h(1) = static_cast<value_type>(-1);
count = 2;
}
else if (name == "small-a") {
v_h(0) = static_cast<value_type>(0);
v_h(1) = static_cast<value_type>(1);
v_h(2) = static_cast<value_type>(1);
v_h(3) = static_cast<value_type>(2);
v_h(4) = static_cast<value_type>(3);
v_h(5) = static_cast<value_type>(4);
v_h(6) = static_cast<value_type>(4);
v_h(7) = static_cast<value_type>(4);
v_h(8) = static_cast<value_type>(5);
v_h(9) = static_cast<value_type>(6);
v_h(10) = static_cast<value_type>(6);
count = 7;
}
else if (name == "small-b") {
v_h(0) = static_cast<value_type>(1);
v_h(1) = static_cast<value_type>(1);
v_h(2) = static_cast<value_type>(1);
v_h(3) = static_cast<value_type>(2);
v_h(4) = static_cast<value_type>(3);
v_h(5) = static_cast<value_type>(4);
v_h(6) = static_cast<value_type>(4);
v_h(7) = static_cast<value_type>(4);
v_h(8) = static_cast<value_type>(5);
v_h(9) = static_cast<value_type>(6);
v_h(10) = static_cast<value_type>(8);
v_h(11) = static_cast<value_type>(9);
v_h(12) = static_cast<value_type>(8);
count = 9;
}
else if (name == "medium" || name == "large") {
UnifDist<value_type> randObj;
for (std::size_t i = 0; i < ext; ++i) {
v_h(i) = randObj();
}
std::vector<value_type> tmp(v_h.extent(0));
std::fill(tmp.begin(), tmp.end(), static_cast<value_type>(0));
using func_t = IsEqualFunctor<value_type>;
auto std_r =
my_unique_copy(KE::cbegin(v_h), KE::cend(v_h), tmp.begin(), func_t());
count = (std::size_t)(std_r - tmp.begin());
}
else {
throw std::runtime_error("invalid choice");
}
Kokkos::deep_copy(aux_view, v_h);
CopyFunctor<aux_view_t, ViewType> F1(aux_view, dest_view);
Kokkos::parallel_for("copy", dest_view.extent(0), F1);
return count;
}
template <class ViewTypeFrom, class ViewTypeTest, class... Args>
void verify_data(const std::string& name, ViewTypeFrom view_from,
ViewTypeTest view_test, Args... args) {
using value_type = typename ViewTypeTest::value_type;
//! always careful because views might not be deep copyable
auto view_test_dc = create_deep_copyable_compatible_clone(view_test);
auto view_test_h =
create_mirror_view_and_copy(Kokkos::HostSpace(), view_test_dc);
auto view_from_dc = create_deep_copyable_compatible_clone(view_from);
auto view_from_h =
create_mirror_view_and_copy(Kokkos::HostSpace(), view_from_dc);
if (name == "empty") {
// no op
}
else if (name == "one-element-a") {
EXPECT_TRUE(view_test_h(0) == static_cast<value_type>(1));
}
else if (name == "one-element-b") {
EXPECT_TRUE(view_test_h(0) == static_cast<value_type>(2));
}
else if (name == "two-elements-a") {
EXPECT_TRUE(view_test_h(0) == static_cast<value_type>(1));
EXPECT_TRUE(view_test_h(1) == static_cast<value_type>(2));
}
else if (name == "two-elements-b") {
EXPECT_TRUE(view_test_h(0) == static_cast<value_type>(2));
EXPECT_TRUE(view_test_h(1) == static_cast<value_type>(-1));
}
else if (name == "small-a") {
EXPECT_TRUE(view_test_h(0) == static_cast<value_type>(0));
EXPECT_TRUE(view_test_h(1) == static_cast<value_type>(1));
EXPECT_TRUE(view_test_h(2) == static_cast<value_type>(2));
EXPECT_TRUE(view_test_h(3) == static_cast<value_type>(3));
EXPECT_TRUE(view_test_h(4) == static_cast<value_type>(4));
EXPECT_TRUE(view_test_h(5) == static_cast<value_type>(5));
EXPECT_TRUE(view_test_h(6) == static_cast<value_type>(6));
EXPECT_TRUE(view_test_h(7) == static_cast<value_type>(0));
EXPECT_TRUE(view_test_h(8) == static_cast<value_type>(0));
EXPECT_TRUE(view_test_h(9) == static_cast<value_type>(0));
EXPECT_TRUE(view_test_h(10) == static_cast<value_type>(0));
}
else if (name == "small-b") {
EXPECT_TRUE(view_test_h(0) == static_cast<value_type>(1));
EXPECT_TRUE(view_test_h(1) == static_cast<value_type>(2));
EXPECT_TRUE(view_test_h(2) == static_cast<value_type>(3));
EXPECT_TRUE(view_test_h(3) == static_cast<value_type>(4));
EXPECT_TRUE(view_test_h(4) == static_cast<value_type>(5));
EXPECT_TRUE(view_test_h(5) == static_cast<value_type>(6));
EXPECT_TRUE(view_test_h(6) == static_cast<value_type>(8));
EXPECT_TRUE(view_test_h(7) == static_cast<value_type>(9));
EXPECT_TRUE(view_test_h(8) == static_cast<value_type>(8));
EXPECT_TRUE(view_test_h(9) == static_cast<value_type>(0));
EXPECT_TRUE(view_test_h(10) == static_cast<value_type>(0));
EXPECT_TRUE(view_test_h(11) == static_cast<value_type>(0));
EXPECT_TRUE(view_test_h(12) == static_cast<value_type>(0));
}
else if (name == "medium" || name == "large") {
std::vector<value_type> tmp(view_test_h.extent(0));
std::fill(tmp.begin(), tmp.end(), static_cast<value_type>(0));
auto std_r = my_unique_copy(KE::cbegin(view_from_h), KE::cend(view_from_h),
tmp.begin(), args...);
(void)std_r;
for (std::size_t i = 0; i < view_from_h.extent(0); ++i) {
EXPECT_TRUE(view_test_h(i) == tmp[i]);
}
}
else {
throw std::runtime_error("invalid choice");
}
}
std::string value_type_to_string(int) { return "int"; }
std::string value_type_to_string(double) { return "double"; }
template <class Tag, class ValueType>
void print_scenario_details(const std::string& name) {
std::cout << "unique_copy: default predicate: " << name << ", "
<< view_tag_to_string(Tag{}) << " "
<< value_type_to_string(ValueType()) << '\n';
}
template <class Tag, class ValueType, class Predicate>
void print_scenario_details(const std::string& name, Predicate pred) {
(void)pred;
std::cout << "unique_copy: custom predicate: " << name << ", "
<< view_tag_to_string(Tag{}) << " "
<< value_type_to_string(ValueType()) << '\n';
}
template <class Tag, class ValueType, class InfoType, class... Args>
void run_single_scenario(const InfoType& scenario_info, Args... args) {
const auto name = std::get<0>(scenario_info);
const std::size_t view_ext = std::get<1>(scenario_info);
// print_scenario_details<Tag, ValueType>(name, args...);
auto view_from = create_view<ValueType>(Tag{}, view_ext, "unique_copy_from");
auto n = fill_view(view_from, name);
{
auto view_dest =
create_view<ValueType>(Tag{}, view_ext, "unique_copy_dest");
auto rit =
KE::unique_copy(exespace(), KE::cbegin(view_from), KE::cend(view_from),
KE::begin(view_dest), args...);
verify_data(name, view_from, view_dest, args...);
EXPECT_TRUE(rit == (KE::begin(view_dest) + n));
}
{
auto view_dest =
create_view<ValueType>(Tag{}, view_ext, "unique_copy_dest");
auto rit =
KE::unique_copy("label", exespace(), KE::cbegin(view_from),
KE::cend(view_from), KE::begin(view_dest), args...);
verify_data(name, view_from, view_dest, args...);
EXPECT_TRUE(rit == (KE::begin(view_dest) + n));
}
{
auto view_dest =
create_view<ValueType>(Tag{}, view_ext, "unique_copy_dest");
auto rit = KE::unique_copy(exespace(), view_from, view_dest, args...);
verify_data(name, view_from, view_dest, args...);
EXPECT_TRUE(rit == (KE::begin(view_dest) + n));
}
{
auto view_dest =
create_view<ValueType>(Tag{}, view_ext, "unique_copy_dest");
auto rit =
KE::unique_copy("label", exespace(), view_from, view_dest, args...);
verify_data(name, view_from, view_dest, args...);
EXPECT_TRUE(rit == (KE::begin(view_dest) + n));
}
Kokkos::fence();
}
template <class Tag, class ValueType>
void run_all_scenarios() {
const std::map<std::string, std::size_t> scenarios = {
{"empty", 0}, {"one-element-a", 1}, {"one-element-b", 1},
{"two-elements-a", 2}, {"two-elements-b", 2}, {"small-a", 11},
{"small-b", 13}, {"medium", 21103}, {"large", 101513}};
for (const auto& it : scenarios) {
run_single_scenario<Tag, ValueType>(it);
using func_t = IsEqualFunctor<ValueType>;
run_single_scenario<Tag, ValueType>(it, func_t());
}
}
TEST(std_algorithms_mod_seq_ops, unique_copy) {
run_all_scenarios<DynamicTag, int>();
run_all_scenarios<StridedThreeTag, int>();
}
} // namespace UniqueCopy
} // namespace stdalgos
} // namespace Test

View File

@ -0,0 +1,281 @@
/*
//@HEADER
// ************************************************************************
//
// Kokkos v. 3.0
// Copyright (2020) 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.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// 3. Neither the name of the Corporation nor the names of the
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY NTESS "AS IS" AND ANY
// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NTESS OR THE
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
// Questions? Contact Christian R. Trott (crtrott@sandia.gov)
//
// ************************************************************************
//@HEADER
*/
#include <Kokkos_Core.hpp>
#include <gtest/gtest.h>
// purpose of this test is to check that the reducers used
// to implement some std algorithms work independently of the order
namespace Test {
enum class StdReducersTestEnumOrder { LeftToRight, RightToLeft, Random };
std::string order_to_string(StdReducersTestEnumOrder value) {
switch (value) {
case StdReducersTestEnumOrder::LeftToRight: return "LeftToRight";
case StdReducersTestEnumOrder::RightToLeft: return "RightToLeft";
case StdReducersTestEnumOrder::Random: return "Random";
}
return {};
}
auto create_host_view_with_reduction_order_indices(
std::size_t extent, StdReducersTestEnumOrder enum_value) {
using view_t = Kokkos::View<int*, Kokkos::HostSpace>;
view_t result("v", extent);
if (enum_value == StdReducersTestEnumOrder::LeftToRight) {
result(0) = 0;
result(1) = 1;
result(2) = 2;
result(3) = 3;
result(4) = 4;
result(5) = 5;
result(6) = 6;
result(7) = 7;
result(8) = 8;
result(9) = 9;
} else if (enum_value == StdReducersTestEnumOrder::RightToLeft) {
result(0) = 9;
result(1) = 8;
result(2) = 7;
result(3) = 6;
result(4) = 5;
result(5) = 4;
result(6) = 3;
result(7) = 2;
result(8) = 1;
result(9) = 0;
} else if (enum_value == StdReducersTestEnumOrder::Random) {
result(0) = 0;
result(1) = 8;
result(2) = 3;
result(3) = 2;
result(4) = 9;
result(5) = 4;
result(6) = 6;
result(7) = 1;
result(8) = 7;
result(9) = 5;
} else {
throw std::runtime_error("test: Invalid enum");
}
return result;
}
template <int flag, class ExeSpace, class IndexType, class ViewType>
auto run_min_or_max_test(ViewType view, StdReducersTestEnumOrder enValue) {
static_assert(std::is_same<ExeSpace, Kokkos::HostSpace>::value,
"test is only enabled for HostSpace");
std::cout << "checking reduction with order: " << order_to_string(enValue)
<< "\n";
using view_value_type = typename ViewType::value_type;
using reducer_type = typename std::conditional<
(flag == 0), Kokkos::MaxFirstLoc<view_value_type, IndexType, ExeSpace>,
Kokkos::MinFirstLoc<view_value_type, IndexType, ExeSpace> >::type;
using reduction_value_type = typename reducer_type::value_type;
reduction_value_type red_result;
reducer_type reducer(red_result);
EXPECT_TRUE(reducer.references_scalar());
reducer.init(red_result);
auto red_order =
create_host_view_with_reduction_order_indices(view.extent(0), enValue);
for (std::size_t i = 0; i < view.extent(0); ++i) {
const auto index = red_order(i);
reducer.join(red_result, reduction_value_type{view(index), index});
}
using return_type = Kokkos::pair<view_value_type, IndexType>;
return return_type{red_result.val, red_result.loc};
}
TEST(std_algorithms_reducers, max_first_loc) {
using hostspace = Kokkos::HostSpace;
using view_t = Kokkos::View<double*, hostspace>;
constexpr std::size_t extent = 10;
view_t view_h("v", extent);
view_h(0) = 0.;
view_h(1) = 0.;
view_h(2) = 0.;
view_h(3) = 2.;
view_h(4) = 2.;
view_h(5) = 1.;
view_h(6) = 1.;
view_h(7) = 1.;
view_h(8) = 1.;
view_h(9) = 0.;
using index_type = int;
using view_value_type = typename view_t::value_type;
const view_value_type gold_value = 2.;
const index_type gold_location = 3;
const auto pair1 = run_min_or_max_test<0, hostspace, index_type>(
view_h, StdReducersTestEnumOrder::LeftToRight);
ASSERT_EQ(pair1.first, gold_value);
ASSERT_EQ(pair1.second, gold_location);
const auto pair2 = run_min_or_max_test<0, hostspace, index_type>(
view_h, StdReducersTestEnumOrder::RightToLeft);
ASSERT_EQ(pair2.first, gold_value);
ASSERT_EQ(pair2.second, gold_location);
const auto pair3 = run_min_or_max_test<0, hostspace, index_type>(
view_h, StdReducersTestEnumOrder::Random);
ASSERT_EQ(pair3.first, gold_value);
ASSERT_EQ(pair3.second, gold_location);
}
TEST(std_algorithms_reducers, min_first_loc) {
using hostspace = Kokkos::HostSpace;
using view_t = Kokkos::View<double*, hostspace>;
constexpr std::size_t extent = 10;
view_t view_h("v", extent);
view_h(0) = 0.;
view_h(1) = 0.;
view_h(2) = 0.;
view_h(3) = 2.;
view_h(4) = 2.;
view_h(5) = -1.;
view_h(6) = -1.;
view_h(7) = 1.;
view_h(8) = 1.;
view_h(9) = 0.;
using index_type = int;
using view_value_type = typename view_t::value_type;
const view_value_type gold_value = -1.;
const index_type gold_location = 5;
const auto pair1 = run_min_or_max_test<1, hostspace, index_type>(
view_h, StdReducersTestEnumOrder::LeftToRight);
ASSERT_EQ(pair1.first, gold_value);
ASSERT_EQ(pair1.second, gold_location);
const auto pair2 = run_min_or_max_test<1, hostspace, index_type>(
view_h, StdReducersTestEnumOrder::RightToLeft);
ASSERT_EQ(pair2.first, gold_value);
ASSERT_EQ(pair2.second, gold_location);
const auto pair3 = run_min_or_max_test<1, hostspace, index_type>(
view_h, StdReducersTestEnumOrder::Random);
ASSERT_EQ(pair3.first, gold_value);
ASSERT_EQ(pair3.second, gold_location);
}
template <class ExeSpace, class IndexType, class ViewType, class ValuesPair,
class IndexPair>
void run_min_max_test(ViewType view, StdReducersTestEnumOrder enValue,
const ValuesPair gold_values, const IndexPair gold_locs) {
static_assert(std::is_same<ExeSpace, Kokkos::HostSpace>::value,
"test is only enabled for HostSpace");
std::cout << "checking reduction with order: " << order_to_string(enValue)
<< "\n";
using view_value_type = typename ViewType::value_type;
using reducer_type =
Kokkos::MinMaxFirstLastLoc<view_value_type, IndexType, ExeSpace>;
using reduction_value_type = typename reducer_type::value_type;
reduction_value_type red_result;
reducer_type reducer(red_result);
EXPECT_TRUE(reducer.references_scalar());
reducer.init(red_result);
auto red_order =
create_host_view_with_reduction_order_indices(view.extent(0), enValue);
for (std::size_t i = 0; i < view.extent(0); ++i) {
const auto index = red_order(i);
reducer.join(red_result,
reduction_value_type{view(index), view(index), index, index});
}
ASSERT_EQ(red_result.min_val, gold_values.first);
ASSERT_EQ(red_result.max_val, gold_values.second);
ASSERT_EQ(red_result.min_loc, gold_locs.first);
ASSERT_EQ(red_result.max_loc, gold_locs.second);
}
TEST(std_algorithms_reducers, min_max_first_last_loc) {
using hostspace = Kokkos::HostSpace;
using view_t = Kokkos::View<double*, hostspace>;
constexpr std::size_t extent = 10;
view_t view_h("v", extent);
view_h(0) = 0.;
view_h(1) = 0.;
view_h(2) = 0.;
view_h(3) = 2.;
view_h(4) = 2.;
view_h(5) = -1.;
view_h(6) = 1.;
view_h(7) = -1.;
view_h(8) = 2.;
view_h(9) = 0.;
using index_type = int;
using view_value_type = typename view_t::value_type;
Kokkos::pair<view_value_type, view_value_type> gold_values = {-1., 2.};
Kokkos::pair<index_type, index_type> gold_indices = {5, 8};
run_min_max_test<hostspace, index_type>(
view_h, StdReducersTestEnumOrder::LeftToRight, gold_values, gold_indices);
run_min_max_test<hostspace, index_type>(
view_h, StdReducersTestEnumOrder::RightToLeft, gold_values, gold_indices);
run_min_max_test<hostspace, index_type>(
view_h, StdReducersTestEnumOrder::Random, gold_values, gold_indices);
}
} // namespace Test