vtk-m/vtkm/worklet/StableSortIndices.h
Kenneth Moreland bddad9b386 Remove TryExecute from filters
Now that the dispatcher does its own TryExecute, filters do not need to
do that. This change requires all worklets called by filters to be able
to execute without knowing the device a priori.
2018-10-16 15:59:53 -06:00

237 lines
8.5 KiB
C++

//============================================================================
// 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.
//
// Copyright 2017 National Technology & Engineering Solutions of Sandia, LLC (NTESS).
// Copyright 2017 UT-Battelle, LLC.
// Copyright 2017 Los Alamos National Security.
//
// Under the terms of Contract DE-NA0003525 with NTESS,
// the U.S. Government retains certain rights in this software.
//
// Under the terms of Contract DE-AC52-06NA25396 with Los Alamos National
// Laboratory (LANL), the U.S. Government retains certain rights in
// this software.
//============================================================================
#ifndef vtk_m_worklet_SortAndUniqueIndices_h
#define vtk_m_worklet_SortAndUniqueIndices_h
#include <vtkm/cont/Algorithm.h>
#include <vtkm/cont/ArrayHandle.h>
#include <vtkm/cont/ArrayHandleIndex.h>
#include <vtkm/cont/ExecutionObjectBase.h>
namespace vtkm
{
namespace worklet
{
/// Produces an ArrayHandle<vtkm::Id> index array that stable-sorts and
/// optionally uniquifies an input array.
struct StableSortIndices
{
using IndexArrayType = vtkm::cont::ArrayHandle<vtkm::Id>;
// Allows Sort to be called on an array that indexes into KeyPortal.
// If the values compare equal, the indices are compared to stabilize the
// result.
template <typename KeyPortalType>
struct IndirectSortPredicate
{
using KeyType = typename KeyPortalType::ValueType;
const KeyPortalType KeyPortal;
VTKM_CONT
IndirectSortPredicate(const KeyPortalType& keyPortal)
: KeyPortal(keyPortal)
{
}
template <typename IndexType>
VTKM_EXEC bool operator()(const IndexType& a, const IndexType& b) const
{
// If the values compare equal, compare the indices as well so we get
// consistent outputs.
const KeyType valueA = this->KeyPortal.Get(a);
const KeyType valueB = this->KeyPortal.Get(b);
if (valueA < valueB)
{
return true;
}
else if (valueB < valueA)
{
return false;
}
else
{
return a < b;
}
}
};
// Allows you to pass an IndirectSortPredicate to a device algorithm without knowing the device.
template <typename KeyArrayType>
struct IndirectSortPredicateExecObject : public vtkm::cont::ExecutionObjectBase
{
const KeyArrayType KeyArray;
VTKM_CONT IndirectSortPredicateExecObject(const KeyArrayType& keyArray)
: KeyArray(keyArray)
{
}
template <typename Device>
IndirectSortPredicate<typename KeyArrayType::template ExecutionTypes<Device>::PortalConst>
PrepareForExecution(Device) const
{
auto keyPortal = this->KeyArray.PrepareForInput(Device());
return IndirectSortPredicate<decltype(keyPortal)>(keyPortal);
}
};
// Allows Unique to be called on an array that indexes into KeyPortal.
template <typename KeyPortalType>
struct IndirectUniquePredicate
{
const KeyPortalType KeyPortal;
VTKM_CONT
IndirectUniquePredicate(const KeyPortalType& keyPortal)
: KeyPortal(keyPortal)
{
}
template <typename IndexType>
VTKM_EXEC bool operator()(const IndexType& a, const IndexType& b) const
{
return this->KeyPortal.Get(a) == this->KeyPortal.Get(b);
}
};
// Allows you to pass an IndirectUniquePredicate to a device algorithm without knowing the device.
template <typename KeyArrayType>
struct IndirectUniquePredicateExecObject : public vtkm::cont::ExecutionObjectBase
{
const KeyArrayType KeyArray;
VTKM_CONT IndirectUniquePredicateExecObject(const KeyArrayType& keyArray)
: KeyArray(keyArray)
{
}
template <typename Device>
IndirectUniquePredicate<typename KeyArrayType::template ExecutionTypes<Device>::PortalConst>
PrepareForExecution(Device) const
{
auto keyPortal = this->KeyArray.PrepareForInput(Device());
return IndirectUniquePredicate<decltype(keyPortal)>(keyPortal);
}
};
/// Permutes the @a indices array so that it will map @a keys into a stable
/// sorted order. The @a keys array is not modified.
///
/// @param device The Id for the device on which to compute the sort
/// @param keys The ArrayHandle containing data to be sorted.
/// @param indices The ArrayHandle<vtkm::Id> containing the permutation indices.
///
/// @note @a indices is expected to contain the values (0, numKeys] in
/// increasing order. If the values in @a indices are not sequential, the sort
/// will succeed and be consistently reproducible, but the result is not
/// guaranteed to be stable with respect to the original ordering of @a keys.
template <typename KeyType, typename Storage>
VTKM_CONT static void Sort(vtkm::cont::DeviceAdapterId device,
const vtkm::cont::ArrayHandle<KeyType, Storage>& keys,
IndexArrayType& indices)
{
using KeyArrayType = vtkm::cont::ArrayHandle<KeyType, Storage>;
using SortPredicate = IndirectSortPredicateExecObject<KeyArrayType>;
VTKM_ASSERT(keys.GetNumberOfValues() == indices.GetNumberOfValues());
vtkm::cont::Algorithm::Sort(device, indices, SortPredicate(keys));
}
/// Permutes the @a indices array so that it will map @a keys into a stable
/// sorted order. The @a keys array is not modified.
///
/// @param keys The ArrayHandle containing data to be sorted.
/// @param indices The ArrayHandle<vtkm::Id> containing the permutation indices.
///
/// @note @a indices is expected to contain the values (0, numKeys] in
/// increasing order. If the values in @a indices are not sequential, the sort
/// will succeed and be consistently reproducible, but the result is not
/// guaranteed to be stable with respect to the original ordering of @a keys.
template <typename KeyType, typename Storage>
VTKM_CONT static void Sort(const vtkm::cont::ArrayHandle<KeyType, Storage>& keys,
IndexArrayType& indices)
{
StableSortIndices::Sort(vtkm::cont::DeviceAdapterTagAny(), keys, indices);
}
/// Returns an index array that maps the @a keys array into a stable sorted
/// ordering. The @a keys array is not modified.
///
/// This is a convenience overload that generates the index array.
template <typename KeyType, typename Storage>
VTKM_CONT static IndexArrayType Sort(vtkm::cont::DeviceAdapterId device,
const vtkm::cont::ArrayHandle<KeyType, Storage>& keys)
{
// Generate the initial index array
IndexArrayType indices;
{
vtkm::cont::ArrayHandleIndex indicesSrc(keys.GetNumberOfValues());
vtkm::cont::Algorithm::Copy(device, indicesSrc, indices);
}
StableSortIndices::Sort(device, keys, indices);
return indices;
}
/// Returns an index array that maps the @a keys array into a stable sorted
/// ordering. The @a keys array is not modified.
///
/// This is a convenience overload that generates the index array.
template <typename KeyType, typename Storage>
VTKM_CONT static IndexArrayType Sort(const vtkm::cont::ArrayHandle<KeyType, Storage>& keys)
{
return StableSortIndices::Sort(vtkm::cont::DeviceAdapterTagAny(), keys);
}
/// Reduces the array returned by @a Sort so that the mapped @a keys are
/// unique. The @a indices array will be modified in-place and the @a keys
/// array is not modified.
///
template <typename KeyType, typename Storage>
VTKM_CONT static void Unique(vtkm::cont::DeviceAdapterId device,
const vtkm::cont::ArrayHandle<KeyType, Storage>& keys,
IndexArrayType& indices)
{
using KeyArrayType = vtkm::cont::ArrayHandle<KeyType, Storage>;
using UniquePredicate = IndirectUniquePredicateExecObject<KeyArrayType>;
vtkm::cont::Algorithm::Unique(device, indices, UniquePredicate(keys));
}
/// Reduces the array returned by @a Sort so that the mapped @a keys are
/// unique. The @a indices array will be modified in-place and the @a keys
/// array is not modified.
///
template <typename KeyType, typename Storage>
VTKM_CONT static void Unique(const vtkm::cont::ArrayHandle<KeyType, Storage>& keys,
IndexArrayType& indices)
{
StableSortIndices::Unique(vtkm::cont::DeviceAdapterTagAny(), keys, indices);
}
};
}
} // end namespace vtkm::worklet
#endif // vtk_m_worklet_SortAndUniqueIndices_h