From ed41874cc80e7b8b38e056ca46b813b38503ea78 Mon Sep 17 00:00:00 2001 From: Kenneth Moreland Date: Tue, 18 Aug 2020 10:33:31 -0600 Subject: [PATCH] Consolidate tests for base vtkm code that is device-specific Some of the code in the base `vtkm` namespace is device specific. For example, the functions in `Math.h` are customized for specific devices. Thus, we want this code to be specially compiled and run on these devices. Previously, we made a header file and then added separate tests to each device package. That was created before we had ways of running on any device. Now, it is much easier to compile the test a single time for all devices and use the `ALL_BACKENDS` feature of `vtkm_unit_tests` CMake function to automatically create the test for all devices. --- vtkm/cont/cuda/testing/CMakeLists.txt | 4 +- .../cuda/testing/UnitTestCudaAlgorithms.cu | 20 - .../cont/cuda/testing/UnitTestCudaGeometry.cu | 21 - ...daMath.cu => UnitTestCudaMathEdgeCases.cu} | 14 +- vtkm/cont/kokkos/testing/CMakeLists.txt | 2 - .../testing/UnitTestKokkosAlgorithms.cxx | 20 - .../kokkos/testing/UnitTestKokkosGeometry.cxx | 21 - vtkm/cont/openmp/testing/CMakeLists.txt | 1 - .../testing/UnitTestOpenMPAlgorithms.cxx | 20 - vtkm/cont/serial/testing/CMakeLists.txt | 1 - .../serial/testing/UnitTestSerialGeometry.cxx | 21 - vtkm/cont/tbb/testing/CMakeLists.txt | 1 - .../tbb/testing/UnitTestTBBAlgorithms.cxx | 20 - vtkm/testing/CMakeLists.txt | 14 +- vtkm/testing/TestingAlgorithms.h | 230 ---- vtkm/testing/TestingMath.h | 1095 ----------------- vtkm/testing/UnitTestAlgorithms.cxx | 154 ++- ...TestingGeometry.h => UnitTestGeometry.cxx} | 34 +- vtkm/testing/UnitTestMath.cxx | 1080 +++++++++++++++- 19 files changed, 1254 insertions(+), 1519 deletions(-) delete mode 100644 vtkm/cont/cuda/testing/UnitTestCudaAlgorithms.cu delete mode 100644 vtkm/cont/cuda/testing/UnitTestCudaGeometry.cu rename vtkm/cont/cuda/testing/{UnitTestCudaMath.cu => UnitTestCudaMathEdgeCases.cu} (94%) delete mode 100644 vtkm/cont/kokkos/testing/UnitTestKokkosAlgorithms.cxx delete mode 100644 vtkm/cont/kokkos/testing/UnitTestKokkosGeometry.cxx delete mode 100644 vtkm/cont/openmp/testing/UnitTestOpenMPAlgorithms.cxx delete mode 100644 vtkm/cont/serial/testing/UnitTestSerialGeometry.cxx delete mode 100644 vtkm/cont/tbb/testing/UnitTestTBBAlgorithms.cxx delete mode 100644 vtkm/testing/TestingAlgorithms.h delete mode 100644 vtkm/testing/TestingMath.h rename vtkm/testing/{TestingGeometry.h => UnitTestGeometry.cxx} (94%) diff --git a/vtkm/cont/cuda/testing/CMakeLists.txt b/vtkm/cont/cuda/testing/CMakeLists.txt index 3123b4552..f2f4874fd 100644 --- a/vtkm/cont/cuda/testing/CMakeLists.txt +++ b/vtkm/cont/cuda/testing/CMakeLists.txt @@ -9,7 +9,6 @@ ##============================================================================ set(unit_tests - UnitTestCudaAlgorithms.cu UnitTestCudaArrayHandle.cu UnitTestCudaArrayHandleFancy.cu UnitTestCudaArrayHandleMultiplexer.cu @@ -23,10 +22,9 @@ set(unit_tests UnitTestCudaDataSetExplicit.cu UnitTestCudaDataSetSingleType.cu UnitTestCudaDeviceAdapter.cu - UnitTestCudaGeometry.cu UnitTestCudaImplicitFunction.cu UnitTestCudaIterators.cu - UnitTestCudaMath.cu + UnitTestCudaMathEdgeCases.cu UnitTestCudaShareUserProvidedManagedMemory.cu UnitTestCudaPointLocatorUniformGrid.cu UnitTestCudaVirtualObjectHandle.cu diff --git a/vtkm/cont/cuda/testing/UnitTestCudaAlgorithms.cu b/vtkm/cont/cuda/testing/UnitTestCudaAlgorithms.cu deleted file mode 100644 index ecda50c3a..000000000 --- a/vtkm/cont/cuda/testing/UnitTestCudaAlgorithms.cu +++ /dev/null @@ -1,20 +0,0 @@ -//============================================================================ -// Copyright (c) Kitware, Inc. -// All rights reserved. -// See LICENSE.txt for details. -// -// This software is distributed WITHOUT ANY WARRANTY; without even -// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR -// PURPOSE. See the above copyright notice for more information. -//============================================================================ - -#include -#include - -#include - -int UnitTestCudaAlgorithms(int argc, char* argv[]) -{ - return vtkm::testing::Testing::Run( - RunAlgorithmsTests, argc, argv); -} diff --git a/vtkm/cont/cuda/testing/UnitTestCudaGeometry.cu b/vtkm/cont/cuda/testing/UnitTestCudaGeometry.cu deleted file mode 100644 index 7089b379f..000000000 --- a/vtkm/cont/cuda/testing/UnitTestCudaGeometry.cu +++ /dev/null @@ -1,21 +0,0 @@ -//============================================================================ -// Copyright (c) Kitware, Inc. -// All rights reserved. -// See LICENSE.txt for details. -// -// This software is distributed WITHOUT ANY WARRANTY; without even -// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR -// PURPOSE. See the above copyright notice for more information. -//============================================================================ - -#include -#include -#include - -int UnitTestCudaGeometry(int argc, char* argv[]) -{ - auto& tracker = vtkm::cont::GetRuntimeDeviceTracker(); - tracker.ForceDevice(vtkm::cont::DeviceAdapterTagCuda{}); - return vtkm::cont::testing::Testing::Run( - UnitTestGeometryNamespace::RunGeometryTests, argc, argv); -} diff --git a/vtkm/cont/cuda/testing/UnitTestCudaMath.cu b/vtkm/cont/cuda/testing/UnitTestCudaMathEdgeCases.cu similarity index 94% rename from vtkm/cont/cuda/testing/UnitTestCudaMath.cu rename to vtkm/cont/cuda/testing/UnitTestCudaMathEdgeCases.cu index dc54d44c8..1129ff515 100644 --- a/vtkm/cont/cuda/testing/UnitTestCudaMath.cu +++ b/vtkm/cont/cuda/testing/UnitTestCudaMathEdgeCases.cu @@ -10,12 +10,12 @@ #include #include -#include -#include #include #include +#include + #include #include #include @@ -164,15 +164,11 @@ void RunEdgeCases() } //namespace -int UnitTestCudaMath(int argc, char* argv[]) +int UnitTestCudaMathEdgeCases(int argc, char* argv[]) { auto& tracker = vtkm::cont::GetRuntimeDeviceTracker(); tracker.ForceDevice(vtkm::cont::DeviceAdapterTagCuda{}); - int tests_valid = vtkm::cont::testing::Testing::Run( - UnitTestMathNamespace::RunMathTests, argc, argv); - tests_valid += - vtkm::cont::testing::Testing::Run(RunEdgeCases, argc, argv); - - return tests_valid; + return vtkm::cont::testing::Testing::Run( + RunEdgeCases, argc, argv); } diff --git a/vtkm/cont/kokkos/testing/CMakeLists.txt b/vtkm/cont/kokkos/testing/CMakeLists.txt index 1d2740a2b..524821c92 100644 --- a/vtkm/cont/kokkos/testing/CMakeLists.txt +++ b/vtkm/cont/kokkos/testing/CMakeLists.txt @@ -9,7 +9,6 @@ ##============================================================================ set(unit_tests - UnitTestKokkosAlgorithms.cxx UnitTestKokkosArrayHandle.cxx UnitTestKokkosArrayHandleFancy.cxx UnitTestKokkosArrayHandleMultiplexer.cxx @@ -23,7 +22,6 @@ set(unit_tests UnitTestKokkosDataSetExplicit.cxx UnitTestKokkosDataSetSingleType.cxx UnitTestKokkosDeviceAdapter.cxx - UnitTestKokkosGeometry.cxx UnitTestKokkosImplicitFunction.cxx UnitTestKokkosPointLocatorUniformGrid.cxx UnitTestKokkosVirtualObjectHandle.cxx diff --git a/vtkm/cont/kokkos/testing/UnitTestKokkosAlgorithms.cxx b/vtkm/cont/kokkos/testing/UnitTestKokkosAlgorithms.cxx deleted file mode 100644 index 2b7f96aa2..000000000 --- a/vtkm/cont/kokkos/testing/UnitTestKokkosAlgorithms.cxx +++ /dev/null @@ -1,20 +0,0 @@ -//============================================================================ -// Copyright (c) Kitware, Inc. -// All rights reserved. -// See LICENSE.txt for details. -// -// This software is distributed WITHOUT ANY WARRANTY; without even -// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR -// PURPOSE. See the above copyright notice for more information. -//============================================================================ - -#include -#include - -#include - -int UnitTestKokkosAlgorithms(int argc, char* argv[]) -{ - return vtkm::cont::testing::Testing::Run( - RunAlgorithmsTests, argc, argv); -} diff --git a/vtkm/cont/kokkos/testing/UnitTestKokkosGeometry.cxx b/vtkm/cont/kokkos/testing/UnitTestKokkosGeometry.cxx deleted file mode 100644 index 9fc3736e7..000000000 --- a/vtkm/cont/kokkos/testing/UnitTestKokkosGeometry.cxx +++ /dev/null @@ -1,21 +0,0 @@ -//============================================================================ -// Copyright (c) Kitware, Inc. -// All rights reserved. -// See LICENSE.txt for details. -// -// This software is distributed WITHOUT ANY WARRANTY; without even -// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR -// PURPOSE. See the above copyright notice for more information. -//============================================================================ - -#include -#include -#include - -int UnitTestKokkosGeometry(int argc, char* argv[]) -{ - auto& tracker = vtkm::cont::GetRuntimeDeviceTracker(); - tracker.ForceDevice(vtkm::cont::DeviceAdapterTagKokkos{}); - return vtkm::cont::testing::Testing::Run( - UnitTestGeometryNamespace::RunGeometryTests, argc, argv); -} diff --git a/vtkm/cont/openmp/testing/CMakeLists.txt b/vtkm/cont/openmp/testing/CMakeLists.txt index 5e0e3b1c4..1b6f69bf9 100644 --- a/vtkm/cont/openmp/testing/CMakeLists.txt +++ b/vtkm/cont/openmp/testing/CMakeLists.txt @@ -9,7 +9,6 @@ ##============================================================================ set(unit_tests - UnitTestOpenMPAlgorithms.cxx UnitTestOpenMPArrayHandle.cxx UnitTestOpenMPArrayHandleFancy.cxx UnitTestOpenMPArrayHandleMultiplexer.cxx diff --git a/vtkm/cont/openmp/testing/UnitTestOpenMPAlgorithms.cxx b/vtkm/cont/openmp/testing/UnitTestOpenMPAlgorithms.cxx deleted file mode 100644 index a63a8add8..000000000 --- a/vtkm/cont/openmp/testing/UnitTestOpenMPAlgorithms.cxx +++ /dev/null @@ -1,20 +0,0 @@ -//============================================================================ -// Copyright (c) Kitware, Inc. -// All rights reserved. -// See LICENSE.txt for details. -// -// This software is distributed WITHOUT ANY WARRANTY; without even -// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR -// PURPOSE. See the above copyright notice for more information. -//============================================================================ - -#include -#include - -#include - -int UnitTestOpenMPAlgorithms(int argc, char* argv[]) -{ - return vtkm::testing::Testing::Run( - RunAlgorithmsTests, argc, argv); -} diff --git a/vtkm/cont/serial/testing/CMakeLists.txt b/vtkm/cont/serial/testing/CMakeLists.txt index 6ff3f61b7..e19eaa301 100644 --- a/vtkm/cont/serial/testing/CMakeLists.txt +++ b/vtkm/cont/serial/testing/CMakeLists.txt @@ -22,7 +22,6 @@ set(unit_tests UnitTestSerialDataSetExplicit.cxx UnitTestSerialDataSetSingleType.cxx UnitTestSerialDeviceAdapter.cxx - UnitTestSerialGeometry.cxx UnitTestSerialImplicitFunction.cxx UnitTestSerialPointLocatorUniformGrid.cxx UnitTestSerialVirtualObjectHandle.cxx diff --git a/vtkm/cont/serial/testing/UnitTestSerialGeometry.cxx b/vtkm/cont/serial/testing/UnitTestSerialGeometry.cxx deleted file mode 100644 index 2b7baa904..000000000 --- a/vtkm/cont/serial/testing/UnitTestSerialGeometry.cxx +++ /dev/null @@ -1,21 +0,0 @@ -//============================================================================ -// Copyright (c) Kitware, Inc. -// All rights reserved. -// See LICENSE.txt for details. -// -// This software is distributed WITHOUT ANY WARRANTY; without even -// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR -// PURPOSE. See the above copyright notice for more information. -//============================================================================ - -#include -#include -#include - -int UnitTestSerialGeometry(int argc, char* argv[]) -{ - auto& tracker = vtkm::cont::GetRuntimeDeviceTracker(); - tracker.ForceDevice(vtkm::cont::DeviceAdapterTagSerial{}); - return vtkm::cont::testing::Testing::Run( - UnitTestGeometryNamespace::RunGeometryTests, argc, argv); -} diff --git a/vtkm/cont/tbb/testing/CMakeLists.txt b/vtkm/cont/tbb/testing/CMakeLists.txt index 27ac80cea..8868478b6 100644 --- a/vtkm/cont/tbb/testing/CMakeLists.txt +++ b/vtkm/cont/tbb/testing/CMakeLists.txt @@ -9,7 +9,6 @@ ##============================================================================ set(unit_tests - UnitTestTBBAlgorithms.cxx UnitTestTBBArrayHandle.cxx UnitTestTBBArrayHandleFancy.cxx UnitTestTBBArrayHandleMultiplexer.cxx diff --git a/vtkm/cont/tbb/testing/UnitTestTBBAlgorithms.cxx b/vtkm/cont/tbb/testing/UnitTestTBBAlgorithms.cxx deleted file mode 100644 index 68ae4bebd..000000000 --- a/vtkm/cont/tbb/testing/UnitTestTBBAlgorithms.cxx +++ /dev/null @@ -1,20 +0,0 @@ -//============================================================================ -// Copyright (c) Kitware, Inc. -// All rights reserved. -// See LICENSE.txt for details. -// -// This software is distributed WITHOUT ANY WARRANTY; without even -// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR -// PURPOSE. See the above copyright notice for more information. -//============================================================================ - -#include -#include - -#include - -int UnitTestTBBAlgorithms(int argc, char* argv[]) -{ - return vtkm::testing::Testing::Run( - RunAlgorithmsTests, argc, argv); -} diff --git a/vtkm/testing/CMakeLists.txt b/vtkm/testing/CMakeLists.txt index 5449b5c8b..6bdc3abe8 100644 --- a/vtkm/testing/CMakeLists.txt +++ b/vtkm/testing/CMakeLists.txt @@ -10,16 +10,12 @@ set(headers Testing.h - TestingAlgorithms.h - TestingMath.h - TestingGeometry.h VecTraitsTests.h ) VTKM_declare_headers(${headers}) set(unit_tests - UnitTestAlgorithms.cxx UnitTestBinaryPredicates.cxx UnitTestBinaryOperators.cxx UnitTestBounds.cxx @@ -29,7 +25,6 @@ set(unit_tests UnitTestHash.cxx UnitTestList.cxx UnitTestListTag.cxx - UnitTestMath.cxx UnitTestMatrix.cxx UnitTestNewtonsMethod.cxx UnitTestNoAssert.cxx @@ -51,6 +46,13 @@ set(unit_tests UnitTestVecVariable.cxx ) +# Unit tests that have device-specific code to be tested +set(unit_tests_device + UnitTestAlgorithms.cxx + UnitTestGeometry.cxx + UnitTestMath.cxx + ) + #suppress gcc note: #variable tracking size limit exceeded with -fvar-tracking-assignments, retrying without @@ -59,3 +61,5 @@ if (VTKM_COMPILER_IS_GNU) endif() vtkm_unit_tests(SOURCES ${unit_tests}) + +vtkm_unit_tests(NAME UnitTests_vtkm_testing_device SOURCES ${unit_tests_device} ALL_BACKENDS) diff --git a/vtkm/testing/TestingAlgorithms.h b/vtkm/testing/TestingAlgorithms.h deleted file mode 100644 index 4e6d129f6..000000000 --- a/vtkm/testing/TestingAlgorithms.h +++ /dev/null @@ -1,230 +0,0 @@ -//============================================================================ -// Copyright (c) Kitware, Inc. -// All rights reserved. -// See LICENSE.txt for details. -// -// This software is distributed WITHOUT ANY WARRANTY; without even -// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR -// PURPOSE. See the above copyright notice for more information. -//============================================================================ -#ifndef vtk_m_testing_TestingAlgorithms_h -#define vtk_m_testing_TestingAlgorithms_h - -#include - -#include -#include - -#include - -#include - -#include - -namespace -{ - -using IdArray = vtkm::cont::ArrayHandle; - -struct TestBinarySearch -{ - template - struct Impl : public vtkm::exec::FunctorBase - { - NeedlesT Needles; - HayStackT HayStack; - ResultsT Results; - - VTKM_CONT - Impl(const NeedlesT& needles, const HayStackT& hayStack, const ResultsT& results) - : Needles(needles) - , HayStack(hayStack) - , Results(results) - { - } - - VTKM_EXEC - void operator()(vtkm::Id index) const - { - this->Results.Set(index, vtkm::BinarySearch(this->HayStack, this->Needles.Get(index))); - } - }; - - template - static void Run() - { - using Algo = vtkm::cont::DeviceAdapterAlgorithm; - - IdArray needles = vtkm::cont::make_ArrayHandle({ -4, -3, -2, -1, 0, 1, 2, 3, 4, 5 }); - IdArray hayStack = - vtkm::cont::make_ArrayHandle({ -3, -2, -2, -2, 0, 0, 1, 1, 1, 4, 4 }); - IdArray results; - - std::vector expectedFound{ - false, true, true, false, true, true, false, false, true, false - }; - - vtkm::cont::Token token; - - using Functor = Impl::PortalConst, - typename IdArray::ExecutionTypes::PortalConst, - typename IdArray::ExecutionTypes::Portal>; - Functor functor{ needles.PrepareForInput(Device{}, token), - hayStack.PrepareForInput(Device{}, token), - results.PrepareForOutput(needles.GetNumberOfValues(), Device{}, token) }; - - Algo::Schedule(functor, needles.GetNumberOfValues()); - - token.DetachFromAll(); - - // Verify: - auto needlesPortal = needles.ReadPortal(); - auto hayStackPortal = hayStack.ReadPortal(); - auto resultsPortal = results.ReadPortal(); - for (vtkm::Id i = 0; i < needles.GetNumberOfValues(); ++i) - { - if (expectedFound[static_cast(i)]) - { - const auto resIdx = resultsPortal.Get(i); - const auto expVal = needlesPortal.Get(i); - VTKM_TEST_ASSERT(resIdx >= 0); - VTKM_TEST_ASSERT(hayStackPortal.Get(resIdx) == expVal); - } - else - { - VTKM_TEST_ASSERT(resultsPortal.Get(i) == -1); - } - } - } -}; - -struct TestLowerBound -{ - template - struct Impl : public vtkm::exec::FunctorBase - { - NeedlesT Needles; - HayStackT HayStack; - ResultsT Results; - - VTKM_CONT - Impl(const NeedlesT& needles, const HayStackT& hayStack, const ResultsT& results) - : Needles(needles) - , HayStack(hayStack) - , Results(results) - { - } - - VTKM_EXEC - void operator()(vtkm::Id index) const - { - this->Results.Set(index, vtkm::LowerBound(this->HayStack, this->Needles.Get(index))); - } - }; - - template - static void Run() - { - using Algo = vtkm::cont::DeviceAdapterAlgorithm; - - IdArray needles = vtkm::cont::make_ArrayHandle({ -4, -3, -2, -1, 0, 1, 2, 3, 4, 5 }); - IdArray hayStack = - vtkm::cont::make_ArrayHandle({ -3, -2, -2, -2, 0, 0, 1, 1, 1, 4, 4 }); - IdArray results; - - std::vector expected{ 0, 0, 1, 4, 4, 6, 9, 9, 9, 11 }; - - vtkm::cont::Token token; - - using Functor = Impl::PortalConst, - typename IdArray::ExecutionTypes::PortalConst, - typename IdArray::ExecutionTypes::Portal>; - Functor functor{ needles.PrepareForInput(Device{}, token), - hayStack.PrepareForInput(Device{}, token), - results.PrepareForOutput(needles.GetNumberOfValues(), Device{}, token) }; - - Algo::Schedule(functor, needles.GetNumberOfValues()); - - token.DetachFromAll(); - - // Verify: - auto resultsPortal = results.ReadPortal(); - for (vtkm::Id i = 0; i < needles.GetNumberOfValues(); ++i) - { - VTKM_TEST_ASSERT(resultsPortal.Get(i) == expected[static_cast(i)]); - } - } -}; - -struct TestUpperBound -{ - template - struct Impl : public vtkm::exec::FunctorBase - { - NeedlesT Needles; - HayStackT HayStack; - ResultsT Results; - - VTKM_CONT - Impl(const NeedlesT& needles, const HayStackT& hayStack, const ResultsT& results) - : Needles(needles) - , HayStack(hayStack) - , Results(results) - { - } - - VTKM_EXEC - void operator()(vtkm::Id index) const - { - this->Results.Set(index, vtkm::UpperBound(this->HayStack, this->Needles.Get(index))); - } - }; - - template - static void Run() - { - using Algo = vtkm::cont::DeviceAdapterAlgorithm; - - IdArray needles = vtkm::cont::make_ArrayHandle({ -4, -3, -2, -1, 0, 1, 2, 3, 4, 5 }); - IdArray hayStack = - vtkm::cont::make_ArrayHandle({ -3, -2, -2, -2, 0, 0, 1, 1, 1, 4, 4 }); - IdArray results; - - std::vector expected{ 0, 1, 4, 4, 6, 9, 9, 9, 11, 11 }; - - vtkm::cont::Token token; - - using Functor = Impl::PortalConst, - typename IdArray::ExecutionTypes::PortalConst, - typename IdArray::ExecutionTypes::Portal>; - Functor functor{ needles.PrepareForInput(Device{}, token), - hayStack.PrepareForInput(Device{}, token), - results.PrepareForOutput(needles.GetNumberOfValues(), Device{}, token) }; - - Algo::Schedule(functor, needles.GetNumberOfValues()); - - token.DetachFromAll(); - - // Verify: - auto resultsPortal = results.ReadPortal(); - for (vtkm::Id i = 0; i < needles.GetNumberOfValues(); ++i) - { - VTKM_TEST_ASSERT(resultsPortal.Get(i) == expected[static_cast(i)]); - } - } -}; - -} // anon namespace - -template -void RunAlgorithmsTests() -{ - std::cout << "Testing binary search." << std::endl; - TestBinarySearch::Run(); - std::cout << "Testing lower bound." << std::endl; - TestLowerBound::Run(); - std::cout << "Testing upper bound." << std::endl; - TestUpperBound::Run(); -} - -#endif //vtk_m_testing_TestingAlgorithms_h diff --git a/vtkm/testing/TestingMath.h b/vtkm/testing/TestingMath.h deleted file mode 100644 index 8c04e1384..000000000 --- a/vtkm/testing/TestingMath.h +++ /dev/null @@ -1,1095 +0,0 @@ -//============================================================================ -// Copyright (c) Kitware, Inc. -// All rights reserved. -// See LICENSE.txt for details. -// -// This software is distributed WITHOUT ANY WARRANTY; without even -// the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR -// PURPOSE. See the above copyright notice for more information. -//============================================================================ -#ifndef vtk_m_testing_TestingMath_h -#define vtk_m_testing_TestingMath_h - -#include - -#include -#include - -#include - -#include - -#include - -#define VTKM_MATH_ASSERT(condition, message) \ - if (!(condition)) \ - { \ - this->RaiseError(message); \ - } - -//----------------------------------------------------------------------------- -namespace UnitTestMathNamespace -{ - -class Lists -{ -public: - static constexpr vtkm::IdComponent NUM_NUMBERS = 5; - - VTKM_EXEC_CONT vtkm::Float64 NumberList(vtkm::Int32 i) const - { - vtkm::Float64 numberList[NUM_NUMBERS] = { 0.25, 0.5, 1.0, 2.0, 3.75 }; - return numberList[i]; - } - VTKM_EXEC_CONT vtkm::Float64 AngleList(vtkm::Int32 i) const - { - vtkm::Float64 angleList[NUM_NUMBERS] = { 0.643501108793284, // angle for 3, 4, 5 triangle. - 0.78539816339745, // pi/4 - 0.5235987755983, // pi/6 - 1.0471975511966, // pi/3 - 0.0 }; - return angleList[i]; - } - VTKM_EXEC_CONT vtkm::Float64 OppositeList(vtkm::Int32 i) const - { - vtkm::Float64 oppositeList[NUM_NUMBERS] = { 3.0, 1.0, 1.0, 1.732050807568877 /*sqrt(3)*/, 0.0 }; - return oppositeList[i]; - } - VTKM_EXEC_CONT vtkm::Float64 AdjacentList(vtkm::Int32 i) const - { - vtkm::Float64 adjacentList[NUM_NUMBERS] = { 4.0, 1.0, 1.732050807568877 /*sqrt(3)*/, 1.0, 1.0 }; - return adjacentList[i]; - } - VTKM_EXEC_CONT vtkm::Float64 HypotenuseList(vtkm::Int32 i) const - { - vtkm::Float64 hypotenuseList[NUM_NUMBERS] = { - 5.0, 1.414213562373095 /*sqrt(2)*/, 2.0, 2.0, 1.0 - }; - return hypotenuseList[i]; - } - VTKM_EXEC_CONT vtkm::Float64 NumeratorList(vtkm::Int32 i) const - { - vtkm::Float64 numeratorList[NUM_NUMBERS] = { 6.5, 5.8, 9.3, 77.0, 0.1 }; - return numeratorList[i]; - } - VTKM_EXEC_CONT vtkm::Float64 DenominatorList(vtkm::Int32 i) const - { - vtkm::Float64 denominatorList[NUM_NUMBERS] = { 2.3, 1.6, 3.1, 19.0, 0.4 }; - return denominatorList[i]; - } - VTKM_EXEC_CONT vtkm::Float64 FModRemainderList(vtkm::Int32 i) const - { - vtkm::Float64 fModRemainderList[NUM_NUMBERS] = { 1.9, 1.0, 0.0, 1.0, 0.1 }; - return fModRemainderList[i]; - } - VTKM_EXEC_CONT vtkm::Float64 RemainderList(vtkm::Int32 i) const - { - vtkm::Float64 remainderList[NUM_NUMBERS] = { -0.4, -0.6, 0.0, 1.0, 0.1 }; - return remainderList[i]; - } - VTKM_EXEC_CONT vtkm::Int64 QuotientList(vtkm::Int32 i) const - { - vtkm::Int64 quotientList[NUM_NUMBERS] = { 3, 4, 3, 4, 0 }; - return quotientList[i]; - } - VTKM_EXEC_CONT vtkm::Float64 XList(vtkm::Int32 i) const - { - vtkm::Float64 xList[NUM_NUMBERS] = { 4.6, 0.1, 73.4, 55.0, 3.75 }; - return xList[i]; - } - VTKM_EXEC_CONT vtkm::Float64 FractionalList(vtkm::Int32 i) const - { - vtkm::Float64 fractionalList[NUM_NUMBERS] = { 0.6, 0.1, 0.4, 0.0, 0.75 }; - return fractionalList[i]; - } - VTKM_EXEC_CONT vtkm::Float64 FloorList(vtkm::Int32 i) const - { - vtkm::Float64 floorList[NUM_NUMBERS] = { 4.0, 0.0, 73.0, 55.0, 3.0 }; - return floorList[i]; - } - VTKM_EXEC_CONT vtkm::Float64 CeilList(vtkm::Int32 i) const - { - vtkm::Float64 ceilList[NUM_NUMBERS] = { 5.0, 1.0, 74.0, 55.0, 4.0 }; - return ceilList[i]; - } - VTKM_EXEC_CONT vtkm::Float64 RoundList(vtkm::Int32 i) const - { - vtkm::Float64 roundList[NUM_NUMBERS] = { 5.0, 0.0, 73.0, 55.0, 4.0 }; - return roundList[i]; - } -}; - -//----------------------------------------------------------------------------- -template -struct ScalarFieldTests : public vtkm::exec::FunctorBase -{ - VTKM_EXEC - void TestPi() const - { - // std::cout << "Testing Pi" << std::endl; - VTKM_MATH_ASSERT(test_equal(vtkm::Pi(), 3.14159265), "Pi not correct."); - VTKM_MATH_ASSERT(test_equal(vtkm::Pif(), 3.14159265f), "Pif not correct."); - VTKM_MATH_ASSERT(test_equal(vtkm::Pi(), 3.14159265), - "Pi template function not correct."); - } - - VTKM_EXEC - void TestArcTan2() const - { - // std::cout << "Testing arc tan 2" << std::endl; - - VTKM_MATH_ASSERT(test_equal(vtkm::ATan2(T(0.0), T(1.0)), T(0.0)), "ATan2 x+ axis."); - VTKM_MATH_ASSERT(test_equal(vtkm::ATan2(T(1.0), T(0.0)), T(0.5 * vtkm::Pi())), - "ATan2 y+ axis."); - VTKM_MATH_ASSERT(test_equal(vtkm::ATan2(T(-1.0), T(0.0)), T(-0.5 * vtkm::Pi())), - "ATan2 y- axis."); - - VTKM_MATH_ASSERT(test_equal(vtkm::ATan2(T(1.0), T(1.0)), T(0.25 * vtkm::Pi())), - "ATan2 Quadrant 1"); - VTKM_MATH_ASSERT(test_equal(vtkm::ATan2(T(1.0), T(-1.0)), T(0.75 * vtkm::Pi())), - "ATan2 Quadrant 2"); - VTKM_MATH_ASSERT(test_equal(vtkm::ATan2(T(-1.0), T(-1.0)), T(-0.75 * vtkm::Pi())), - "ATan2 Quadrant 3"); - VTKM_MATH_ASSERT(test_equal(vtkm::ATan2(T(-1.0), T(1.0)), T(-0.25 * vtkm::Pi())), - "ATan2 Quadrant 4"); - } - - VTKM_EXEC - void TestPow() const - { - // std::cout << "Running power tests." << std::endl; - for (vtkm::IdComponent index = 0; index < Lists::NUM_NUMBERS; index++) - { - T x = static_cast(Lists{}.NumberList(index)); - T powx = vtkm::Pow(x, static_cast(2.0)); - T sqrx = x * x; - VTKM_MATH_ASSERT(test_equal(powx, sqrx), "Power gave wrong result."); - } - } - - VTKM_EXEC - void TestLog2() const - { - // std::cout << "Testing Log2" << std::endl; - VTKM_MATH_ASSERT(test_equal(vtkm::Log2(T(0.25)), T(-2.0)), "Bad value from Log2"); - VTKM_MATH_ASSERT(test_equal(vtkm::Log2(vtkm::Vec(0.5, 1.0, 2.0, 4.0)), - vtkm::Vec(-1.0, 0.0, 1.0, 2.0)), - "Bad value from Log2"); - } - - VTKM_EXEC - void TestNonFinites() const - { - // std::cout << "Testing non-finites." << std::endl; - - T zero = 0.0; - T finite = 1.0; - T nan = vtkm::Nan(); - T inf = vtkm::Infinity(); - T neginf = vtkm::NegativeInfinity(); - T epsilon = vtkm::Epsilon(); - - // General behavior. - VTKM_MATH_ASSERT(nan != vtkm::Nan(), "Nan not equal itself."); - VTKM_MATH_ASSERT(!(nan >= zero), "Nan not greater or less."); - VTKM_MATH_ASSERT(!(nan <= zero), "Nan not greater or less."); - VTKM_MATH_ASSERT(!(nan >= finite), "Nan not greater or less."); - VTKM_MATH_ASSERT(!(nan <= finite), "Nan not greater or less."); - - VTKM_MATH_ASSERT(neginf < inf, "Infinity big"); - VTKM_MATH_ASSERT(zero < inf, "Infinity big"); - VTKM_MATH_ASSERT(finite < inf, "Infinity big"); - VTKM_MATH_ASSERT(zero > -inf, "-Infinity small"); - VTKM_MATH_ASSERT(finite > -inf, "-Infinity small"); - VTKM_MATH_ASSERT(zero > neginf, "-Infinity small"); - VTKM_MATH_ASSERT(finite > neginf, "-Infinity small"); - - VTKM_MATH_ASSERT(zero < epsilon, "Negative epsilon"); - VTKM_MATH_ASSERT(finite > epsilon, "Large epsilon"); - - // Math check functions. - VTKM_MATH_ASSERT(!vtkm::IsNan(zero), "Bad IsNan check."); - VTKM_MATH_ASSERT(!vtkm::IsNan(finite), "Bad IsNan check."); - VTKM_MATH_ASSERT(vtkm::IsNan(nan), "Bad IsNan check."); - VTKM_MATH_ASSERT(!vtkm::IsNan(inf), "Bad IsNan check."); - VTKM_MATH_ASSERT(!vtkm::IsNan(neginf), "Bad IsNan check."); - VTKM_MATH_ASSERT(!vtkm::IsNan(epsilon), "Bad IsNan check."); - - VTKM_MATH_ASSERT(!vtkm::IsInf(zero), "Bad infinity check."); - VTKM_MATH_ASSERT(!vtkm::IsInf(finite), "Bad infinity check."); - VTKM_MATH_ASSERT(!vtkm::IsInf(nan), "Bad infinity check."); - VTKM_MATH_ASSERT(vtkm::IsInf(inf), "Bad infinity check."); - VTKM_MATH_ASSERT(vtkm::IsInf(neginf), "Bad infinity check."); - VTKM_MATH_ASSERT(!vtkm::IsInf(epsilon), "Bad infinity check."); - - VTKM_MATH_ASSERT(vtkm::IsFinite(zero), "Bad finite check."); - VTKM_MATH_ASSERT(vtkm::IsFinite(finite), "Bad finite check."); - VTKM_MATH_ASSERT(!vtkm::IsFinite(nan), "Bad finite check."); - VTKM_MATH_ASSERT(!vtkm::IsFinite(inf), "Bad finite check."); - VTKM_MATH_ASSERT(!vtkm::IsFinite(neginf), "Bad finite check."); - VTKM_MATH_ASSERT(vtkm::IsFinite(epsilon), "Bad finite check."); - } - - VTKM_EXEC - void TestRemainders() const - { - // std::cout << "Testing remainders." << std::endl; - Lists table; - for (vtkm::IdComponent index = 0; index < Lists::NUM_NUMBERS; index++) - { - T numerator = static_cast(table.NumeratorList(index)); - T denominator = static_cast(table.DenominatorList(index)); - T fmodremainder = static_cast(table.FModRemainderList(index)); - T remainder = static_cast(table.RemainderList(index)); - vtkm::Int64 quotient = table.QuotientList(index); - - VTKM_MATH_ASSERT(test_equal(vtkm::FMod(numerator, denominator), fmodremainder), - "Bad FMod remainder."); - VTKM_MATH_ASSERT(test_equal(vtkm::Remainder(numerator, denominator), remainder), - "Bad remainder."); - vtkm::Int64 q; - VTKM_MATH_ASSERT(test_equal(vtkm::RemainderQuotient(numerator, denominator, q), remainder), - "Bad remainder-quotient remainder."); - VTKM_MATH_ASSERT(test_equal(q, quotient), "Bad reminder-quotient quotient."); - } - } - - VTKM_EXEC - void TestRound() const - { - // std::cout << "Testing round." << std::endl; - Lists table; - for (vtkm::IdComponent index = 0; index < Lists::NUM_NUMBERS; index++) - { - T x = static_cast(table.XList(index)); - T fractional = static_cast(table.FractionalList(index)); - T floor = static_cast(table.FloorList(index)); - T ceil = static_cast(table.CeilList(index)); - T round = static_cast(table.RoundList(index)); - - T intPart; - VTKM_MATH_ASSERT(test_equal(vtkm::ModF(x, intPart), fractional), - "ModF returned wrong fractional part."); - VTKM_MATH_ASSERT(test_equal(intPart, floor), "ModF returned wrong integral part."); - VTKM_MATH_ASSERT(test_equal(vtkm::Floor(x), floor), "Bad floor."); - VTKM_MATH_ASSERT(test_equal(vtkm::Ceil(x), ceil), "Bad ceil."); - VTKM_MATH_ASSERT(test_equal(vtkm::Round(x), round), "Bad round."); - } - } - - VTKM_EXEC - void TestIsNegative() const - { - // std::cout << "Testing SignBit and IsNegative." << std::endl; - T x = 0; - VTKM_MATH_ASSERT(vtkm::SignBit(x) == 0, "SignBit wrong for 0."); - VTKM_MATH_ASSERT(!vtkm::IsNegative(x), "IsNegative wrong for 0."); - - x = 20; - VTKM_MATH_ASSERT(vtkm::SignBit(x) == 0, "SignBit wrong for 20."); - VTKM_MATH_ASSERT(!vtkm::IsNegative(x), "IsNegative wrong for 20."); - - x = -20; - VTKM_MATH_ASSERT(vtkm::SignBit(x) != 0, "SignBit wrong for -20."); - VTKM_MATH_ASSERT(vtkm::IsNegative(x), "IsNegative wrong for -20."); - - x = 0.02f; - VTKM_MATH_ASSERT(vtkm::SignBit(x) == 0, "SignBit wrong for 0.02."); - VTKM_MATH_ASSERT(!vtkm::IsNegative(x), "IsNegative wrong for 0.02."); - - x = -0.02f; - VTKM_MATH_ASSERT(vtkm::SignBit(x) != 0, "SignBit wrong for -0.02."); - VTKM_MATH_ASSERT(vtkm::IsNegative(x), "IsNegative wrong for -0.02."); - } - - VTKM_EXEC - void operator()(vtkm::Id) const - { - this->TestPi(); - this->TestArcTan2(); - this->TestPow(); - this->TestLog2(); - this->TestNonFinites(); - this->TestRemainders(); - this->TestRound(); - this->TestIsNegative(); - } -}; - -template -struct TryScalarFieldTests -{ - template - void operator()(const T&) const - { - vtkm::cont::DeviceAdapterAlgorithm::Schedule(ScalarFieldTests(), 1); - } -}; - -//----------------------------------------------------------------------------- -template -struct ScalarVectorFieldTests : public vtkm::exec::FunctorBase -{ - using Traits = vtkm::VecTraits; - using ComponentType = typename Traits::ComponentType; - enum - { - NUM_COMPONENTS = Traits::NUM_COMPONENTS - }; - - VTKM_EXEC - void TestTriangleTrig() const - { - // std::cout << "Testing normal trig functions." << std::endl; - Lists table; - for (vtkm::IdComponent index = 0; index < Lists::NUM_NUMBERS - NUM_COMPONENTS + 1; index++) - { - VectorType angle; - VectorType opposite; - VectorType adjacent; - VectorType hypotenuse; - for (vtkm::IdComponent componentIndex = 0; componentIndex < NUM_COMPONENTS; componentIndex++) - { - Traits::SetComponent(angle, - componentIndex, - static_cast(table.AngleList(componentIndex + index))); - Traits::SetComponent( - opposite, - componentIndex, - static_cast(table.OppositeList(componentIndex + index))); - Traits::SetComponent( - adjacent, - componentIndex, - static_cast(table.AdjacentList(componentIndex + index))); - Traits::SetComponent( - hypotenuse, - componentIndex, - static_cast(table.HypotenuseList(componentIndex + index))); - } - - VTKM_MATH_ASSERT(test_equal(vtkm::Sin(angle), opposite / hypotenuse), "Sin failed test."); - VTKM_MATH_ASSERT(test_equal(vtkm::Cos(angle), adjacent / hypotenuse), "Cos failed test."); - VTKM_MATH_ASSERT(test_equal(vtkm::Tan(angle), opposite / adjacent), "Tan failed test."); - - VTKM_MATH_ASSERT(test_equal(vtkm::ASin(opposite / hypotenuse), angle), - "Arc Sin failed test."); - -#if defined(VTKM_ICC) - // When the intel compiler has vectorization enabled ( -O2/-O3 ) it converts the - // `adjacent/hypotenuse` divide operation into reciprocal (rcpps) and - // multiply (mulps) operations. This causes a change in the expected result that - // is larger than the default tolerance of test_equal. - // - VTKM_MATH_ASSERT(test_equal(vtkm::ACos(adjacent / hypotenuse), angle, 0.0004), - "Arc Cos failed test."); -#else - VTKM_MATH_ASSERT(test_equal(vtkm::ACos(adjacent / hypotenuse), angle), - "Arc Cos failed test."); -#endif - VTKM_MATH_ASSERT(test_equal(vtkm::ATan(opposite / adjacent), angle), "Arc Tan failed test."); - } - } - - VTKM_EXEC - void TestHyperbolicTrig() const - { - // std::cout << "Testing hyperbolic trig functions." << std::endl; - - const VectorType zero(0); - const VectorType half(0.5); - Lists table; - for (vtkm::IdComponent index = 0; index < Lists::NUM_NUMBERS - NUM_COMPONENTS + 1; index++) - { - VectorType x; - for (vtkm::IdComponent componentIndex = 0; componentIndex < NUM_COMPONENTS; componentIndex++) - { - Traits::SetComponent( - x, componentIndex, static_cast(table.AngleList(componentIndex + index))); - } - - const VectorType minusX = zero - x; - - VTKM_MATH_ASSERT(test_equal(vtkm::SinH(x), half * (vtkm::Exp(x) - vtkm::Exp(minusX))), - "SinH does not match definition."); - VTKM_MATH_ASSERT(test_equal(vtkm::CosH(x), half * (vtkm::Exp(x) + vtkm::Exp(minusX))), - "SinH does not match definition."); - VTKM_MATH_ASSERT(test_equal(vtkm::TanH(x), vtkm::SinH(x) / vtkm::CosH(x)), - "TanH does not match definition"); - - VTKM_MATH_ASSERT(test_equal(vtkm::ASinH(vtkm::SinH(x)), x), "SinH not inverting."); - VTKM_MATH_ASSERT(test_equal(vtkm::ACosH(vtkm::CosH(x)), x), "CosH not inverting."); - VTKM_MATH_ASSERT(test_equal(vtkm::ATanH(vtkm::TanH(x)), x), "TanH not inverting."); - } - } - - template - VTKM_EXEC void RaiseToTest(FunctionType function, ComponentType exponent) const - { - Lists table; - for (vtkm::IdComponent index = 0; index < Lists::NUM_NUMBERS - NUM_COMPONENTS + 1; index++) - { - VectorType original; - VectorType raiseresult; - for (vtkm::IdComponent componentIndex = 0; componentIndex < NUM_COMPONENTS; componentIndex++) - { - ComponentType x = static_cast(table.NumberList(componentIndex + index)); - Traits::SetComponent(original, componentIndex, x); - Traits::SetComponent(raiseresult, componentIndex, vtkm::Pow(x, exponent)); - } - - VectorType mathresult = function(original); - - VTKM_MATH_ASSERT(test_equal(mathresult, raiseresult), "Exponent functions do not agree."); - } - } - - struct SqrtFunctor - { - VTKM_EXEC - VectorType operator()(VectorType x) const { return vtkm::Sqrt(x); } - }; - VTKM_EXEC - void TestSqrt() const - { - // std::cout << " Testing Sqrt" << std::endl; - RaiseToTest(SqrtFunctor(), 0.5); - } - - struct RSqrtFunctor - { - VTKM_EXEC - VectorType operator()(VectorType x) const { return vtkm::RSqrt(x); } - }; - VTKM_EXEC - void TestRSqrt() const - { - // std::cout << " Testing RSqrt"<< std::endl; - RaiseToTest(RSqrtFunctor(), -0.5); - } - - struct CbrtFunctor - { - VTKM_EXEC - VectorType operator()(VectorType x) const { return vtkm::Cbrt(x); } - }; - VTKM_EXEC - void TestCbrt() const - { - // std::cout << " Testing Cbrt" << std::endl; - RaiseToTest(CbrtFunctor(), vtkm::Float32(1.0 / 3.0)); - } - - struct RCbrtFunctor - { - VTKM_EXEC - VectorType operator()(VectorType x) const { return vtkm::RCbrt(x); } - }; - VTKM_EXEC - void TestRCbrt() const - { - // std::cout << " Testing RCbrt" << std::endl; - RaiseToTest(RCbrtFunctor(), vtkm::Float32(-1.0 / 3.0)); - } - - template - VTKM_EXEC void RaiseByTest(FunctionType function, - ComponentType base, - ComponentType exponentbias = 0.0, - ComponentType resultbias = 0.0) const - { - Lists table; - for (vtkm::IdComponent index = 0; index < Lists::NUM_NUMBERS - NUM_COMPONENTS + 1; index++) - { - VectorType original; - VectorType raiseresult; - for (vtkm::IdComponent componentIndex = 0; componentIndex < NUM_COMPONENTS; componentIndex++) - { - ComponentType x = static_cast(table.NumberList(componentIndex + index)); - Traits::SetComponent(original, componentIndex, x); - Traits::SetComponent( - raiseresult, componentIndex, vtkm::Pow(base, x + exponentbias) + resultbias); - } - - VectorType mathresult = function(original); - - VTKM_MATH_ASSERT(test_equal(mathresult, raiseresult), "Exponent functions do not agree."); - } - } - - struct ExpFunctor - { - VTKM_EXEC - VectorType operator()(VectorType x) const { return vtkm::Exp(x); } - }; - VTKM_EXEC - void TestExp() const - { - // std::cout << " Testing Exp" << std::endl; - RaiseByTest(ExpFunctor(), vtkm::Float32(2.71828183)); - } - - struct Exp2Functor - { - VTKM_EXEC - VectorType operator()(VectorType x) const { return vtkm::Exp2(x); } - }; - VTKM_EXEC - void TestExp2() const - { - // std::cout << " Testing Exp2" << std::endl; - RaiseByTest(Exp2Functor(), 2.0); - } - - struct ExpM1Functor - { - VTKM_EXEC - VectorType operator()(VectorType x) const { return vtkm::ExpM1(x); } - }; - VTKM_EXEC - void TestExpM1() const - { - // std::cout << " Testing ExpM1" << std::endl; - RaiseByTest(ExpM1Functor(), ComponentType(2.71828183), 0.0, -1.0); - } - - struct Exp10Functor - { - VTKM_EXEC - VectorType operator()(VectorType x) const { return vtkm::Exp10(x); } - }; - VTKM_EXEC - void TestExp10() const - { - // std::cout << " Testing Exp10" << std::endl; - RaiseByTest(Exp10Functor(), 10.0); - } - - template - VTKM_EXEC void LogBaseTest(FunctionType function, - ComponentType base, - ComponentType bias = 0.0) const - { - Lists table; - for (vtkm::IdComponent index = 0; index < Lists::NUM_NUMBERS - NUM_COMPONENTS + 1; index++) - { - VectorType basevector(base); - VectorType original; - VectorType biased; - for (vtkm::IdComponent componentIndex = 0; componentIndex < NUM_COMPONENTS; componentIndex++) - { - ComponentType x = static_cast(table.NumberList(componentIndex + index)); - Traits::SetComponent(original, componentIndex, x); - Traits::SetComponent(biased, componentIndex, x + bias); - } - - VectorType logresult = vtkm::Log2(biased) / vtkm::Log2(basevector); - - VectorType mathresult = function(original); - - VTKM_MATH_ASSERT(test_equal(mathresult, logresult), "Exponent functions do not agree."); - } - } - - struct LogFunctor - { - VTKM_EXEC - VectorType operator()(VectorType x) const { return vtkm::Log(x); } - }; - VTKM_EXEC - void TestLog() const - { - // std::cout << " Testing Log" << std::endl; - LogBaseTest(LogFunctor(), vtkm::Float32(2.71828183)); - } - - struct Log10Functor - { - VTKM_EXEC - VectorType operator()(VectorType x) const { return vtkm::Log10(x); } - }; - VTKM_EXEC - void TestLog10() const - { - // std::cout << " Testing Log10" << std::endl; - LogBaseTest(Log10Functor(), 10.0); - } - - struct Log1PFunctor - { - VTKM_EXEC - VectorType operator()(VectorType x) const { return vtkm::Log1P(x); } - }; - VTKM_EXEC - void TestLog1P() const - { - // std::cout << " Testing Log1P" << std::endl; - LogBaseTest(Log1PFunctor(), ComponentType(2.71828183), 1.0); - } - - VTKM_EXEC - void TestCopySign() const - { - // std::cout << "Testing CopySign." << std::endl; - // Assuming all TestValues positive. - VectorType positive1 = TestValue(1, VectorType()); - VectorType positive2 = TestValue(2, VectorType()); - VectorType negative1 = -positive1; - VectorType negative2 = -positive2; - - VTKM_MATH_ASSERT(test_equal(vtkm::CopySign(positive1, positive2), positive1), - "CopySign failed."); - VTKM_MATH_ASSERT(test_equal(vtkm::CopySign(negative1, positive2), positive1), - "CopySign failed."); - VTKM_MATH_ASSERT(test_equal(vtkm::CopySign(positive1, negative2), negative1), - "CopySign failed."); - VTKM_MATH_ASSERT(test_equal(vtkm::CopySign(negative1, negative2), negative1), - "CopySign failed."); - } - - VTKM_EXEC - void TestFloatDistance() const - { - { - vtkm::UInt64 dist = vtkm::FloatDistance(1.0, 1.0); - VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(0), dist), - "Float distance from 1.0 to 1.0 is not zero."); - - dist = vtkm::FloatDistance(-1.0, -1.0); - VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(0), dist), - "Float distance from -1.0 to -1.0 is not zero."); - - dist = vtkm::FloatDistance(0.0, 0.0); - VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(0), dist), - "Float distance from 0.0 to 0.0 is not zero."); - - // Check nan: - dist = vtkm::FloatDistance(std::numeric_limits::quiet_NaN(), 1.0); - VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(0xFFFFFFFFFFFFFFFFL), dist), - "Float distance to a Nan is not the documented value."); - - dist = vtkm::FloatDistance(1.0, std::numeric_limits::quiet_NaN()); - VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(0xFFFFFFFFFFFFFFFFL), dist), - "Float distance to a Nan is not the documented value."); - - // Check infinity: - dist = vtkm::FloatDistance(std::numeric_limits::infinity(), 1.0); - VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(0xFFFFFFFFFFFFFFFFL), dist), - "Float distance to infinity is not the documented value."); - - dist = vtkm::FloatDistance(1.0, std::numeric_limits::infinity()); - VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(0xFFFFFFFFFFFFFFFFL), dist), - "Float distance to infinity is not the documented value."); - - // Check saturation: - dist = vtkm::FloatDistance(std::numeric_limits::lowest(), - std::numeric_limits::max()); - VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(18437736874454810622uL), dist), - "Float distance from lowest to max is incorrect."); - - dist = vtkm::FloatDistance(std::numeric_limits::max(), - std::numeric_limits::lowest()); - VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(18437736874454810622uL), dist), - "Float distance from max to lowest is incorrect."); - - // Check symmetry: - dist = vtkm::FloatDistance(-2.0, -1.0); - vtkm::UInt64 dist2 = vtkm::FloatDistance(-1.0, -2.0); - VTKM_MATH_ASSERT(test_equal(dist2, dist), "Symmetry of negative numbers does not hold."); - - dist = vtkm::FloatDistance(1.0, 2.0); - dist2 = vtkm::FloatDistance(2.0, 1.0); - VTKM_MATH_ASSERT(test_equal(dist2, dist), "Float distance 1->2 != float distance 2->1."); - - // Check symmetry of bound which includes zero: - dist = vtkm::FloatDistance(-0.25, 0.25); - dist2 = vtkm::FloatDistance(0.25, -0.25); - VTKM_MATH_ASSERT(test_equal(dist2, dist), - "Symmetry is violated over a bound which contains zero."); - - // Check correctness: - dist = vtkm::FloatDistance(1.0, 1.0 + std::numeric_limits::epsilon()); - VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(1), dist), - "Float distance from 1 to 1 + eps is not = 1."); - dist = vtkm::FloatDistance(1.0 + std::numeric_limits::epsilon(), 1.0); - VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(1), dist), "Symmetry is violated"); - - dist = vtkm::FloatDistance(1.0, 1.0 + 2 * std::numeric_limits::epsilon()); - VTKM_MATH_ASSERT(test_equal(vtkm::Int64(2), dist), - "Float distance from 1 to 1 + 2eps is not 2."); - dist = vtkm::FloatDistance(1.0 + 2 * std::numeric_limits::epsilon(), 1.0); - VTKM_MATH_ASSERT(test_equal(vtkm::Int64(2), dist), "Symmetry is violated."); - - // Now test x = y: - vtkm::Float64 x = -1; - for (int i = 0; i < 500; ++i) - { - dist = vtkm::FloatDistance(x, x); - VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(0), dist), - "Float distance from x to x is not zero."); - x += 0.01; - } - // Test zero: - dist = vtkm::FloatDistance(0.0, 0.0); - VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(0), dist), - "Float distance from zero to zero is not zero."); - // Test signed zero: - dist = vtkm::FloatDistance(0.0, -0.0); - VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(0), dist), - "Float distance from 0.0 to -0.0 is not zero."); - - dist = vtkm::FloatDistance(-0.0, 0.0); - VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(0), dist), - "Float distance from -0.0 to 0.0 is not zero."); - - dist = vtkm::FloatDistance(-0.0, -0.0); - VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(0), dist), - "Float distance from -0.0 to 0.0 is not zero."); - - // Negative to negative zero: - dist = vtkm::FloatDistance(-std::numeric_limits::denorm_min(), -0.0); - VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(1), dist), "Negative to zero incorrect."); - // And symmetry: - dist = vtkm::FloatDistance(-0.0, -std::numeric_limits::denorm_min()); - VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(1), dist), "Symmetry is violated."); - - // Negative to positive zero: - dist = vtkm::FloatDistance(-std::numeric_limits::denorm_min(), 0.0); - VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(1), dist), - "Negative to positive zero is incorrect."); - // And symmetry: - dist = vtkm::FloatDistance(0.0, -std::numeric_limits::denorm_min()); - VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(1), dist), "Symmetry is violated."); - - // Positive to zero: - dist = vtkm::FloatDistance(std::numeric_limits::denorm_min(), 0.0); - VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(1), dist), "Positive to zero is incorrect."); - // And symmetry: - dist = vtkm::FloatDistance(0.0, std::numeric_limits::denorm_min()); - VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(1), dist), "Symmetry is violated"); - - // Positive to negative zero: - dist = vtkm::FloatDistance(std::numeric_limits::denorm_min(), -0.0); - VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(1), dist), - "Positive to negative zero is incorrect."); - // And symmetry: - dist = vtkm::FloatDistance(-0.0, std::numeric_limits::denorm_min()); - VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(1), dist), "Symmetry is violated."); - } - - // I would try to just template these, but in fact the double precision version has to saturate, - // whereas the float version has sufficient range. - { - vtkm::UInt64 dist = vtkm::FloatDistance(1.0f, 1.0f); - VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(0), dist), - "Float distance from 1.0 to 1.0 is not zero."); - - dist = vtkm::FloatDistance(-1.0f, -1.0f); - VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(0), dist), - "Float distance from -1.0 to -1.0 is not zero."); - - dist = vtkm::FloatDistance(0.0f, 0.0f); - VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(0), dist), - "Float distance from 0.0 to 0.0 is not zero."); - - // Check nan: - dist = vtkm::FloatDistance(std::numeric_limits::quiet_NaN(), 1.0f); - VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(0xFFFFFFFFFFFFFFFFL), dist), - "Float distance to a Nan is not the documented value."); - - dist = vtkm::FloatDistance(1.0f, std::numeric_limits::quiet_NaN()); - VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(0xFFFFFFFFFFFFFFFFL), dist), - "Float distance to a Nan is not the documented value."); - - // Check infinity: - dist = vtkm::FloatDistance(std::numeric_limits::infinity(), 1.0f); - VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(0xFFFFFFFFFFFFFFFFL), dist), - "Float distance to infinity is not the documented value."); - - dist = vtkm::FloatDistance(1.0f, std::numeric_limits::infinity()); - VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(0xFFFFFFFFFFFFFFFFL), dist), - "Float distance to infinity is not the documented value."); - - // Check saturation: - dist = vtkm::FloatDistance(std::numeric_limits::lowest(), - std::numeric_limits::max()); - VTKM_MATH_ASSERT(dist > 0, "Float distance is negative."); - - dist = vtkm::FloatDistance(std::numeric_limits::max(), - std::numeric_limits::lowest()); - VTKM_MATH_ASSERT(dist > 0, "Float distance is negative."); - - // Check symmetry: - dist = vtkm::FloatDistance(-2.0f, -1.0f); - vtkm::UInt64 dist2 = vtkm::FloatDistance(-1.0f, -2.0f); - VTKM_MATH_ASSERT(test_equal(dist2, dist), "Symmetry of negative numbers does not hold."); - - dist = vtkm::FloatDistance(1.0f, 2.0f); - dist2 = vtkm::FloatDistance(2.0f, 1.0f); - VTKM_MATH_ASSERT(test_equal(dist2, dist), "Float distance 1->2 != float distance 2->1."); - - // Check symmetry of bound which includes zero: - dist = vtkm::FloatDistance(-0.25f, 0.25f); - dist2 = vtkm::FloatDistance(0.25f, -0.25f); - VTKM_MATH_ASSERT(test_equal(dist2, dist), - "Symmetry is violated over a bound which contains zero."); - - // Check correctness: - dist = vtkm::FloatDistance(1.0f, 1.0f + std::numeric_limits::epsilon()); - VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(1), dist), - "Float distance from 1 to 1 + eps is not = 1."); - dist = vtkm::FloatDistance(1.0f + std::numeric_limits::epsilon(), 1.0f); - VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(1), dist), "Symmetry is violated"); - - dist = vtkm::FloatDistance(1.0f, 1.0f + 2 * std::numeric_limits::epsilon()); - VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(2), dist), - "Float distance from 1 to 1 + 2eps is not 2."); - dist = vtkm::FloatDistance(1.0f + 2 * std::numeric_limits::epsilon(), 1.0f); - VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(2), dist), "Symmetry is violated."); - - // Now test x = y: - vtkm::Float32 x = -1; - for (int i = 0; i < 500; ++i) - { - dist = vtkm::FloatDistance(x, x); - VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(0), dist), - "Float distance from x to x is not zero."); - x += 0.01f; - } - // Test zero: - dist = vtkm::FloatDistance(0.0f, 0.0f); - VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(0), dist), - "Float distance from zero to zero is not zero."); - // Test signed zero: - dist = vtkm::FloatDistance(0.0f, -0.0f); - VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(0), dist), - "Float distance from 0.0 to -0.0 is not zero."); - - dist = vtkm::FloatDistance(-0.0f, 0.0f); - VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(0), dist), - "Float distance from -0.0 to 0.0 is not zero."); - - dist = vtkm::FloatDistance(-0.0f, -0.0f); - VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(0), dist), - "Float distance from -0.0 to 0.0 is not zero."); - - // Negative to negative zero: - dist = vtkm::FloatDistance(-std::numeric_limits::denorm_min(), -0.0f); - VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(1), dist), "Negative to zero incorrect."); - // And symmetry: - dist = vtkm::FloatDistance(-0.0f, -std::numeric_limits::denorm_min()); - VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(1), dist), "Symmetry is violated."); - - // Negative to positive zero: - dist = vtkm::FloatDistance(-std::numeric_limits::denorm_min(), 0.0f); - VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(1), dist), - "Negative to positive zero is incorrect."); - // And symmetry: - dist = vtkm::FloatDistance(0.0f, -std::numeric_limits::denorm_min()); - VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(1), dist), "Symmetry is violated."); - - // Positive to zero: - dist = vtkm::FloatDistance(std::numeric_limits::denorm_min(), 0.0f); - VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(1), dist), "Positive to zero is incorrect."); - // And symmetry: - dist = vtkm::FloatDistance(0.0f, std::numeric_limits::denorm_min()); - VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(1), dist), "Symmetry is violated"); - - // Positive to negative zero: - dist = vtkm::FloatDistance(std::numeric_limits::denorm_min(), -0.0f); - VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(1), dist), - "Positive to negative zero is incorrect."); - // And symmetry: - dist = vtkm::FloatDistance(-0.0f, std::numeric_limits::denorm_min()); - VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(1), dist), "Symmetry is violated."); - } - } - - VTKM_EXEC - void operator()(vtkm::Id) const - { - this->TestTriangleTrig(); - this->TestHyperbolicTrig(); - this->TestSqrt(); - this->TestRSqrt(); - this->TestCbrt(); - this->TestRCbrt(); - this->TestExp(); - this->TestExp2(); - this->TestExpM1(); - this->TestExp10(); - this->TestLog(); - this->TestLog10(); - this->TestLog1P(); - this->TestCopySign(); - this->TestFloatDistance(); - } -}; - -template -struct TryScalarVectorFieldTests -{ - template - void operator()(const VectorType&) const - { - vtkm::cont::DeviceAdapterAlgorithm::Schedule(ScalarVectorFieldTests(), 1); - } -}; - -//----------------------------------------------------------------------------- -template -struct AllTypesTests : public vtkm::exec::FunctorBase -{ - VTKM_EXEC - void TestMinMax() const - { - T low = TestValue(2, T()); - T high = TestValue(10, T()); - // std::cout << "Testing min/max " << low << " " << high << std::endl; - VTKM_MATH_ASSERT(test_equal(vtkm::Min(low, high), low), "Wrong min."); - VTKM_MATH_ASSERT(test_equal(vtkm::Min(high, low), low), "Wrong min."); - VTKM_MATH_ASSERT(test_equal(vtkm::Max(low, high), high), "Wrong max."); - VTKM_MATH_ASSERT(test_equal(vtkm::Max(high, low), high), "Wrong max."); - - using Traits = vtkm::VecTraits; - T mixed1 = low; - T mixed2 = high; - Traits::SetComponent(mixed1, 0, Traits::GetComponent(high, 0)); - Traits::SetComponent(mixed2, 0, Traits::GetComponent(low, 0)); - VTKM_MATH_ASSERT(test_equal(vtkm::Min(mixed1, mixed2), low), "Wrong min."); - VTKM_MATH_ASSERT(test_equal(vtkm::Min(mixed2, mixed1), low), "Wrong min."); - VTKM_MATH_ASSERT(test_equal(vtkm::Max(mixed1, mixed2), high), "Wrong max."); - VTKM_MATH_ASSERT(test_equal(vtkm::Max(mixed2, mixed1), high), "Wrong max."); - } - - VTKM_EXEC - void operator()(vtkm::Id) const { this->TestMinMax(); } -}; - -template -struct TryAllTypesTests -{ - template - void operator()(const T&) const - { - vtkm::cont::DeviceAdapterAlgorithm::Schedule(AllTypesTests(), 1); - } -}; - -//----------------------------------------------------------------------------- -template -struct AbsTests : public vtkm::exec::FunctorBase -{ - VTKM_EXEC - void operator()(vtkm::Id index) const - { - // std::cout << "Testing Abs." << std::endl; - T positive = TestValue(index, T()); // Assuming all TestValues positive. - T negative = -positive; - - VTKM_MATH_ASSERT(test_equal(vtkm::Abs(positive), positive), "Abs returned wrong value."); - VTKM_MATH_ASSERT(test_equal(vtkm::Abs(negative), positive), "Abs returned wrong value."); - } -}; - -template -struct TryAbsTests -{ - template - void operator()(const T&) const - { - vtkm::cont::DeviceAdapterAlgorithm::Schedule(AbsTests(), 10); - } -}; - -using TypeListAbs = - vtkm::ListAppend, vtkm::TypeListIndex, vtkm::TypeListField>; - -//----------------------------------------------------------------------------- -static constexpr vtkm::Id BitOpSamples = 1024 * 1024; - -template -struct BitOpTests : public vtkm::exec::FunctorBase -{ - static constexpr T MaxT = std::numeric_limits::max(); - static constexpr T Offset = MaxT / BitOpSamples; - - VTKM_EXEC void operator()(vtkm::Id i) const - { - const T idx = static_cast(i); - const T word = idx * this->Offset; - - TestWord(word - idx); - TestWord(word); - TestWord(word + idx); - } - - VTKM_EXEC void TestWord(T word) const - { - VTKM_MATH_ASSERT(test_equal(vtkm::CountSetBits(word), this->DumbCountBits(word)), - "CountBits returned wrong value."); - VTKM_MATH_ASSERT(test_equal(vtkm::FindFirstSetBit(word), this->DumbFindFirstSetBit(word)), - "FindFirstSetBit returned wrong value.") - } - - VTKM_EXEC vtkm::Int32 DumbCountBits(T word) const - { - vtkm::Int32 bits = 0; - while (word) - { - if (word & 0x1) - { - ++bits; - } - word >>= 1; - } - return bits; - } - - VTKM_EXEC vtkm::Int32 DumbFindFirstSetBit(T word) const - { - if (word == 0) - { - return 0; - } - - vtkm::Int32 bit = 1; - while ((word & 0x1) == 0) - { - word >>= 1; - ++bit; - } - return bit; - } -}; - -template -struct TryBitOpTests -{ - template - void operator()(const T&) const - { - vtkm::cont::DeviceAdapterAlgorithm::Schedule(BitOpTests(), BitOpSamples); - } -}; - -using TypeListBitOp = vtkm::List; - -//----------------------------------------------------------------------------- -template -void RunMathTests() -{ - std::cout << "Tests for scalar types." << std::endl; - vtkm::testing::Testing::TryTypes(TryScalarFieldTests(), vtkm::TypeListFieldScalar()); - std::cout << "Test for scalar and vector types." << std::endl; - vtkm::testing::Testing::TryTypes(TryScalarVectorFieldTests(), vtkm::TypeListField()); - std::cout << "Test for exemplar types." << std::endl; - vtkm::testing::Testing::TryTypes(TryAllTypesTests()); - std::cout << "Test all Abs types" << std::endl; - vtkm::testing::Testing::TryTypes(TryAbsTests(), TypeListAbs()); - std::cout << "Test all bit operations" << std::endl; - vtkm::testing::Testing::TryTypes(TryBitOpTests(), TypeListBitOp()); -} - -} // namespace UnitTestMathNamespace - -#endif //vtk_m_testing_TestingMath_h diff --git a/vtkm/testing/UnitTestAlgorithms.cxx b/vtkm/testing/UnitTestAlgorithms.cxx index 1f2afde3d..994e3cd1a 100644 --- a/vtkm/testing/UnitTestAlgorithms.cxx +++ b/vtkm/testing/UnitTestAlgorithms.cxx @@ -8,13 +8,157 @@ // PURPOSE. See the above copyright notice for more information. //============================================================================ -#include -#include +#include -#include +#include +#include + +#include + +#include + +#include + +namespace +{ + +using IdArray = vtkm::cont::ArrayHandle; + +struct TestBinarySearch +{ + struct Impl : public vtkm::worklet::WorkletMapField + { + using ControlSignature = void(FieldIn needles, WholeArrayIn haystack, FieldOut results); + using ExecutionSignature = _3(_1, _2); + using InputDomain = _1; + + template + VTKM_EXEC vtkm::Id operator()(vtkm::Id needle, const HaystackPortal& haystack) const + { + return vtkm::BinarySearch(haystack, needle); + } + }; + + static void Run() + { + IdArray needles = vtkm::cont::make_ArrayHandle({ -4, -3, -2, -1, 0, 1, 2, 3, 4, 5 }); + IdArray haystack = + vtkm::cont::make_ArrayHandle({ -3, -2, -2, -2, 0, 0, 1, 1, 1, 4, 4 }); + IdArray results; + + std::vector expectedFound{ + false, true, true, false, true, true, false, false, true, false + }; + + vtkm::cont::Invoker invoke; + invoke(Impl{}, needles, haystack, results); + + // Verify: + auto needlesPortal = needles.ReadPortal(); + auto haystackPortal = haystack.ReadPortal(); + auto resultsPortal = results.ReadPortal(); + for (vtkm::Id i = 0; i < needles.GetNumberOfValues(); ++i) + { + if (expectedFound[static_cast(i)]) + { + const auto resIdx = resultsPortal.Get(i); + const auto expVal = needlesPortal.Get(i); + VTKM_TEST_ASSERT(resIdx >= 0); + VTKM_TEST_ASSERT(haystackPortal.Get(resIdx) == expVal); + } + else + { + VTKM_TEST_ASSERT(resultsPortal.Get(i) == -1); + } + } + } +}; + +struct TestLowerBound +{ + struct Impl : public vtkm::worklet::WorkletMapField + { + using ControlSignature = void(FieldIn needles, WholeArrayIn haystack, FieldOut results); + using ExecutionSignature = _3(_1, _2); + using InputDomain = _1; + + template + VTKM_EXEC vtkm::Id operator()(vtkm::Id needle, const HaystackPortal& haystack) const + { + return vtkm::LowerBound(haystack, needle); + } + }; + + static void Run() + { + IdArray needles = vtkm::cont::make_ArrayHandle({ -4, -3, -2, -1, 0, 1, 2, 3, 4, 5 }); + IdArray haystack = + vtkm::cont::make_ArrayHandle({ -3, -2, -2, -2, 0, 0, 1, 1, 1, 4, 4 }); + IdArray results; + + std::vector expected{ 0, 0, 1, 4, 4, 6, 9, 9, 9, 11 }; + + vtkm::cont::Invoker invoke; + invoke(Impl{}, needles, haystack, results); + + // Verify: + auto resultsPortal = results.ReadPortal(); + for (vtkm::Id i = 0; i < needles.GetNumberOfValues(); ++i) + { + VTKM_TEST_ASSERT(resultsPortal.Get(i) == expected[static_cast(i)]); + } + } +}; + +struct TestUpperBound +{ + struct Impl : public vtkm::worklet::WorkletMapField + { + using ControlSignature = void(FieldIn needles, WholeArrayIn haystack, FieldOut results); + using ExecutionSignature = _3(_1, _2); + using InputDomain = _1; + + template + VTKM_EXEC vtkm::Id operator()(vtkm::Id needle, const HaystackPortal& haystack) const + { + return vtkm::UpperBound(haystack, needle); + } + }; + + static void Run() + { + IdArray needles = vtkm::cont::make_ArrayHandle({ -4, -3, -2, -1, 0, 1, 2, 3, 4, 5 }); + IdArray haystack = + vtkm::cont::make_ArrayHandle({ -3, -2, -2, -2, 0, 0, 1, 1, 1, 4, 4 }); + IdArray results; + + std::vector expected{ 0, 1, 4, 4, 6, 9, 9, 9, 11, 11 }; + + vtkm::cont::Invoker invoke; + invoke(Impl{}, needles, haystack, results); + + // Verify: + auto resultsPortal = results.ReadPortal(); + for (vtkm::Id i = 0; i < needles.GetNumberOfValues(); ++i) + { + VTKM_TEST_ASSERT(resultsPortal.Get(i) == expected[static_cast(i)]); + } + } +}; + +void RunAlgorithmsTests() +{ + std::cout << "Testing binary search." << std::endl; + TestBinarySearch::Run(); + std::cout << "Testing lower bound." << std::endl; + TestLowerBound::Run(); + std::cout << "Testing upper bound." << std::endl; + TestUpperBound::Run(); +} + +} // anon namespace int UnitTestAlgorithms(int argc, char* argv[]) { - return vtkm::testing::Testing::Run( - RunAlgorithmsTests, argc, argv); + return vtkm::cont::testing::Testing::Run(RunAlgorithmsTests, argc, argv); } diff --git a/vtkm/testing/TestingGeometry.h b/vtkm/testing/UnitTestGeometry.cxx similarity index 94% rename from vtkm/testing/TestingGeometry.h rename to vtkm/testing/UnitTestGeometry.cxx index 35d7379fa..560659628 100644 --- a/vtkm/testing/TestingGeometry.h +++ b/vtkm/testing/UnitTestGeometry.cxx @@ -7,8 +7,6 @@ // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notice for more information. //============================================================================ -#ifndef vtk_m_testing_TestingGeometry_h -#define vtk_m_testing_TestingGeometry_h #include #include @@ -18,7 +16,7 @@ #include -#include +#include #include @@ -29,7 +27,7 @@ } //----------------------------------------------------------------------------- -namespace UnitTestGeometryNamespace +namespace { class Coords @@ -126,13 +124,12 @@ struct RayTests : public vtkm::exec::FunctorBase } }; -template struct TryRayTests { template void operator()(const T&) const { - vtkm::cont::DeviceAdapterAlgorithm::Schedule(RayTests(), 1); + vtkm::cont::Algorithm::Schedule(RayTests(), 1); } }; @@ -215,13 +212,12 @@ struct LineSegmentTests : public vtkm::exec::FunctorBase } }; -template struct TryLineSegmentTests { template void operator()(const T&) const { - vtkm::cont::DeviceAdapterAlgorithm::Schedule(LineSegmentTests(), 1); + vtkm::cont::Algorithm::Schedule(LineSegmentTests(), 1); } }; @@ -349,13 +345,12 @@ struct PlaneTests : public vtkm::exec::FunctorBase } }; -template struct TryPlaneTests { template void operator()(const T&) const { - vtkm::cont::DeviceAdapterAlgorithm::Schedule(PlaneTests(), 1); + vtkm::cont::Algorithm::Schedule(PlaneTests(), 1); } }; @@ -457,30 +452,31 @@ struct SphereTests : public vtkm::exec::FunctorBase } }; -template struct TrySphereTests { template void operator()(const T&) const { - vtkm::cont::DeviceAdapterAlgorithm::Schedule(SphereTests(), 1); + vtkm::cont::Algorithm::Schedule(SphereTests(), 1); } }; //----------------------------------------------------------------------------- -template void RunGeometryTests() { std::cout << "Tests for rays." << std::endl; - vtkm::testing::Testing::TryTypes(TryRayTests(), vtkm::TypeListFieldScalar()); + vtkm::testing::Testing::TryTypes(TryRayTests(), vtkm::TypeListFieldScalar()); std::cout << "Tests for line segments." << std::endl; - vtkm::testing::Testing::TryTypes(TryLineSegmentTests(), vtkm::TypeListFieldScalar()); + vtkm::testing::Testing::TryTypes(TryLineSegmentTests(), vtkm::TypeListFieldScalar()); std::cout << "Tests for planes." << std::endl; - vtkm::testing::Testing::TryTypes(TryPlaneTests(), vtkm::TypeListFieldScalar()); + vtkm::testing::Testing::TryTypes(TryPlaneTests(), vtkm::TypeListFieldScalar()); std::cout << "Tests for spheres." << std::endl; - vtkm::testing::Testing::TryTypes(TrySphereTests(), vtkm::TypeListFieldScalar()); + vtkm::testing::Testing::TryTypes(TrySphereTests(), vtkm::TypeListFieldScalar()); } -} // namespace UnitTestGeometryNamespace +} // anonymous namespace -#endif //vtk_m_testing_TestingGeometry_h +int UnitTestGeometry(int argc, char* argv[]) +{ + return vtkm::cont::testing::Testing::Run(RunGeometryTests, argc, argv); +} diff --git a/vtkm/testing/UnitTestMath.cxx b/vtkm/testing/UnitTestMath.cxx index 79f7ad2b6..cf7ca7a21 100644 --- a/vtkm/testing/UnitTestMath.cxx +++ b/vtkm/testing/UnitTestMath.cxx @@ -7,14 +7,1084 @@ // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notice for more information. //============================================================================ +#include -#include -#include +#include +#include -#include +#include + +#include + +#include + +#include + +#define VTKM_MATH_ASSERT(condition, message) \ + if (!(condition)) \ + { \ + this->RaiseError(message); \ + } + +//----------------------------------------------------------------------------- +namespace UnitTestMathNamespace +{ + +class Lists +{ +public: + static constexpr vtkm::IdComponent NUM_NUMBERS = 5; + + VTKM_EXEC_CONT vtkm::Float64 NumberList(vtkm::Int32 i) const + { + vtkm::Float64 numberList[NUM_NUMBERS] = { 0.25, 0.5, 1.0, 2.0, 3.75 }; + return numberList[i]; + } + VTKM_EXEC_CONT vtkm::Float64 AngleList(vtkm::Int32 i) const + { + vtkm::Float64 angleList[NUM_NUMBERS] = { 0.643501108793284, // angle for 3, 4, 5 triangle. + 0.78539816339745, // pi/4 + 0.5235987755983, // pi/6 + 1.0471975511966, // pi/3 + 0.0 }; + return angleList[i]; + } + VTKM_EXEC_CONT vtkm::Float64 OppositeList(vtkm::Int32 i) const + { + vtkm::Float64 oppositeList[NUM_NUMBERS] = { 3.0, 1.0, 1.0, 1.732050807568877 /*sqrt(3)*/, 0.0 }; + return oppositeList[i]; + } + VTKM_EXEC_CONT vtkm::Float64 AdjacentList(vtkm::Int32 i) const + { + vtkm::Float64 adjacentList[NUM_NUMBERS] = { 4.0, 1.0, 1.732050807568877 /*sqrt(3)*/, 1.0, 1.0 }; + return adjacentList[i]; + } + VTKM_EXEC_CONT vtkm::Float64 HypotenuseList(vtkm::Int32 i) const + { + vtkm::Float64 hypotenuseList[NUM_NUMBERS] = { + 5.0, 1.414213562373095 /*sqrt(2)*/, 2.0, 2.0, 1.0 + }; + return hypotenuseList[i]; + } + VTKM_EXEC_CONT vtkm::Float64 NumeratorList(vtkm::Int32 i) const + { + vtkm::Float64 numeratorList[NUM_NUMBERS] = { 6.5, 5.8, 9.3, 77.0, 0.1 }; + return numeratorList[i]; + } + VTKM_EXEC_CONT vtkm::Float64 DenominatorList(vtkm::Int32 i) const + { + vtkm::Float64 denominatorList[NUM_NUMBERS] = { 2.3, 1.6, 3.1, 19.0, 0.4 }; + return denominatorList[i]; + } + VTKM_EXEC_CONT vtkm::Float64 FModRemainderList(vtkm::Int32 i) const + { + vtkm::Float64 fModRemainderList[NUM_NUMBERS] = { 1.9, 1.0, 0.0, 1.0, 0.1 }; + return fModRemainderList[i]; + } + VTKM_EXEC_CONT vtkm::Float64 RemainderList(vtkm::Int32 i) const + { + vtkm::Float64 remainderList[NUM_NUMBERS] = { -0.4, -0.6, 0.0, 1.0, 0.1 }; + return remainderList[i]; + } + VTKM_EXEC_CONT vtkm::Int64 QuotientList(vtkm::Int32 i) const + { + vtkm::Int64 quotientList[NUM_NUMBERS] = { 3, 4, 3, 4, 0 }; + return quotientList[i]; + } + VTKM_EXEC_CONT vtkm::Float64 XList(vtkm::Int32 i) const + { + vtkm::Float64 xList[NUM_NUMBERS] = { 4.6, 0.1, 73.4, 55.0, 3.75 }; + return xList[i]; + } + VTKM_EXEC_CONT vtkm::Float64 FractionalList(vtkm::Int32 i) const + { + vtkm::Float64 fractionalList[NUM_NUMBERS] = { 0.6, 0.1, 0.4, 0.0, 0.75 }; + return fractionalList[i]; + } + VTKM_EXEC_CONT vtkm::Float64 FloorList(vtkm::Int32 i) const + { + vtkm::Float64 floorList[NUM_NUMBERS] = { 4.0, 0.0, 73.0, 55.0, 3.0 }; + return floorList[i]; + } + VTKM_EXEC_CONT vtkm::Float64 CeilList(vtkm::Int32 i) const + { + vtkm::Float64 ceilList[NUM_NUMBERS] = { 5.0, 1.0, 74.0, 55.0, 4.0 }; + return ceilList[i]; + } + VTKM_EXEC_CONT vtkm::Float64 RoundList(vtkm::Int32 i) const + { + vtkm::Float64 roundList[NUM_NUMBERS] = { 5.0, 0.0, 73.0, 55.0, 4.0 }; + return roundList[i]; + } +}; + +//----------------------------------------------------------------------------- +template +struct ScalarFieldTests : public vtkm::exec::FunctorBase +{ + VTKM_EXEC + void TestPi() const + { + // std::cout << "Testing Pi" << std::endl; + VTKM_MATH_ASSERT(test_equal(vtkm::Pi(), 3.14159265), "Pi not correct."); + VTKM_MATH_ASSERT(test_equal(vtkm::Pif(), 3.14159265f), "Pif not correct."); + VTKM_MATH_ASSERT(test_equal(vtkm::Pi(), 3.14159265), + "Pi template function not correct."); + } + + VTKM_EXEC + void TestArcTan2() const + { + // std::cout << "Testing arc tan 2" << std::endl; + + VTKM_MATH_ASSERT(test_equal(vtkm::ATan2(T(0.0), T(1.0)), T(0.0)), "ATan2 x+ axis."); + VTKM_MATH_ASSERT(test_equal(vtkm::ATan2(T(1.0), T(0.0)), T(0.5 * vtkm::Pi())), + "ATan2 y+ axis."); + VTKM_MATH_ASSERT(test_equal(vtkm::ATan2(T(-1.0), T(0.0)), T(-0.5 * vtkm::Pi())), + "ATan2 y- axis."); + + VTKM_MATH_ASSERT(test_equal(vtkm::ATan2(T(1.0), T(1.0)), T(0.25 * vtkm::Pi())), + "ATan2 Quadrant 1"); + VTKM_MATH_ASSERT(test_equal(vtkm::ATan2(T(1.0), T(-1.0)), T(0.75 * vtkm::Pi())), + "ATan2 Quadrant 2"); + VTKM_MATH_ASSERT(test_equal(vtkm::ATan2(T(-1.0), T(-1.0)), T(-0.75 * vtkm::Pi())), + "ATan2 Quadrant 3"); + VTKM_MATH_ASSERT(test_equal(vtkm::ATan2(T(-1.0), T(1.0)), T(-0.25 * vtkm::Pi())), + "ATan2 Quadrant 4"); + } + + VTKM_EXEC + void TestPow() const + { + // std::cout << "Running power tests." << std::endl; + for (vtkm::IdComponent index = 0; index < Lists::NUM_NUMBERS; index++) + { + T x = static_cast(Lists{}.NumberList(index)); + T powx = vtkm::Pow(x, static_cast(2.0)); + T sqrx = x * x; + VTKM_MATH_ASSERT(test_equal(powx, sqrx), "Power gave wrong result."); + } + } + + VTKM_EXEC + void TestLog2() const + { + // std::cout << "Testing Log2" << std::endl; + VTKM_MATH_ASSERT(test_equal(vtkm::Log2(T(0.25)), T(-2.0)), "Bad value from Log2"); + VTKM_MATH_ASSERT(test_equal(vtkm::Log2(vtkm::Vec(0.5, 1.0, 2.0, 4.0)), + vtkm::Vec(-1.0, 0.0, 1.0, 2.0)), + "Bad value from Log2"); + } + + VTKM_EXEC + void TestNonFinites() const + { + // std::cout << "Testing non-finites." << std::endl; + + T zero = 0.0; + T finite = 1.0; + T nan = vtkm::Nan(); + T inf = vtkm::Infinity(); + T neginf = vtkm::NegativeInfinity(); + T epsilon = vtkm::Epsilon(); + + // General behavior. + VTKM_MATH_ASSERT(nan != vtkm::Nan(), "Nan not equal itself."); + VTKM_MATH_ASSERT(!(nan >= zero), "Nan not greater or less."); + VTKM_MATH_ASSERT(!(nan <= zero), "Nan not greater or less."); + VTKM_MATH_ASSERT(!(nan >= finite), "Nan not greater or less."); + VTKM_MATH_ASSERT(!(nan <= finite), "Nan not greater or less."); + + VTKM_MATH_ASSERT(neginf < inf, "Infinity big"); + VTKM_MATH_ASSERT(zero < inf, "Infinity big"); + VTKM_MATH_ASSERT(finite < inf, "Infinity big"); + VTKM_MATH_ASSERT(zero > -inf, "-Infinity small"); + VTKM_MATH_ASSERT(finite > -inf, "-Infinity small"); + VTKM_MATH_ASSERT(zero > neginf, "-Infinity small"); + VTKM_MATH_ASSERT(finite > neginf, "-Infinity small"); + + VTKM_MATH_ASSERT(zero < epsilon, "Negative epsilon"); + VTKM_MATH_ASSERT(finite > epsilon, "Large epsilon"); + + // Math check functions. + VTKM_MATH_ASSERT(!vtkm::IsNan(zero), "Bad IsNan check."); + VTKM_MATH_ASSERT(!vtkm::IsNan(finite), "Bad IsNan check."); + VTKM_MATH_ASSERT(vtkm::IsNan(nan), "Bad IsNan check."); + VTKM_MATH_ASSERT(!vtkm::IsNan(inf), "Bad IsNan check."); + VTKM_MATH_ASSERT(!vtkm::IsNan(neginf), "Bad IsNan check."); + VTKM_MATH_ASSERT(!vtkm::IsNan(epsilon), "Bad IsNan check."); + + VTKM_MATH_ASSERT(!vtkm::IsInf(zero), "Bad infinity check."); + VTKM_MATH_ASSERT(!vtkm::IsInf(finite), "Bad infinity check."); + VTKM_MATH_ASSERT(!vtkm::IsInf(nan), "Bad infinity check."); + VTKM_MATH_ASSERT(vtkm::IsInf(inf), "Bad infinity check."); + VTKM_MATH_ASSERT(vtkm::IsInf(neginf), "Bad infinity check."); + VTKM_MATH_ASSERT(!vtkm::IsInf(epsilon), "Bad infinity check."); + + VTKM_MATH_ASSERT(vtkm::IsFinite(zero), "Bad finite check."); + VTKM_MATH_ASSERT(vtkm::IsFinite(finite), "Bad finite check."); + VTKM_MATH_ASSERT(!vtkm::IsFinite(nan), "Bad finite check."); + VTKM_MATH_ASSERT(!vtkm::IsFinite(inf), "Bad finite check."); + VTKM_MATH_ASSERT(!vtkm::IsFinite(neginf), "Bad finite check."); + VTKM_MATH_ASSERT(vtkm::IsFinite(epsilon), "Bad finite check."); + } + + VTKM_EXEC + void TestRemainders() const + { + // std::cout << "Testing remainders." << std::endl; + Lists table; + for (vtkm::IdComponent index = 0; index < Lists::NUM_NUMBERS; index++) + { + T numerator = static_cast(table.NumeratorList(index)); + T denominator = static_cast(table.DenominatorList(index)); + T fmodremainder = static_cast(table.FModRemainderList(index)); + T remainder = static_cast(table.RemainderList(index)); + vtkm::Int64 quotient = table.QuotientList(index); + + VTKM_MATH_ASSERT(test_equal(vtkm::FMod(numerator, denominator), fmodremainder), + "Bad FMod remainder."); + VTKM_MATH_ASSERT(test_equal(vtkm::Remainder(numerator, denominator), remainder), + "Bad remainder."); + vtkm::Int64 q; + VTKM_MATH_ASSERT(test_equal(vtkm::RemainderQuotient(numerator, denominator, q), remainder), + "Bad remainder-quotient remainder."); + VTKM_MATH_ASSERT(test_equal(q, quotient), "Bad reminder-quotient quotient."); + } + } + + VTKM_EXEC + void TestRound() const + { + // std::cout << "Testing round." << std::endl; + Lists table; + for (vtkm::IdComponent index = 0; index < Lists::NUM_NUMBERS; index++) + { + T x = static_cast(table.XList(index)); + T fractional = static_cast(table.FractionalList(index)); + T floor = static_cast(table.FloorList(index)); + T ceil = static_cast(table.CeilList(index)); + T round = static_cast(table.RoundList(index)); + + T intPart; + VTKM_MATH_ASSERT(test_equal(vtkm::ModF(x, intPart), fractional), + "ModF returned wrong fractional part."); + VTKM_MATH_ASSERT(test_equal(intPart, floor), "ModF returned wrong integral part."); + VTKM_MATH_ASSERT(test_equal(vtkm::Floor(x), floor), "Bad floor."); + VTKM_MATH_ASSERT(test_equal(vtkm::Ceil(x), ceil), "Bad ceil."); + VTKM_MATH_ASSERT(test_equal(vtkm::Round(x), round), "Bad round."); + } + } + + VTKM_EXEC + void TestIsNegative() const + { + // std::cout << "Testing SignBit and IsNegative." << std::endl; + T x = 0; + VTKM_MATH_ASSERT(vtkm::SignBit(x) == 0, "SignBit wrong for 0."); + VTKM_MATH_ASSERT(!vtkm::IsNegative(x), "IsNegative wrong for 0."); + + x = 20; + VTKM_MATH_ASSERT(vtkm::SignBit(x) == 0, "SignBit wrong for 20."); + VTKM_MATH_ASSERT(!vtkm::IsNegative(x), "IsNegative wrong for 20."); + + x = -20; + VTKM_MATH_ASSERT(vtkm::SignBit(x) != 0, "SignBit wrong for -20."); + VTKM_MATH_ASSERT(vtkm::IsNegative(x), "IsNegative wrong for -20."); + + x = 0.02f; + VTKM_MATH_ASSERT(vtkm::SignBit(x) == 0, "SignBit wrong for 0.02."); + VTKM_MATH_ASSERT(!vtkm::IsNegative(x), "IsNegative wrong for 0.02."); + + x = -0.02f; + VTKM_MATH_ASSERT(vtkm::SignBit(x) != 0, "SignBit wrong for -0.02."); + VTKM_MATH_ASSERT(vtkm::IsNegative(x), "IsNegative wrong for -0.02."); + } + + VTKM_EXEC + void operator()(vtkm::Id) const + { + this->TestPi(); + this->TestArcTan2(); + this->TestPow(); + this->TestLog2(); + this->TestNonFinites(); + this->TestRemainders(); + this->TestRound(); + this->TestIsNegative(); + } +}; + +struct TryScalarFieldTests +{ + template + void operator()(const T&) const + { + vtkm::cont::Algorithm::Schedule(ScalarFieldTests(), 1); + } +}; + +//----------------------------------------------------------------------------- +template +struct ScalarVectorFieldTests : public vtkm::exec::FunctorBase +{ + using Traits = vtkm::VecTraits; + using ComponentType = typename Traits::ComponentType; + enum + { + NUM_COMPONENTS = Traits::NUM_COMPONENTS + }; + + VTKM_EXEC + void TestTriangleTrig() const + { + // std::cout << "Testing normal trig functions." << std::endl; + Lists table; + for (vtkm::IdComponent index = 0; index < Lists::NUM_NUMBERS - NUM_COMPONENTS + 1; index++) + { + VectorType angle; + VectorType opposite; + VectorType adjacent; + VectorType hypotenuse; + for (vtkm::IdComponent componentIndex = 0; componentIndex < NUM_COMPONENTS; componentIndex++) + { + Traits::SetComponent(angle, + componentIndex, + static_cast(table.AngleList(componentIndex + index))); + Traits::SetComponent( + opposite, + componentIndex, + static_cast(table.OppositeList(componentIndex + index))); + Traits::SetComponent( + adjacent, + componentIndex, + static_cast(table.AdjacentList(componentIndex + index))); + Traits::SetComponent( + hypotenuse, + componentIndex, + static_cast(table.HypotenuseList(componentIndex + index))); + } + + VTKM_MATH_ASSERT(test_equal(vtkm::Sin(angle), opposite / hypotenuse), "Sin failed test."); + VTKM_MATH_ASSERT(test_equal(vtkm::Cos(angle), adjacent / hypotenuse), "Cos failed test."); + VTKM_MATH_ASSERT(test_equal(vtkm::Tan(angle), opposite / adjacent), "Tan failed test."); + + VTKM_MATH_ASSERT(test_equal(vtkm::ASin(opposite / hypotenuse), angle), + "Arc Sin failed test."); + +#if defined(VTKM_ICC) + // When the intel compiler has vectorization enabled ( -O2/-O3 ) it converts the + // `adjacent/hypotenuse` divide operation into reciprocal (rcpps) and + // multiply (mulps) operations. This causes a change in the expected result that + // is larger than the default tolerance of test_equal. + // + VTKM_MATH_ASSERT(test_equal(vtkm::ACos(adjacent / hypotenuse), angle, 0.0004), + "Arc Cos failed test."); +#else + VTKM_MATH_ASSERT(test_equal(vtkm::ACos(adjacent / hypotenuse), angle), + "Arc Cos failed test."); +#endif + VTKM_MATH_ASSERT(test_equal(vtkm::ATan(opposite / adjacent), angle), "Arc Tan failed test."); + } + } + + VTKM_EXEC + void TestHyperbolicTrig() const + { + // std::cout << "Testing hyperbolic trig functions." << std::endl; + + const VectorType zero(0); + Lists table; + for (vtkm::IdComponent index = 0; index < Lists::NUM_NUMBERS - NUM_COMPONENTS + 1; index++) + { + VectorType x; + for (vtkm::IdComponent componentIndex = 0; componentIndex < NUM_COMPONENTS; componentIndex++) + { + Traits::SetComponent( + x, componentIndex, static_cast(table.AngleList(componentIndex + index))); + } + + const VectorType minusX = zero - x; + + VTKM_MATH_ASSERT(test_equal(vtkm::SinH(x), 0.5 * (vtkm::Exp(x) - vtkm::Exp(minusX))), + "SinH does not match definition."); + VTKM_MATH_ASSERT(test_equal(vtkm::CosH(x), 0.5 * (vtkm::Exp(x) + vtkm::Exp(minusX))), + "SinH does not match definition."); + VTKM_MATH_ASSERT(test_equal(vtkm::TanH(x), vtkm::SinH(x) / vtkm::CosH(x)), + "TanH does not match definition"); + + VTKM_MATH_ASSERT(test_equal(vtkm::ASinH(vtkm::SinH(x)), x), "SinH not inverting."); + VTKM_MATH_ASSERT(test_equal(vtkm::ACosH(vtkm::CosH(x)), x), "CosH not inverting."); + VTKM_MATH_ASSERT(test_equal(vtkm::ATanH(vtkm::TanH(x)), x), "TanH not inverting."); + } + } + + template + VTKM_EXEC void RaiseToTest(FunctionType function, ComponentType exponent) const + { + Lists table; + for (vtkm::IdComponent index = 0; index < Lists::NUM_NUMBERS - NUM_COMPONENTS + 1; index++) + { + VectorType original; + VectorType raiseresult; + for (vtkm::IdComponent componentIndex = 0; componentIndex < NUM_COMPONENTS; componentIndex++) + { + ComponentType x = static_cast(table.NumberList(componentIndex + index)); + Traits::SetComponent(original, componentIndex, x); + Traits::SetComponent(raiseresult, componentIndex, vtkm::Pow(x, exponent)); + } + + VectorType mathresult = function(original); + + VTKM_MATH_ASSERT(test_equal(mathresult, raiseresult), "Exponent functions do not agree."); + } + } + + struct SqrtFunctor + { + VTKM_EXEC + VectorType operator()(VectorType x) const { return vtkm::Sqrt(x); } + }; + VTKM_EXEC + void TestSqrt() const + { + // std::cout << " Testing Sqrt" << std::endl; + RaiseToTest(SqrtFunctor(), 0.5); + } + + struct RSqrtFunctor + { + VTKM_EXEC + VectorType operator()(VectorType x) const { return vtkm::RSqrt(x); } + }; + VTKM_EXEC + void TestRSqrt() const + { + // std::cout << " Testing RSqrt"<< std::endl; + RaiseToTest(RSqrtFunctor(), -0.5); + } + + struct CbrtFunctor + { + VTKM_EXEC + VectorType operator()(VectorType x) const { return vtkm::Cbrt(x); } + }; + VTKM_EXEC + void TestCbrt() const + { + // std::cout << " Testing Cbrt" << std::endl; + RaiseToTest(CbrtFunctor(), vtkm::Float32(1.0 / 3.0)); + } + + struct RCbrtFunctor + { + VTKM_EXEC + VectorType operator()(VectorType x) const { return vtkm::RCbrt(x); } + }; + VTKM_EXEC + void TestRCbrt() const + { + // std::cout << " Testing RCbrt" << std::endl; + RaiseToTest(RCbrtFunctor(), vtkm::Float32(-1.0 / 3.0)); + } + + template + VTKM_EXEC void RaiseByTest(FunctionType function, + ComponentType base, + ComponentType exponentbias = 0.0, + ComponentType resultbias = 0.0) const + { + Lists table; + for (vtkm::IdComponent index = 0; index < Lists::NUM_NUMBERS - NUM_COMPONENTS + 1; index++) + { + VectorType original; + VectorType raiseresult; + for (vtkm::IdComponent componentIndex = 0; componentIndex < NUM_COMPONENTS; componentIndex++) + { + ComponentType x = static_cast(table.NumberList(componentIndex + index)); + Traits::SetComponent(original, componentIndex, x); + Traits::SetComponent( + raiseresult, componentIndex, vtkm::Pow(base, x + exponentbias) + resultbias); + } + + VectorType mathresult = function(original); + + VTKM_MATH_ASSERT(test_equal(mathresult, raiseresult), "Exponent functions do not agree."); + } + } + + struct ExpFunctor + { + VTKM_EXEC + VectorType operator()(VectorType x) const { return vtkm::Exp(x); } + }; + VTKM_EXEC + void TestExp() const + { + // std::cout << " Testing Exp" << std::endl; + RaiseByTest(ExpFunctor(), vtkm::Float32(2.71828183)); + } + + struct Exp2Functor + { + VTKM_EXEC + VectorType operator()(VectorType x) const { return vtkm::Exp2(x); } + }; + VTKM_EXEC + void TestExp2() const + { + // std::cout << " Testing Exp2" << std::endl; + RaiseByTest(Exp2Functor(), 2.0); + } + + struct ExpM1Functor + { + VTKM_EXEC + VectorType operator()(VectorType x) const { return vtkm::ExpM1(x); } + }; + VTKM_EXEC + void TestExpM1() const + { + // std::cout << " Testing ExpM1" << std::endl; + RaiseByTest(ExpM1Functor(), ComponentType(2.71828183), 0.0, -1.0); + } + + struct Exp10Functor + { + VTKM_EXEC + VectorType operator()(VectorType x) const { return vtkm::Exp10(x); } + }; + VTKM_EXEC + void TestExp10() const + { + // std::cout << " Testing Exp10" << std::endl; + RaiseByTest(Exp10Functor(), 10.0); + } + + template + VTKM_EXEC void LogBaseTest(FunctionType function, + ComponentType base, + ComponentType bias = 0.0) const + { + Lists table; + for (vtkm::IdComponent index = 0; index < Lists::NUM_NUMBERS - NUM_COMPONENTS + 1; index++) + { + VectorType basevector(base); + VectorType original; + VectorType biased; + for (vtkm::IdComponent componentIndex = 0; componentIndex < NUM_COMPONENTS; componentIndex++) + { + ComponentType x = static_cast(table.NumberList(componentIndex + index)); + Traits::SetComponent(original, componentIndex, x); + Traits::SetComponent(biased, componentIndex, x + bias); + } + + VectorType logresult = vtkm::Log2(biased) / vtkm::Log2(basevector); + + VectorType mathresult = function(original); + + VTKM_MATH_ASSERT(test_equal(mathresult, logresult), "Exponent functions do not agree."); + } + } + + struct LogFunctor + { + VTKM_EXEC + VectorType operator()(VectorType x) const { return vtkm::Log(x); } + }; + VTKM_EXEC + void TestLog() const + { + // std::cout << " Testing Log" << std::endl; + LogBaseTest(LogFunctor(), vtkm::Float32(2.71828183)); + } + + struct Log10Functor + { + VTKM_EXEC + VectorType operator()(VectorType x) const { return vtkm::Log10(x); } + }; + VTKM_EXEC + void TestLog10() const + { + // std::cout << " Testing Log10" << std::endl; + LogBaseTest(Log10Functor(), 10.0); + } + + struct Log1PFunctor + { + VTKM_EXEC + VectorType operator()(VectorType x) const { return vtkm::Log1P(x); } + }; + VTKM_EXEC + void TestLog1P() const + { + // std::cout << " Testing Log1P" << std::endl; + LogBaseTest(Log1PFunctor(), ComponentType(2.71828183), 1.0); + } + + VTKM_EXEC + void TestCopySign() const + { + // std::cout << "Testing CopySign." << std::endl; + // Assuming all TestValues positive. + VectorType positive1 = TestValue(1, VectorType()); + VectorType positive2 = TestValue(2, VectorType()); + VectorType negative1 = -positive1; + VectorType negative2 = -positive2; + + VTKM_MATH_ASSERT(test_equal(vtkm::CopySign(positive1, positive2), positive1), + "CopySign failed."); + VTKM_MATH_ASSERT(test_equal(vtkm::CopySign(negative1, positive2), positive1), + "CopySign failed."); + VTKM_MATH_ASSERT(test_equal(vtkm::CopySign(positive1, negative2), negative1), + "CopySign failed."); + VTKM_MATH_ASSERT(test_equal(vtkm::CopySign(negative1, negative2), negative1), + "CopySign failed."); + } + + VTKM_EXEC + void TestFloatDistance() const + { + { + vtkm::UInt64 dist = vtkm::FloatDistance(1.0, 1.0); + VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(0), dist), + "Float distance from 1.0 to 1.0 is not zero."); + + dist = vtkm::FloatDistance(-1.0, -1.0); + VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(0), dist), + "Float distance from -1.0 to -1.0 is not zero."); + + dist = vtkm::FloatDistance(0.0, 0.0); + VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(0), dist), + "Float distance from 0.0 to 0.0 is not zero."); + + // Check nan: + dist = vtkm::FloatDistance(std::numeric_limits::quiet_NaN(), 1.0); + VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(0xFFFFFFFFFFFFFFFFL), dist), + "Float distance to a Nan is not the documented value."); + + dist = vtkm::FloatDistance(1.0, std::numeric_limits::quiet_NaN()); + VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(0xFFFFFFFFFFFFFFFFL), dist), + "Float distance to a Nan is not the documented value."); + + // Check infinity: + dist = vtkm::FloatDistance(std::numeric_limits::infinity(), 1.0); + VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(0xFFFFFFFFFFFFFFFFL), dist), + "Float distance to infinity is not the documented value."); + + dist = vtkm::FloatDistance(1.0, std::numeric_limits::infinity()); + VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(0xFFFFFFFFFFFFFFFFL), dist), + "Float distance to infinity is not the documented value."); + + // Check saturation: + dist = vtkm::FloatDistance(std::numeric_limits::lowest(), + std::numeric_limits::max()); + VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(18437736874454810622uL), dist), + "Float distance from lowest to max is incorrect."); + + dist = vtkm::FloatDistance(std::numeric_limits::max(), + std::numeric_limits::lowest()); + VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(18437736874454810622uL), dist), + "Float distance from max to lowest is incorrect."); + + // Check symmetry: + dist = vtkm::FloatDistance(-2.0, -1.0); + vtkm::UInt64 dist2 = vtkm::FloatDistance(-1.0, -2.0); + VTKM_MATH_ASSERT(test_equal(dist2, dist), "Symmetry of negative numbers does not hold."); + + dist = vtkm::FloatDistance(1.0, 2.0); + dist2 = vtkm::FloatDistance(2.0, 1.0); + VTKM_MATH_ASSERT(test_equal(dist2, dist), "Float distance 1->2 != float distance 2->1."); + + // Check symmetry of bound which includes zero: + dist = vtkm::FloatDistance(-0.25, 0.25); + dist2 = vtkm::FloatDistance(0.25, -0.25); + VTKM_MATH_ASSERT(test_equal(dist2, dist), + "Symmetry is violated over a bound which contains zero."); + + // Check correctness: + dist = vtkm::FloatDistance(1.0, 1.0 + std::numeric_limits::epsilon()); + VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(1), dist), + "Float distance from 1 to 1 + eps is not = 1."); + dist = vtkm::FloatDistance(1.0 + std::numeric_limits::epsilon(), 1.0); + VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(1), dist), "Symmetry is violated"); + + dist = vtkm::FloatDistance(1.0, 1.0 + 2 * std::numeric_limits::epsilon()); + VTKM_MATH_ASSERT(test_equal(vtkm::Int64(2), dist), + "Float distance from 1 to 1 + 2eps is not 2."); + dist = vtkm::FloatDistance(1.0 + 2 * std::numeric_limits::epsilon(), 1.0); + VTKM_MATH_ASSERT(test_equal(vtkm::Int64(2), dist), "Symmetry is violated."); + + // Now test x = y: + vtkm::Float64 x = -1; + for (int i = 0; i < 500; ++i) + { + dist = vtkm::FloatDistance(x, x); + VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(0), dist), + "Float distance from x to x is not zero."); + x += 0.01; + } + // Test zero: + dist = vtkm::FloatDistance(0.0, 0.0); + VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(0), dist), + "Float distance from zero to zero is not zero."); + // Test signed zero: + dist = vtkm::FloatDistance(0.0, -0.0); + VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(0), dist), + "Float distance from 0.0 to -0.0 is not zero."); + + dist = vtkm::FloatDistance(-0.0, 0.0); + VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(0), dist), + "Float distance from -0.0 to 0.0 is not zero."); + + dist = vtkm::FloatDistance(-0.0, -0.0); + VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(0), dist), + "Float distance from -0.0 to 0.0 is not zero."); + + // Negative to negative zero: + dist = vtkm::FloatDistance(-std::numeric_limits::denorm_min(), -0.0); + VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(1), dist), "Negative to zero incorrect."); + // And symmetry: + dist = vtkm::FloatDistance(-0.0, -std::numeric_limits::denorm_min()); + VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(1), dist), "Symmetry is violated."); + + // Negative to positive zero: + dist = vtkm::FloatDistance(-std::numeric_limits::denorm_min(), 0.0); + VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(1), dist), + "Negative to positive zero is incorrect."); + // And symmetry: + dist = vtkm::FloatDistance(0.0, -std::numeric_limits::denorm_min()); + VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(1), dist), "Symmetry is violated."); + + // Positive to zero: + dist = vtkm::FloatDistance(std::numeric_limits::denorm_min(), 0.0); + VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(1), dist), "Positive to zero is incorrect."); + // And symmetry: + dist = vtkm::FloatDistance(0.0, std::numeric_limits::denorm_min()); + VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(1), dist), "Symmetry is violated"); + + // Positive to negative zero: + dist = vtkm::FloatDistance(std::numeric_limits::denorm_min(), -0.0); + VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(1), dist), + "Positive to negative zero is incorrect."); + // And symmetry: + dist = vtkm::FloatDistance(-0.0, std::numeric_limits::denorm_min()); + VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(1), dist), "Symmetry is violated."); + } + + // I would try to just template these, but in fact the double precision version has to saturate, + // whereas the float version has sufficient range. + { + vtkm::UInt64 dist = vtkm::FloatDistance(1.0f, 1.0f); + VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(0), dist), + "Float distance from 1.0 to 1.0 is not zero."); + + dist = vtkm::FloatDistance(-1.0f, -1.0f); + VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(0), dist), + "Float distance from -1.0 to -1.0 is not zero."); + + dist = vtkm::FloatDistance(0.0f, 0.0f); + VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(0), dist), + "Float distance from 0.0 to 0.0 is not zero."); + + // Check nan: + dist = vtkm::FloatDistance(std::numeric_limits::quiet_NaN(), 1.0f); + VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(0xFFFFFFFFFFFFFFFFL), dist), + "Float distance to a Nan is not the documented value."); + + dist = vtkm::FloatDistance(1.0f, std::numeric_limits::quiet_NaN()); + VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(0xFFFFFFFFFFFFFFFFL), dist), + "Float distance to a Nan is not the documented value."); + + // Check infinity: + dist = vtkm::FloatDistance(std::numeric_limits::infinity(), 1.0f); + VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(0xFFFFFFFFFFFFFFFFL), dist), + "Float distance to infinity is not the documented value."); + + dist = vtkm::FloatDistance(1.0f, std::numeric_limits::infinity()); + VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(0xFFFFFFFFFFFFFFFFL), dist), + "Float distance to infinity is not the documented value."); + + // Check saturation: + dist = vtkm::FloatDistance(std::numeric_limits::lowest(), + std::numeric_limits::max()); + VTKM_MATH_ASSERT(dist > 0, "Float distance is negative."); + + dist = vtkm::FloatDistance(std::numeric_limits::max(), + std::numeric_limits::lowest()); + VTKM_MATH_ASSERT(dist > 0, "Float distance is negative."); + + // Check symmetry: + dist = vtkm::FloatDistance(-2.0f, -1.0f); + vtkm::UInt64 dist2 = vtkm::FloatDistance(-1.0f, -2.0f); + VTKM_MATH_ASSERT(test_equal(dist2, dist), "Symmetry of negative numbers does not hold."); + + dist = vtkm::FloatDistance(1.0f, 2.0f); + dist2 = vtkm::FloatDistance(2.0f, 1.0f); + VTKM_MATH_ASSERT(test_equal(dist2, dist), "Float distance 1->2 != float distance 2->1."); + + // Check symmetry of bound which includes zero: + dist = vtkm::FloatDistance(-0.25f, 0.25f); + dist2 = vtkm::FloatDistance(0.25f, -0.25f); + VTKM_MATH_ASSERT(test_equal(dist2, dist), + "Symmetry is violated over a bound which contains zero."); + + // Check correctness: + dist = vtkm::FloatDistance(1.0f, 1.0f + std::numeric_limits::epsilon()); + VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(1), dist), + "Float distance from 1 to 1 + eps is not = 1."); + dist = vtkm::FloatDistance(1.0f + std::numeric_limits::epsilon(), 1.0f); + VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(1), dist), "Symmetry is violated"); + + dist = vtkm::FloatDistance(1.0f, 1.0f + 2 * std::numeric_limits::epsilon()); + VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(2), dist), + "Float distance from 1 to 1 + 2eps is not 2."); + dist = vtkm::FloatDistance(1.0f + 2 * std::numeric_limits::epsilon(), 1.0f); + VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(2), dist), "Symmetry is violated."); + + // Now test x = y: + vtkm::Float32 x = -1; + for (int i = 0; i < 500; ++i) + { + dist = vtkm::FloatDistance(x, x); + VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(0), dist), + "Float distance from x to x is not zero."); + x += 0.01f; + } + // Test zero: + dist = vtkm::FloatDistance(0.0f, 0.0f); + VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(0), dist), + "Float distance from zero to zero is not zero."); + // Test signed zero: + dist = vtkm::FloatDistance(0.0f, -0.0f); + VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(0), dist), + "Float distance from 0.0 to -0.0 is not zero."); + + dist = vtkm::FloatDistance(-0.0f, 0.0f); + VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(0), dist), + "Float distance from -0.0 to 0.0 is not zero."); + + dist = vtkm::FloatDistance(-0.0f, -0.0f); + VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(0), dist), + "Float distance from -0.0 to 0.0 is not zero."); + + // Negative to negative zero: + dist = vtkm::FloatDistance(-std::numeric_limits::denorm_min(), -0.0f); + VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(1), dist), "Negative to zero incorrect."); + // And symmetry: + dist = vtkm::FloatDistance(-0.0f, -std::numeric_limits::denorm_min()); + VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(1), dist), "Symmetry is violated."); + + // Negative to positive zero: + dist = vtkm::FloatDistance(-std::numeric_limits::denorm_min(), 0.0f); + VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(1), dist), + "Negative to positive zero is incorrect."); + // And symmetry: + dist = vtkm::FloatDistance(0.0f, -std::numeric_limits::denorm_min()); + VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(1), dist), "Symmetry is violated."); + + // Positive to zero: + dist = vtkm::FloatDistance(std::numeric_limits::denorm_min(), 0.0f); + VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(1), dist), "Positive to zero is incorrect."); + // And symmetry: + dist = vtkm::FloatDistance(0.0f, std::numeric_limits::denorm_min()); + VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(1), dist), "Symmetry is violated"); + + // Positive to negative zero: + dist = vtkm::FloatDistance(std::numeric_limits::denorm_min(), -0.0f); + VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(1), dist), + "Positive to negative zero is incorrect."); + // And symmetry: + dist = vtkm::FloatDistance(-0.0f, std::numeric_limits::denorm_min()); + VTKM_MATH_ASSERT(test_equal(vtkm::UInt64(1), dist), "Symmetry is violated."); + } + } + + VTKM_EXEC + void operator()(vtkm::Id) const + { + this->TestTriangleTrig(); + this->TestHyperbolicTrig(); + this->TestSqrt(); + this->TestRSqrt(); + this->TestCbrt(); + this->TestRCbrt(); + this->TestExp(); + this->TestExp2(); + this->TestExpM1(); + this->TestExp10(); + this->TestLog(); + this->TestLog10(); + this->TestLog1P(); + this->TestCopySign(); + this->TestFloatDistance(); + } +}; + +struct TryScalarVectorFieldTests +{ + template + void operator()(const VectorType&) const + { + vtkm::cont::Algorithm::Schedule(ScalarVectorFieldTests(), 1); + } +}; + +//----------------------------------------------------------------------------- +template +struct AllTypesTests : public vtkm::exec::FunctorBase +{ + VTKM_EXEC + void TestMinMax() const + { + T low = TestValue(2, T()); + T high = TestValue(10, T()); + // std::cout << "Testing min/max " << low << " " << high << std::endl; + VTKM_MATH_ASSERT(test_equal(vtkm::Min(low, high), low), "Wrong min."); + VTKM_MATH_ASSERT(test_equal(vtkm::Min(high, low), low), "Wrong min."); + VTKM_MATH_ASSERT(test_equal(vtkm::Max(low, high), high), "Wrong max."); + VTKM_MATH_ASSERT(test_equal(vtkm::Max(high, low), high), "Wrong max."); + + using Traits = vtkm::VecTraits; + T mixed1 = low; + T mixed2 = high; + Traits::SetComponent(mixed1, 0, Traits::GetComponent(high, 0)); + Traits::SetComponent(mixed2, 0, Traits::GetComponent(low, 0)); + VTKM_MATH_ASSERT(test_equal(vtkm::Min(mixed1, mixed2), low), "Wrong min."); + VTKM_MATH_ASSERT(test_equal(vtkm::Min(mixed2, mixed1), low), "Wrong min."); + VTKM_MATH_ASSERT(test_equal(vtkm::Max(mixed1, mixed2), high), "Wrong max."); + VTKM_MATH_ASSERT(test_equal(vtkm::Max(mixed2, mixed1), high), "Wrong max."); + } + + VTKM_EXEC + void operator()(vtkm::Id) const { this->TestMinMax(); } +}; + +struct TryAllTypesTests +{ + template + void operator()(const T&) const + { + vtkm::cont::Algorithm::Schedule(AllTypesTests(), 1); + } +}; + +//----------------------------------------------------------------------------- +template +struct AbsTests : public vtkm::exec::FunctorBase +{ + VTKM_EXEC + void operator()(vtkm::Id index) const + { + // std::cout << "Testing Abs." << std::endl; + T positive = TestValue(index, T()); // Assuming all TestValues positive. + T negative = -positive; + + VTKM_MATH_ASSERT(test_equal(vtkm::Abs(positive), positive), "Abs returned wrong value."); + VTKM_MATH_ASSERT(test_equal(vtkm::Abs(negative), positive), "Abs returned wrong value."); + } +}; + +struct TryAbsTests +{ + template + void operator()(const T&) const + { + vtkm::cont::Algorithm::Schedule(AbsTests(), 10); + } +}; + +using TypeListAbs = + vtkm::ListAppend, vtkm::TypeListIndex, vtkm::TypeListField>; + +//----------------------------------------------------------------------------- +static constexpr vtkm::Id BitOpSamples = 1024 * 1024; + +template +struct BitOpTests : public vtkm::exec::FunctorBase +{ + static constexpr T MaxT = std::numeric_limits::max(); + static constexpr T Offset = MaxT / BitOpSamples; + + VTKM_EXEC void operator()(vtkm::Id i) const + { + const T idx = static_cast(i); + const T word = idx * this->Offset; + + TestWord(word - idx); + TestWord(word); + TestWord(word + idx); + } + + VTKM_EXEC void TestWord(T word) const + { + VTKM_MATH_ASSERT(test_equal(vtkm::CountSetBits(word), this->DumbCountBits(word)), + "CountBits returned wrong value."); + VTKM_MATH_ASSERT(test_equal(vtkm::FindFirstSetBit(word), this->DumbFindFirstSetBit(word)), + "FindFirstSetBit returned wrong value.") + } + + VTKM_EXEC vtkm::Int32 DumbCountBits(T word) const + { + vtkm::Int32 bits = 0; + while (word) + { + if (word & 0x1) + { + ++bits; + } + word >>= 1; + } + return bits; + } + + VTKM_EXEC vtkm::Int32 DumbFindFirstSetBit(T word) const + { + if (word == 0) + { + return 0; + } + + vtkm::Int32 bit = 1; + while ((word & 0x1) == 0) + { + word >>= 1; + ++bit; + } + return bit; + } +}; + +struct TryBitOpTests +{ + template + void operator()(const T&) const + { + vtkm::cont::Algorithm::Schedule(BitOpTests(), BitOpSamples); + } +}; + +using TypeListBitOp = vtkm::List; + +//----------------------------------------------------------------------------- +void RunMathTests() +{ + std::cout << "Tests for scalar types." << std::endl; + vtkm::testing::Testing::TryTypes(TryScalarFieldTests(), vtkm::TypeListFieldScalar()); + std::cout << "Test for scalar and vector types." << std::endl; + vtkm::testing::Testing::TryTypes(TryScalarVectorFieldTests(), vtkm::TypeListField()); + std::cout << "Test for exemplar types." << std::endl; + vtkm::testing::Testing::TryTypes(TryAllTypesTests()); + std::cout << "Test all Abs types" << std::endl; + vtkm::testing::Testing::TryTypes(TryAbsTests(), TypeListAbs()); + std::cout << "Test all bit operations" << std::endl; + vtkm::testing::Testing::TryTypes(TryBitOpTests(), TypeListBitOp()); +} + +} // namespace UnitTestMathNamespace int UnitTestMath(int argc, char* argv[]) { - return vtkm::testing::Testing::Run( - UnitTestMathNamespace::RunMathTests, argc, argv); + return vtkm::cont::testing::Testing::Run(UnitTestMathNamespace::RunMathTests, argc, argv); }