375 counts_view_type counts_;
376 offsets_view_type ptr_;
377 keys_view_type keys_;
379 typename pair_type::second_type startingValue_;
381 key_type initMinKey_;
383 key_type initMaxKey_;
411 class SizeType =
typename OffsetsViewType::size_type>
414 typedef typename OffsetsViewType::const_type offsets_view_type;
415 typedef typename PairsViewType::const_type pairs_view_type;
416 typedef typename offsets_view_type::execution_space execution_space;
417 typedef typename offsets_view_type::memory_space memory_space;
428 const offsets_view_type&
ptr)
431 , size_(ptr_.extent(0) == 0 ?
size_type(0) : ptr_.extent(0) - 1) {}
442 dst = dst + src > 0 ? 1 : 0;
448 typedef typename offsets_view_type::non_const_value_type offset_type;
449 typedef typename pairs_view_type::non_const_value_type pair_type;
450 typedef typename pair_type::first_type key_type;
455 const offset_type
beg = ptr_[
i];
456 const offset_type
end = ptr_[
i + 1];
462 for (offset_type
j =
beg + 1;
j <
end; ++
j) {
463 const key_type
curKey = pairs_[
j].first;
464 for (offset_type
k =
beg;
k <
j; ++
k) {
476 pairs_view_type pairs_;
477 offsets_view_type ptr_;
487template <
class KeyType,
class ValueType,
class DeviceType>
492 , checkedForDuplicateKeys_(
false) {
500template <
class KeyType,
class ValueType,
class DeviceType>
505 , checkedForDuplicateKeys_(
false) {
514 using Kokkos::ViewAllocateWithoutInitializing;
525template <
class KeyType,
class ValueType,
class DeviceType>
531 , checkedForDuplicateKeys_(
false) {
539 using Kokkos::ViewAllocateWithoutInitializing;
558 const KeyType initMaxKey = ::KokkosKernels::ArithTraits<KeyType>::is_integer ? ::KokkosKernels::ArithTraits<KeyType>::min() : -::KokkosKernels::ArithTraits<KeyType>::max();
563template <
class KeyType,
class ValueType,
class DeviceType>
573 , checkedForDuplicateKeys_(
false) {
587 const KeyType initMaxKey = ::KokkosKernels::ArithTraits<KeyType>::is_integer ? ::KokkosKernels::ArithTraits<KeyType>::min() : -::KokkosKernels::ArithTraits<KeyType>::max();
592template <
class KeyType,
class ValueType,
class DeviceType>
602 , checkedForDuplicateKeys_(
false) {
610 using Kokkos::ViewAllocateWithoutInitializing;
629 const KeyType initMaxKey = ::KokkosKernels::ArithTraits<KeyType>::is_integer ? ::KokkosKernels::ArithTraits<KeyType>::min() : -::KokkosKernels::ArithTraits<KeyType>::max();
634template <
class KeyType,
class ValueType,
class DeviceType>
640 , checkedForDuplicateKeys_(
false) {
654 const KeyType initMaxKey = ::KokkosKernels::ArithTraits<KeyType>::is_integer ? ::KokkosKernels::ArithTraits<KeyType>::min() : -::KokkosKernels::ArithTraits<KeyType>::max();
659template <
class KeyType,
class ValueType,
class DeviceType>
662 const Teuchos::ArrayView<const ValueType>&
vals)
663 : contiguousValues_(
false)
664 , checkedForDuplicateKeys_(
false) {
685 const KeyType initMaxKey = ::KokkosKernels::ArithTraits<KeyType>::is_integer ? ::KokkosKernels::ArithTraits<KeyType>::min() : -::KokkosKernels::ArithTraits<KeyType>::max();
689template <
class KeyType,
class ValueType,
class DeviceType>
698 using Kokkos::subview;
699 using Kokkos::ViewAllocateWithoutInitializing;
700 using Teuchos::TypeNameTraits;
701 typedef typename std::decay<
decltype(
keys.extent(0))>::type size_type;
703 const char prefix[] =
"Tpetra::Details::FixedHashTable: ";
705 const offset_type
numKeys =
static_cast<offset_type
>(
keys.extent(0));
707 const offset_type
theMaxVal = ::KokkosKernels::ArithTraits<offset_type>::max();
711 <<
keys.extent(0) <<
" does not fit in "
715 <<
theMaxVal <<
". This means that it is not possible to "
716 "use this constructor.");
719 static_cast<unsigned long long>(::KokkosKernels::ArithTraits<ValueType>::max()),
720 std::invalid_argument,
721 "Tpetra::Details::FixedHashTable: The number of "
723 <<
numKeys <<
" is greater than the maximum representable "
725 << ::KokkosKernels::ArithTraits<ValueType>::max() <<
". "
726 "This means that it is not possible to use this constructor.");
731 FHT::worthBuildingFixedHashTableInParallel<execution_space>();
756 auto keys_h = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(),
758 firstContigKey_ =
keys_h[0];
762 lastContigKey_ = firstContigKey_ + 1;
769 if (lastContigKey_ !=
keys_h[
k]) {
777 firstContigKey_ = firstContigKey;
778 lastContigKey_ = lastContigKey;
781 offset_type startIndex;
783 initMinKey = std::min(initMinKey, firstContigKey_);
784 initMaxKey = std::max(initMaxKey, lastContigKey_);
785 startIndex =
static_cast<offset_type
>(lastContigKey_ - firstContigKey_);
790 const offset_type theNumKeys = numKeys - startIndex;
791 const offset_type size = hash_type::getRecommendedSize(theNumKeys);
792#ifdef HAVE_TPETRA_DEBUG
793 TEUCHOS_TEST_FOR_EXCEPTION(
794 size == 0 && numKeys != 0, std::logic_error,
795 "Tpetra::Details::FixedHashTable constructor: "
796 "getRecommendedSize("
797 << numKeys <<
") returned zero, "
798 "even though the number of keys "
799 << numKeys <<
" is nonzero. "
800 "Please report this bug to the Tpetra developers.");
803 subview(keys, std::pair<offset_type, offset_type>(startIndex, numKeys));
810 typedef typename ptr_type::non_const_type counts_type;
811 counts_type counts(
"Tpetra::FixedHashTable::counts", size);
818 typename keys_type::host_mirror_type theKeysHost;
825 if (buildInParallel) {
826 FHT::CountBuckets<counts_type, keys_type> functor(counts, theKeys, size);
827 using range_type = Kokkos::RangePolicy<execution_space, offset_type>;
828 const char kernelLabel[] =
"Tpetra::Details::FixedHashTable CountBuckets";
830 using key_type =
typename keys_type::non_const_value_type;
831 Kokkos::pair<int, key_type> err;
832 Kokkos::parallel_reduce(kernelLabel, range_type(0, theNumKeys),
834 TEUCHOS_TEST_FOR_EXCEPTION(err.first != 0, std::logic_error,
835 "Tpetra::Details::FixedHashTable "
836 "constructor: CountBuckets found a key "
837 << err.second <<
" that "
838 "results in an out-of-bounds hash value.");
840 Kokkos::parallel_for(kernelLabel, range_type(0, theNumKeys), functor);
843 Kokkos::HostSpace hostMemSpace;
844 theKeysHost = Kokkos::create_mirror_view(theKeys);
846 Kokkos::deep_copy(execution_space(), theKeysHost, theKeys);
847 auto countsHost = Kokkos::create_mirror_view(hostMemSpace, counts);
849 for (offset_type k = 0; k < theNumKeys; ++k) {
850 using key_type =
typename keys_type::non_const_value_type;
851 const key_type key = theKeysHost[k];
853 using hash_value_type =
typename hash_type::result_type;
854 const hash_value_type hashVal = hash_type::hashFunc(key, size);
855 TEUCHOS_TEST_FOR_EXCEPTION(hashVal < hash_value_type(0) ||
856 hashVal >= hash_value_type(countsHost.extent(0)),
858 "Tpetra::Details::FixedHashTable "
859 "constructor: Sequential CountBuckets found a key "
861 <<
" that results in an out-of-bounds hash value.");
863 ++countsHost[hashVal];
866 Kokkos::deep_copy(execution_space(), counts, countsHost);
872 execution_space().fence();
875 typename ptr_type::non_const_type ptr(
"Tpetra::FixedHashTable::ptr", size + 1);
890 using ::Tpetra::Details::computeOffsetsFromCounts;
891 if (buildInParallel) {
895 if (!buildInParallel || debug) {
896 Kokkos::HostSpace hostMemSpace;
897 auto counts_h = Kokkos::create_mirror_view_and_copy(hostMemSpace, counts);
898 auto ptr_h = Kokkos::create_mirror_view(hostMemSpace, ptr);
900#ifdef KOKKOS_ENABLE_SERIAL
901 Kokkos::Serial hostExecSpace;
903 Kokkos::DefaultHostExecutionSpace hostExecSpace;
908 Kokkos::deep_copy(execution_space(), ptr, ptr_h);
912 for (offset_type i = 0; i < size; ++i) {
913 if (ptr_h[i + 1] != ptr_h[i] + counts_h[i]) {
917 TEUCHOS_TEST_FOR_EXCEPTION(bad, std::logic_error,
918 "Tpetra::Details::FixedHashTable "
919 "constructor: computeOffsetsFromCounts gave an incorrect "
927 execution_space().fence();
931 typedef typename val_type::non_const_type nonconst_val_type;
932 nonconst_val_type val(ViewAllocateWithoutInitializing(
"Tpetra::FixedHashTable::pairs"),
936 typedef FHT::FillPairs<
typename val_type::non_const_type, keys_type,
937 typename ptr_type::non_const_type>
939 typename functor_type::value_type result(initMinKey, initMaxKey);
941 const ValueType newStartingValue = startingValue +
static_cast<ValueType
>(startIndex);
942 if (buildInParallel) {
943 functor_type functor(val, counts, ptr, theKeys, newStartingValue,
944 initMinKey, initMaxKey);
945 typedef Kokkos::RangePolicy<execution_space, offset_type> range_type;
946 Kokkos::parallel_reduce(
"Tpetra::Details::FixedHashTable::FillPairs", range_type(0, theNumKeys), functor, result);
948 Kokkos::HostSpace hostMemSpace;
949 auto counts_h = Kokkos::create_mirror_view_and_copy(hostMemSpace, counts);
950 auto ptr_h = Kokkos::create_mirror_view_and_copy(hostMemSpace, ptr);
951 auto val_h = Kokkos::create_mirror_view_and_copy(hostMemSpace, val);
952 for (offset_type k = 0; k < theNumKeys; ++k) {
953 typedef typename hash_type::result_type hash_value_type;
954 const KeyType key = theKeysHost[k];
955 if (key > result.maxKey_) {
956 result.maxKey_ = key;
958 if (key < result.minKey_) {
959 result.minKey_ = key;
961 const ValueType theVal = newStartingValue +
static_cast<ValueType
>(k);
962 const hash_value_type hashVal = hash_type::hashFunc(key, size);
965 const offset_type count = counts_h[hashVal];
968 result.success_ =
false;
971 const offset_type curPos = ptr_h[hashVal + 1] - count;
972 val_h[curPos].first = key;
973 val_h[curPos].second = theVal;
976 Kokkos::deep_copy(counts, counts_h);
977 Kokkos::deep_copy(val, val_h);
992 minKey_ = result.minKey_;
993 maxKey_ = result.maxKey_;
997template <
class KeyType,
class ValueType,
class DeviceType>
998void FixedHashTable<KeyType, ValueType, DeviceType>::
999 init(
const host_input_keys_type& keys,
1000 const host_input_vals_type& vals,
1002 KeyType initMaxKey) {
1004 const offset_type numKeys =
static_cast<offset_type
>(keys.extent(0));
1005 TEUCHOS_TEST_FOR_EXCEPTION(
static_cast<unsigned long long>(numKeys) >
static_cast<unsigned long long>(::KokkosKernels::ArithTraits<ValueType>::max()),
1006 std::invalid_argument,
1007 "Tpetra::Details::FixedHashTable: The number of "
1009 << numKeys <<
" is greater than the maximum representable "
1011 << ::KokkosKernels::ArithTraits<ValueType>::max() <<
".");
1012 TEUCHOS_TEST_FOR_EXCEPTION(numKeys >
static_cast<offset_type
>(INT_MAX), std::logic_error,
1014 "Details::FixedHashTable: This class currently only works when the number "
1015 "of keys is <= INT_MAX = "
1016 << INT_MAX <<
". If this is a problem for you"
1017 ", please talk to the Tpetra developers.");
1024 const offset_type size = hash_type::getRecommendedSize(numKeys);
1025#ifdef HAVE_TPETRA_DEBUG
1026 TEUCHOS_TEST_FOR_EXCEPTION(
1027 size == 0 && numKeys != 0, std::logic_error,
1028 "Tpetra::Details::FixedHashTable constructor: "
1029 "getRecommendedSize("
1030 << numKeys <<
") returned zero, "
1031 "even though the number of keys "
1032 << numKeys <<
" is nonzero. "
1033 "Please report this bug to the Tpetra developers.");
1042 Kokkos::HostSpace hostMemSpace;
1043 typename ptr_type::non_const_type ptr(
"Tpetra::FixedHashTable::ptr", size + 1);
1044 auto ptr_h = Kokkos::create_mirror_view_and_copy(hostMemSpace, ptr);
1048 using Kokkos::ViewAllocateWithoutInitializing;
1049 typedef typename val_type::non_const_type nonconst_val_type;
1050 nonconst_val_type val(ViewAllocateWithoutInitializing(
"Tpetra::FixedHashTable::pairs"),
1052 auto val_h = Kokkos::create_mirror_view_and_copy(hostMemSpace, val);
1055 for (offset_type k = 0; k < numKeys; ++k) {
1056 const typename hash_type::result_type hashVal =
1057 hash_type::hashFunc(keys[k], size);
1059 ++ptr_h[hashVal + 1];
1069 for (offset_type i = 0; i < size; ++i) {
1070 ptr_h[i + 1] += ptr_h[i];
1075 typename ptr_type::non_const_type::host_mirror_type curRowStart(
"Tpetra::FixedHashTable::curRowStart", size);
1078 FHT::FillPairsResult<KeyType> result(initMinKey, initMaxKey);
1079 for (offset_type k = 0; k < numKeys; ++k) {
1080 typedef typename hash_type::result_type hash_value_type;
1081 const KeyType key = keys[k];
1082 if (key > result.maxKey_) {
1083 result.maxKey_ = key;
1085 if (key < result.minKey_) {
1086 result.minKey_ = key;
1088 const ValueType theVal = vals[k];
1089 if (theVal > maxVal_) {
1092 if (theVal < minVal_) {
1095 const hash_value_type hashVal = hash_type::hashFunc(key, size);
1097 const offset_type offset = curRowStart[hashVal];
1098 const offset_type curPos = ptr_h[hashVal] + offset;
1099 if (curPos >= ptr_h[hashVal + 1]) {
1100 result.success_ =
false;
1102 val_h[curPos].first = key;
1103 val_h[curPos].second = theVal;
1104 ++curRowStart[hashVal];
1108 TEUCHOS_TEST_FOR_EXCEPTION(!result.success_, std::logic_error,
1109 "Tpetra::Details::FixedHashTable::"
1110 "init: Filling the hash table failed! Please report this bug to the "
1111 "Tpetra developers.");
1114 Kokkos::deep_copy(ptr, ptr_h);
1115 Kokkos::deep_copy(val, val_h);
1119 minKey_ = result.minKey_;
1120 maxKey_ = result.maxKey_;
1124template <
class KeyType,
class ValueType,
class DeviceType>
1127 if (!checkedForDuplicateKeys_) {
1128 hasDuplicateKeys_ = checkForDuplicateKeys();
1129 checkedForDuplicateKeys_ =
true;
1131 return hasDuplicateKeys_;
1134template <
class KeyType,
class ValueType,
class DeviceType>
1137 const offset_type
size = this->getSize();
1141 if (
size == 0 || this->numPairs() == 0) {
1144 typedef FHT::CheckForDuplicateKeys<ptr_type, val_type>
functor_type;
1147 typedef Kokkos::RangePolicy<execution_space, offset_type> range_type;
1148 Kokkos::parallel_reduce(
"Tpetra::Details::FixedHashTable::CheckForDuplicateKeys", range_type(0,
size),
functor,
hasDupKeys);
1153template <
class KeyType,
class ValueType,
class DeviceType>
1157 std::ostringstream
oss;
1158 oss <<
"FixedHashTable<"
1159 << Teuchos::TypeNameTraits<KeyType>::name() <<
","
1160 << Teuchos::TypeNameTraits<ValueType>::name() <<
">: "
1161 <<
"{ numKeys: " << val_.extent(0)
1162 <<
", tableSize: " << this->getSize() <<
" }";
1166template <
class KeyType,
class ValueType,
class DeviceType>
1169 const Teuchos::EVerbosityLevel
verbLevel)
const {
1172 using Teuchos::OSTab;
1173 using Teuchos::rcpFromRef;
1174 using Teuchos::TypeNameTraits;
1175 using Teuchos::VERB_DEFAULT;
1176 using Teuchos::VERB_EXTREME;
1177 using Teuchos::VERB_LOW;
1178 using Teuchos::VERB_NONE;
1189 out << this->description() <<
endl;
1191 out <<
"FixedHashTable:" <<
endl;
1199 out <<
"Template parameters:" <<
endl;
1206 const offset_type
tableSize = this->getSize();
1207 const offset_type
numKeys = val_.extent(0);
1209 out <<
"Table parameters:" <<
endl;
1217 out <<
"Contents: ";
1227 for (offset_type
k = ptr_[
i];
k < ptr_[
i + 1]; ++
k) {
1228 out <<
"(" << val_[
k].first <<
"," << val_[
k].second <<
")";
1229 if (
k + 1 < ptr_[
i + 1]) {