Merge topic 'ScanExclusiveExtend'
afe1bd12d Add `ScanExtended` device algorithm. 1480efaeb Add perf logging to DeviceAdapterAlgorithmSerial. Acked-by: Kitware Robot <kwrobot@kitware.com> Merge-request: !1824
This commit is contained in:
commit
e143eaf2e6
29
docs/changelog/scan-extended.md
Normal file
29
docs/changelog/scan-extended.md
Normal file
@ -0,0 +1,29 @@
|
||||
# A `ScanExtended` device algorithm has been added.
|
||||
|
||||
This new scan algorithm produces an array that contains both an inclusive scan
|
||||
and an exclusive scan in the same array:
|
||||
|
||||
```
|
||||
#include <vtkm/cont/Algorithm.h>
|
||||
#include <vtkm/cont/ArrayGetValue.h>
|
||||
#include <vtkm/cont/ArrayHandle.h>
|
||||
#include <vtkm/cont/ArrayHandleView.h>
|
||||
|
||||
vtkm::cont::ArrayHandle<T> inputData = ...;
|
||||
const vtkm::Id size = inputData.GetNumberOfValues();
|
||||
|
||||
vtkm::cont::ArrayHandle<T> extendedScan;
|
||||
vtkm::cont::Algorithm::ScanExtended(inputData, extendedScan);
|
||||
|
||||
// The exclusive scan is the first `inputSize` values starting at index 0:
|
||||
auto exclusiveScan = vtkm::cont::make_ArrayHandleView(extendedScan, 0, size);
|
||||
|
||||
// The inclusive scan is the first `inputSize` values starting at index 1:
|
||||
auto inclusiveScan = vtkm::cont::make_ArrayHandleView(extendedScan, 1, size);
|
||||
|
||||
// The total sum of the input data is the last value in the extended scan.
|
||||
const T totalSum = vtkm::cont::ArrayGetValue(size, extendedScan);
|
||||
```
|
||||
|
||||
This can also be thought of as an exclusive scan that appends the total sum,
|
||||
rather than returning it.
|
@ -317,6 +317,19 @@ struct ScanExclusiveByKeyFunctor
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct ScanExtendedFunctor
|
||||
{
|
||||
template <typename Device, typename... Args>
|
||||
VTKM_CONT bool operator()(Device, Args&&... args)
|
||||
{
|
||||
VTKM_IS_DEVICE_ADAPTER_TAG(Device);
|
||||
vtkm::cont::DeviceAdapterAlgorithm<Device>::ScanExtended(
|
||||
PrepareArgForExec<Device>(std::forward<Args>(args))...);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
struct ScheduleFunctor
|
||||
{
|
||||
template <typename Device, typename... Args>
|
||||
@ -976,6 +989,42 @@ struct Algorithm
|
||||
}
|
||||
|
||||
|
||||
template <typename T, class CIn, class COut>
|
||||
VTKM_CONT static void ScanExtended(vtkm::cont::DeviceAdapterId devId,
|
||||
const vtkm::cont::ArrayHandle<T, CIn>& input,
|
||||
vtkm::cont::ArrayHandle<T, COut>& output)
|
||||
{
|
||||
detail::ScanExtendedFunctor<T> functor;
|
||||
vtkm::cont::TryExecuteOnDevice(devId, functor, input, output);
|
||||
}
|
||||
template <typename T, class CIn, class COut>
|
||||
VTKM_CONT static void ScanExtended(const vtkm::cont::ArrayHandle<T, CIn>& input,
|
||||
vtkm::cont::ArrayHandle<T, COut>& output)
|
||||
{
|
||||
ScanExtended(vtkm::cont::DeviceAdapterTagAny(), input, output);
|
||||
}
|
||||
|
||||
|
||||
template <typename T, class CIn, class COut, class BinaryFunctor>
|
||||
VTKM_CONT static void ScanExtended(vtkm::cont::DeviceAdapterId devId,
|
||||
const vtkm::cont::ArrayHandle<T, CIn>& input,
|
||||
vtkm::cont::ArrayHandle<T, COut>& output,
|
||||
BinaryFunctor binaryFunctor,
|
||||
const T& initialValue)
|
||||
{
|
||||
detail::ScanExtendedFunctor<T> functor;
|
||||
vtkm::cont::TryExecuteOnDevice(devId, functor, input, output, binaryFunctor, initialValue);
|
||||
}
|
||||
template <typename T, class CIn, class COut, class BinaryFunctor>
|
||||
VTKM_CONT static void ScanExtended(const vtkm::cont::ArrayHandle<T, CIn>& input,
|
||||
vtkm::cont::ArrayHandle<T, COut>& output,
|
||||
BinaryFunctor binaryFunctor,
|
||||
const T& initialValue)
|
||||
{
|
||||
ScanExtended(vtkm::cont::DeviceAdapterTagAny(), input, output, binaryFunctor, initialValue);
|
||||
}
|
||||
|
||||
|
||||
template <class Functor>
|
||||
VTKM_CONT static void Schedule(vtkm::cont::DeviceAdapterId devId,
|
||||
Functor functor,
|
||||
|
@ -378,6 +378,55 @@ struct DeviceAdapterAlgorithm
|
||||
const vtkm::cont::ArrayHandle<U, VIn>& values,
|
||||
vtkm::cont::ArrayHandle<U, VOut>& output);
|
||||
|
||||
/// \brief Compute an extended prefix sum operation on the input ArrayHandle.
|
||||
///
|
||||
/// Computes an extended prefix sum operation on the \c input ArrayHandle,
|
||||
/// storing the results in the \c output ArrayHandle. This produces an output
|
||||
/// array that contains both an inclusive scan (in elements [1, size)) and an
|
||||
/// exclusive scan (in elements [0, size-1)). By using ArrayHandleView,
|
||||
/// arrays containing both inclusive and exclusive scans can be generated
|
||||
/// from an extended scan with minimal memory usage.
|
||||
///
|
||||
/// This algorithm may also be more efficient than ScanInclusive and
|
||||
/// ScanExclusive on some devices, since it may be able to avoid copying the
|
||||
/// total sum to the control environment to return.
|
||||
///
|
||||
/// ScanExtended is similar to the stl partial sum function, exception that
|
||||
/// ScanExtended doesn't do a serial summation. This means that if you have
|
||||
/// defined a custom plus operator for T it must be associative, or you will
|
||||
/// get inconsistent results.
|
||||
///
|
||||
/// This overload of ScanExtended uses vtkm::Add for the binary functor, and
|
||||
/// uses zero for the initial value of the scan operation.
|
||||
///
|
||||
template <typename T, class CIn, class COut>
|
||||
VTKM_CONT static void ScanExtended(const vtkm::cont::ArrayHandle<T, CIn>& input,
|
||||
vtkm::cont::ArrayHandle<T, COut>& output);
|
||||
|
||||
/// \brief Compute an extended prefix sum operation on the input ArrayHandle.
|
||||
///
|
||||
/// Computes an extended prefix sum operation on the \c input ArrayHandle,
|
||||
/// storing the results in the \c output ArrayHandle. This produces an output
|
||||
/// array that contains both an inclusive scan (in elements [1, size)) and an
|
||||
/// exclusive scan (in elements [0, size-1)). By using ArrayHandleView,
|
||||
/// arrays containing both inclusive and exclusive scans can be generated
|
||||
/// from an extended scan with minimal memory usage.
|
||||
///
|
||||
/// This algorithm may also be more efficient than ScanInclusive and
|
||||
/// ScanExclusive on some devices, since it may be able to avoid copying the
|
||||
/// total sum to the control environment to return.
|
||||
///
|
||||
/// ScanExtended is similar to the stl partial sum function, exception that
|
||||
/// ScanExtended doesn't do a serial summation. This means that if you have
|
||||
/// defined a custom plus operator for T it must be associative, or you will
|
||||
/// get inconsistent results.
|
||||
///
|
||||
template <typename T, class CIn, class COut, class BinaryFunctor>
|
||||
VTKM_CONT static void ScanExtended(const vtkm::cont::ArrayHandle<T, CIn>& input,
|
||||
vtkm::cont::ArrayHandle<T, COut>& output,
|
||||
BinaryFunctor binaryFunctor,
|
||||
const T& initialValue);
|
||||
|
||||
/// \brief Schedule many instances of a function to run on concurrent threads.
|
||||
///
|
||||
/// Calls the \c functor on several threads. This is the function used in the
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include <vtkm/cont/ArrayHandleImplicit.h>
|
||||
#include <vtkm/cont/ArrayHandleIndex.h>
|
||||
#include <vtkm/cont/ArrayHandleStreaming.h>
|
||||
#include <vtkm/cont/ArrayHandleView.h>
|
||||
#include <vtkm/cont/ArrayHandleZip.h>
|
||||
#include <vtkm/cont/BitField.h>
|
||||
#include <vtkm/cont/Logging.h>
|
||||
@ -660,6 +661,7 @@ public:
|
||||
vtkm::Id numValues = input.GetNumberOfValues();
|
||||
if (numValues <= 0)
|
||||
{
|
||||
output.Shrink(0);
|
||||
return initialValue;
|
||||
}
|
||||
|
||||
@ -687,6 +689,50 @@ public:
|
||||
input, output, vtkm::Sum(), vtkm::TypeTraits<T>::ZeroInitialization());
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Scan Exclusive Extend
|
||||
template <typename T, class CIn, class COut, class BinaryFunctor>
|
||||
VTKM_CONT static void ScanExtended(const vtkm::cont::ArrayHandle<T, CIn>& input,
|
||||
vtkm::cont::ArrayHandle<T, COut>& output,
|
||||
BinaryFunctor binaryFunctor,
|
||||
const T& initialValue)
|
||||
{
|
||||
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
|
||||
|
||||
vtkm::Id numValues = input.GetNumberOfValues();
|
||||
if (numValues <= 0)
|
||||
{
|
||||
output.Allocate(1);
|
||||
output.GetPortalControl().Set(0, initialValue);
|
||||
return;
|
||||
}
|
||||
|
||||
vtkm::cont::ArrayHandle<T, vtkm::cont::StorageTagBasic> inclusiveScan;
|
||||
T result = DerivedAlgorithm::ScanInclusive(input, inclusiveScan, binaryFunctor);
|
||||
|
||||
auto inputPortal = inclusiveScan.PrepareForInput(DeviceAdapterTag());
|
||||
auto outputPortal = output.PrepareForOutput(numValues + 1, DeviceAdapterTag());
|
||||
|
||||
InclusiveToExtendedKernel<decltype(inputPortal), decltype(outputPortal), BinaryFunctor>
|
||||
inclusiveToExtended(inputPortal,
|
||||
outputPortal,
|
||||
binaryFunctor,
|
||||
initialValue,
|
||||
binaryFunctor(initialValue, result));
|
||||
|
||||
DerivedAlgorithm::Schedule(inclusiveToExtended, numValues + 1);
|
||||
}
|
||||
|
||||
template <typename T, class CIn, class COut>
|
||||
VTKM_CONT static void ScanExtended(const vtkm::cont::ArrayHandle<T, CIn>& input,
|
||||
vtkm::cont::ArrayHandle<T, COut>& output)
|
||||
{
|
||||
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
|
||||
|
||||
DerivedAlgorithm::ScanExtended(
|
||||
input, output, vtkm::Sum(), vtkm::TypeTraits<T>::ZeroInitialization());
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
// Scan Exclusive By Key
|
||||
template <typename KeyT,
|
||||
|
@ -1106,9 +1106,50 @@ struct InclusiveToExclusiveKernel : vtkm::exec::FunctorBase
|
||||
VTKM_EXEC
|
||||
void operator()(vtkm::Id index) const
|
||||
{
|
||||
ValueType result = (index == 0)
|
||||
const ValueType result = (index == 0)
|
||||
? this->InitialValue
|
||||
: this->BinaryOperator(this->InitialValue, this->InPortal.Get(index - 1));
|
||||
|
||||
this->OutPortal.Set(index, result);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename InPortalType, typename OutPortalType, typename BinaryFunctor>
|
||||
struct InclusiveToExtendedKernel : vtkm::exec::FunctorBase
|
||||
{
|
||||
using ValueType = typename InPortalType::ValueType;
|
||||
|
||||
InPortalType InPortal;
|
||||
OutPortalType OutPortal;
|
||||
BinaryFunctor BinaryOperator;
|
||||
ValueType InitialValue;
|
||||
ValueType FinalValue;
|
||||
|
||||
VTKM_CONT
|
||||
InclusiveToExtendedKernel(const InPortalType& inPortal,
|
||||
const OutPortalType& outPortal,
|
||||
BinaryFunctor& binaryOperator,
|
||||
ValueType initialValue,
|
||||
ValueType finalValue)
|
||||
: InPortal(inPortal)
|
||||
, OutPortal(outPortal)
|
||||
, BinaryOperator(binaryOperator)
|
||||
, InitialValue(initialValue)
|
||||
, FinalValue(finalValue)
|
||||
{
|
||||
}
|
||||
|
||||
VTKM_SUPPRESS_EXEC_WARNINGS
|
||||
VTKM_EXEC
|
||||
void operator()(vtkm::Id index) const
|
||||
{
|
||||
// The output array has one more value than the input, which holds the
|
||||
// total sum.
|
||||
const ValueType result =
|
||||
(index == 0) ? this->InitialValue : (index == this->InPortal.GetNumberOfValues())
|
||||
? this->FinalValue
|
||||
: this->BinaryOperator(this->InitialValue, this->InPortal.Get(index - 1));
|
||||
|
||||
this->OutPortal.Set(index, result);
|
||||
}
|
||||
};
|
||||
|
@ -19,6 +19,8 @@ void DeviceAdapterAlgorithm<vtkm::cont::DeviceAdapterTagSerial>::ScheduleTask(
|
||||
vtkm::exec::serial::internal::TaskTiling1D& functor,
|
||||
vtkm::Id size)
|
||||
{
|
||||
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
|
||||
|
||||
const vtkm::Id MESSAGE_SIZE = 1024;
|
||||
char errorString[MESSAGE_SIZE];
|
||||
errorString[0] = '\0';
|
||||
@ -44,6 +46,8 @@ void DeviceAdapterAlgorithm<vtkm::cont::DeviceAdapterTagSerial>::ScheduleTask(
|
||||
vtkm::exec::serial::internal::TaskTiling3D& functor,
|
||||
vtkm::Id3 size)
|
||||
{
|
||||
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
|
||||
|
||||
const vtkm::Id MESSAGE_SIZE = 1024;
|
||||
char errorString[MESSAGE_SIZE];
|
||||
errorString[0] = '\0';
|
||||
|
@ -69,6 +69,8 @@ public:
|
||||
VTKM_CONT static void Copy(const vtkm::cont::ArrayHandle<T, CIn>& input,
|
||||
vtkm::cont::ArrayHandle<U, COut>& output)
|
||||
{
|
||||
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
|
||||
|
||||
const vtkm::Id inSize = input.GetNumberOfValues();
|
||||
auto inputPortal = input.PrepareForInput(DeviceAdapterTagSerial());
|
||||
auto outputPortal = output.PrepareForOutput(inSize, DeviceAdapterTagSerial());
|
||||
@ -92,6 +94,8 @@ public:
|
||||
const vtkm::cont::ArrayHandle<U, CStencil>& stencil,
|
||||
vtkm::cont::ArrayHandle<T, COut>& output)
|
||||
{
|
||||
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
|
||||
|
||||
::vtkm::NotZeroInitialized unary_predicate;
|
||||
CopyIf(input, stencil, output, unary_predicate);
|
||||
}
|
||||
@ -102,6 +106,8 @@ public:
|
||||
vtkm::cont::ArrayHandle<T, COut>& output,
|
||||
UnaryPredicate predicate)
|
||||
{
|
||||
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
|
||||
|
||||
vtkm::Id inputSize = input.GetNumberOfValues();
|
||||
VTKM_ASSERT(inputSize == stencil.GetNumberOfValues());
|
||||
|
||||
@ -131,6 +137,8 @@ public:
|
||||
vtkm::cont::ArrayHandle<U, COut>& output,
|
||||
vtkm::Id outputIndex = 0)
|
||||
{
|
||||
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
|
||||
|
||||
const vtkm::Id inSize = input.GetNumberOfValues();
|
||||
|
||||
// Check if the ranges overlap and fail if they do.
|
||||
@ -191,6 +199,8 @@ public:
|
||||
template <typename T, typename U, class CIn>
|
||||
VTKM_CONT static U Reduce(const vtkm::cont::ArrayHandle<T, CIn>& input, U initialValue)
|
||||
{
|
||||
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
|
||||
|
||||
return Reduce(input, initialValue, vtkm::Add());
|
||||
}
|
||||
|
||||
@ -199,6 +209,8 @@ public:
|
||||
U initialValue,
|
||||
BinaryFunctor binary_functor)
|
||||
{
|
||||
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
|
||||
|
||||
internal::WrappedBinaryOperator<U, BinaryFunctor> wrappedOp(binary_functor);
|
||||
auto inputPortal = input.PrepareForInput(Device());
|
||||
return std::accumulate(vtkm::cont::ArrayPortalToIteratorBegin(inputPortal),
|
||||
@ -220,6 +232,8 @@ public:
|
||||
vtkm::cont::ArrayHandle<U, VOut>& values_output,
|
||||
BinaryFunctor binary_functor)
|
||||
{
|
||||
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
|
||||
|
||||
auto keysPortalIn = keys.PrepareForInput(Device());
|
||||
auto valuesPortalIn = values.PrepareForInput(Device());
|
||||
const vtkm::Id numberOfKeys = keys.GetNumberOfValues();
|
||||
@ -275,6 +289,8 @@ public:
|
||||
vtkm::cont::ArrayHandle<T, COut>& output,
|
||||
BinaryFunctor binary_functor)
|
||||
{
|
||||
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
|
||||
|
||||
internal::WrappedBinaryOperator<T, BinaryFunctor> wrappedBinaryOp(binary_functor);
|
||||
|
||||
vtkm::Id numberOfValues = input.GetNumberOfValues();
|
||||
@ -300,6 +316,8 @@ public:
|
||||
VTKM_CONT static T ScanInclusive(const vtkm::cont::ArrayHandle<T, CIn>& input,
|
||||
vtkm::cont::ArrayHandle<T, COut>& output)
|
||||
{
|
||||
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
|
||||
|
||||
return ScanInclusive(input, output, vtkm::Sum());
|
||||
}
|
||||
|
||||
@ -309,6 +327,8 @@ public:
|
||||
BinaryFunctor binaryFunctor,
|
||||
const T& initialValue)
|
||||
{
|
||||
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
|
||||
|
||||
internal::WrappedBinaryOperator<T, BinaryFunctor> wrappedBinaryOp(binaryFunctor);
|
||||
|
||||
vtkm::Id numberOfValues = input.GetNumberOfValues();
|
||||
@ -347,6 +367,8 @@ public:
|
||||
VTKM_CONT static T ScanExclusive(const vtkm::cont::ArrayHandle<T, CIn>& input,
|
||||
vtkm::cont::ArrayHandle<T, COut>& output)
|
||||
{
|
||||
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
|
||||
|
||||
return ScanExclusive(input, output, vtkm::Sum(), vtkm::TypeTraits<T>::ZeroInitialization());
|
||||
}
|
||||
|
||||
@ -358,6 +380,8 @@ public:
|
||||
template <class FunctorType>
|
||||
VTKM_CONT static inline void Schedule(FunctorType functor, vtkm::Id size)
|
||||
{
|
||||
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
|
||||
|
||||
vtkm::exec::serial::internal::TaskTiling1D kernel(functor);
|
||||
ScheduleTask(kernel, size);
|
||||
}
|
||||
@ -365,6 +389,8 @@ public:
|
||||
template <class FunctorType>
|
||||
VTKM_CONT static inline void Schedule(FunctorType functor, vtkm::Id3 size)
|
||||
{
|
||||
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
|
||||
|
||||
vtkm::exec::serial::internal::TaskTiling3D kernel(functor);
|
||||
ScheduleTask(kernel, size);
|
||||
}
|
||||
@ -380,6 +406,8 @@ private:
|
||||
vtkm::cont::ArrayHandle<I, StorageI>& index,
|
||||
vtkm::cont::ArrayHandle<Vout, StorageVout>& values_out)
|
||||
{
|
||||
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
|
||||
|
||||
const vtkm::Id n = values.GetNumberOfValues();
|
||||
VTKM_ASSERT(n == index.GetNumberOfValues());
|
||||
|
||||
@ -400,6 +428,8 @@ private:
|
||||
vtkm::cont::ArrayHandle<U, StorageU>& values,
|
||||
BinaryCompare binary_compare)
|
||||
{
|
||||
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
|
||||
|
||||
//combine the keys and values into a ZipArrayHandle
|
||||
//we than need to specify a custom compare function wrapper
|
||||
//that only checks for key side of the pair, using the custom compare
|
||||
@ -413,6 +443,8 @@ public:
|
||||
VTKM_CONT static void SortByKey(vtkm::cont::ArrayHandle<T, StorageT>& keys,
|
||||
vtkm::cont::ArrayHandle<U, StorageU>& values)
|
||||
{
|
||||
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
|
||||
|
||||
SortByKey(keys, values, std::less<T>());
|
||||
}
|
||||
|
||||
@ -421,6 +453,8 @@ public:
|
||||
vtkm::cont::ArrayHandle<U, StorageU>& values,
|
||||
const BinaryCompare& binary_compare)
|
||||
{
|
||||
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
|
||||
|
||||
internal::WrappedBinaryOperator<bool, BinaryCompare> wrappedCompare(binary_compare);
|
||||
constexpr bool larger_than_64bits = sizeof(U) > sizeof(vtkm::Int64);
|
||||
if (larger_than_64bits)
|
||||
@ -444,6 +478,8 @@ public:
|
||||
template <typename T, class Storage>
|
||||
VTKM_CONT static void Sort(vtkm::cont::ArrayHandle<T, Storage>& values)
|
||||
{
|
||||
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
|
||||
|
||||
Sort(values, std::less<T>());
|
||||
}
|
||||
|
||||
@ -451,6 +487,8 @@ public:
|
||||
VTKM_CONT static void Sort(vtkm::cont::ArrayHandle<T, Storage>& values,
|
||||
BinaryCompare binary_compare)
|
||||
{
|
||||
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
|
||||
|
||||
auto arrayPortal = values.PrepareForInPlace(Device());
|
||||
vtkm::cont::ArrayPortalToIterators<decltype(arrayPortal)> iterators(arrayPortal);
|
||||
|
||||
@ -461,6 +499,8 @@ public:
|
||||
template <typename T, class Storage>
|
||||
VTKM_CONT static void Unique(vtkm::cont::ArrayHandle<T, Storage>& values)
|
||||
{
|
||||
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
|
||||
|
||||
Unique(values, std::equal_to<T>());
|
||||
}
|
||||
|
||||
@ -468,6 +508,8 @@ public:
|
||||
VTKM_CONT static void Unique(vtkm::cont::ArrayHandle<T, Storage>& values,
|
||||
BinaryCompare binary_compare)
|
||||
{
|
||||
VTKM_LOG_SCOPE_FUNCTION(vtkm::cont::LogLevel::Perf);
|
||||
|
||||
auto arrayPortal = values.PrepareForInPlace(Device());
|
||||
vtkm::cont::ArrayPortalToIterators<decltype(arrayPortal)> iterators(arrayPortal);
|
||||
internal::WrappedBinaryOperator<bool, BinaryCompare> wrappedCompare(binary_compare);
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include <vtkm/BinaryPredicates.h>
|
||||
#include <vtkm/TypeTraits.h>
|
||||
|
||||
#include <vtkm/cont/ArrayGetValues.h>
|
||||
#include <vtkm/cont/ArrayHandle.h>
|
||||
#include <vtkm/cont/ArrayHandleConstant.h>
|
||||
#include <vtkm/cont/ArrayHandleIndex.h>
|
||||
@ -1985,6 +1986,108 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
static VTKM_CONT void TestScanExtended()
|
||||
{
|
||||
std::cout << "-------------------------------------------" << std::endl;
|
||||
std::cout << "Testing Extended Scan" << std::endl;
|
||||
|
||||
{
|
||||
std::cout << " size " << ARRAY_SIZE << std::endl;
|
||||
|
||||
//construct the index array
|
||||
IdArrayHandle array;
|
||||
Algorithm::Schedule(ClearArrayKernel(array.PrepareForOutput(ARRAY_SIZE, DeviceAdapterTag())),
|
||||
ARRAY_SIZE);
|
||||
|
||||
// we now have an array whose sum = (OFFSET * ARRAY_SIZE),
|
||||
// let's validate that
|
||||
Algorithm::ScanExtended(array, array);
|
||||
VTKM_TEST_ASSERT(array.GetNumberOfValues() == ARRAY_SIZE + 1, "Output size incorrect.");
|
||||
auto portal = array.GetPortalConstControl();
|
||||
for (vtkm::Id i = 0; i < ARRAY_SIZE + 1; ++i)
|
||||
{
|
||||
const vtkm::Id value = portal.Get(i);
|
||||
VTKM_TEST_ASSERT(value == i * OFFSET, "Incorrect partial sum");
|
||||
}
|
||||
|
||||
std::cout << " size 1" << std::endl;
|
||||
array.Shrink(1);
|
||||
array.GetPortalControl().Set(0, OFFSET);
|
||||
Algorithm::ScanExtended(array, array);
|
||||
VTKM_TEST_ASSERT(array.GetNumberOfValues() == 2);
|
||||
portal = array.GetPortalConstControl();
|
||||
VTKM_TEST_ASSERT(portal.Get(0) == 0, "Incorrect initial value");
|
||||
VTKM_TEST_ASSERT(portal.Get(1) == OFFSET, "Incorrect total sum");
|
||||
|
||||
std::cout << " size 0" << std::endl;
|
||||
array.Shrink(0);
|
||||
Algorithm::ScanExtended(array, array);
|
||||
VTKM_TEST_ASSERT(array.GetNumberOfValues() == 1);
|
||||
portal = array.GetPortalConstControl();
|
||||
VTKM_TEST_ASSERT(portal.Get(0) == 0, "Incorrect initial value");
|
||||
}
|
||||
|
||||
std::cout << "-------------------------------------------" << std::endl;
|
||||
std::cout << "Testing Extended Scan with multiplication operator" << std::endl;
|
||||
{
|
||||
std::vector<vtkm::Float64> inputValues(ARRAY_SIZE);
|
||||
for (std::size_t i = 0; i < ARRAY_SIZE; ++i)
|
||||
{
|
||||
inputValues[i] = 1.01;
|
||||
}
|
||||
|
||||
std::size_t mid = ARRAY_SIZE / 2;
|
||||
inputValues[mid] = 0.0;
|
||||
|
||||
vtkm::cont::ArrayHandle<vtkm::Float64> array =
|
||||
vtkm::cont::make_ArrayHandle(inputValues, vtkm::CopyFlag::On);
|
||||
|
||||
vtkm::Float64 initialValue = 2.00;
|
||||
Algorithm::ScanExtended(array, array, vtkm::Multiply(), initialValue);
|
||||
|
||||
VTKM_TEST_ASSERT(array.GetNumberOfValues() == ARRAY_SIZE + 1,
|
||||
"ScanExtended output size incorrect.");
|
||||
|
||||
auto portal = array.GetPortalConstControl();
|
||||
VTKM_TEST_ASSERT(portal.Get(0) == initialValue,
|
||||
"ScanExtended result's first value != initialValue");
|
||||
|
||||
for (std::size_t i = 1; i <= mid; ++i)
|
||||
{
|
||||
vtkm::Id index = static_cast<vtkm::Id>(i);
|
||||
vtkm::Float64 expected = pow(1.01, static_cast<vtkm::Float64>(i)) * initialValue;
|
||||
vtkm::Float64 got = portal.Get(index);
|
||||
VTKM_TEST_ASSERT(test_equal(got, expected), "Incorrect results for ScanExtended");
|
||||
}
|
||||
for (std::size_t i = mid + 1; i < ARRAY_SIZE + 1; ++i)
|
||||
{
|
||||
vtkm::Id index = static_cast<vtkm::Id>(i);
|
||||
VTKM_TEST_ASSERT(portal.Get(index) == 0.0f, "Incorrect results for ScanExtended");
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "-------------------------------------------" << std::endl;
|
||||
std::cout << "Testing Extended Scan with a vtkm::Vec" << std::endl;
|
||||
|
||||
{
|
||||
using Vec3 = vtkm::Vec3f_64;
|
||||
using Vec3ArrayHandle = vtkm::cont::ArrayHandle<Vec3, StorageTag>;
|
||||
|
||||
std::vector<Vec3> testValues(ARRAY_SIZE);
|
||||
|
||||
for (std::size_t i = 0; i < ARRAY_SIZE; ++i)
|
||||
{
|
||||
testValues[i] = TestValue(1, Vec3());
|
||||
}
|
||||
Vec3ArrayHandle values = vtkm::cont::make_ArrayHandle(testValues, vtkm::CopyFlag::On);
|
||||
|
||||
Algorithm::ScanExtended(values, values);
|
||||
VTKM_TEST_ASSERT(test_equal(vtkm::cont::ArrayGetValue(ARRAY_SIZE, values),
|
||||
(TestValue(1, Vec3()) * ARRAY_SIZE)),
|
||||
"Got bad sum from ScanExtended");
|
||||
}
|
||||
}
|
||||
|
||||
static VTKM_CONT void TestErrorExecution()
|
||||
{
|
||||
std::cout << "-------------------------------------------" << std::endl;
|
||||
@ -2763,6 +2866,7 @@ private:
|
||||
TestReduceByKeyWithFancyArrays();
|
||||
|
||||
TestScanExclusive();
|
||||
TestScanExtended();
|
||||
|
||||
TestScanInclusive();
|
||||
TestScanInclusiveWithComparisonObject();
|
||||
|
@ -99,6 +99,8 @@ void ScanTest()
|
||||
out = vtkm::cont::Algorithm::ScanExclusive(input, output, vtkm::Maximum(), vtkm::Id(0));
|
||||
vtkm::cont::Algorithm::ScanExclusiveByKey(keys, input, output, vtkm::Id(0), vtkm::Maximum());
|
||||
vtkm::cont::Algorithm::ScanExclusiveByKey(keys, input, output);
|
||||
vtkm::cont::Algorithm::ScanExtended(input, output);
|
||||
vtkm::cont::Algorithm::ScanExtended(input, output, vtkm::Maximum(), vtkm::Id(0));
|
||||
(void)out;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user