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_;
409template <
class OffsetsViewType,
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;
418 typedef SizeType size_type;
421 typedef int value_type;
428 const offsets_view_type& ptr)
431 , size_(ptr_.extent(0) == 0 ? size_type(0) : ptr_.extent(0) - 1) {}
434 KOKKOS_INLINE_FUNCTION
void init(value_type& dst)
const {
439 KOKKOS_INLINE_FUNCTION
void
441 const value_type& src)
const {
442 dst = dst + src > 0 ? 1 : 0;
446 KOKKOS_INLINE_FUNCTION
void
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];
457 bool foundDuplicateKey =
false;
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) {
465 if (pairs_[k].first == curKey) {
466 foundDuplicateKey =
true;
471 dst = (dst > 0) || foundDuplicateKey ? 1 : 0;
476 pairs_view_type pairs_;
477 offsets_view_type ptr_;
487template <
class KeyType,
class ValueType,
class DeviceType>
491 , maxVal_(keys.size() == 0 ? static_cast<ValueType>(0) : static_cast<ValueType>(keys.size() - 1))
492 , checkedForDuplicateKeys_(false) {
493 const ValueType startingValue =
static_cast<ValueType
>(0);
494 const KeyType initMinKey = this->minKey_;
495 const KeyType initMaxKey = this->maxKey_;
496 this->init(keys, startingValue, initMinKey, initMaxKey,
497 initMinKey, initMinKey,
false);
500template <
class KeyType,
class ValueType,
class DeviceType>
504 , maxVal_(keys.size() == 0 ? static_cast<ValueType>(0) : static_cast<ValueType>(keys.size() - 1))
505 , checkedForDuplicateKeys_(false) {
506 typedef typename keys_type::non_const_type nonconst_keys_type;
511 const ValueType startingValue =
static_cast<ValueType
>(0);
512 host_input_keys_type keys_k(keys.size() == 0 ? NULL : keys.getRawPtr(),
514 using Kokkos::ViewAllocateWithoutInitializing;
515 nonconst_keys_type keys_d(ViewAllocateWithoutInitializing(
"FixedHashTable::keys"),
518 Kokkos::deep_copy(keys_d, keys_k);
519 const KeyType initMinKey = this->minKey_;
520 const KeyType initMaxKey = this->maxKey_;
521 this->init(keys_d, startingValue, initMinKey, initMaxKey,
522 initMinKey, initMinKey,
false);
525template <
class KeyType,
class ValueType,
class DeviceType>
528 const ValueType startingValue)
529 : minVal_(startingValue)
530 , maxVal_(keys.size() == 0 ? startingValue : static_cast<ValueType>(startingValue + keys.size() - 1))
531 , checkedForDuplicateKeys_(false) {
532 typedef typename keys_type::non_const_type nonconst_keys_type;
537 host_input_keys_type keys_k(keys.size() == 0 ? NULL : keys.getRawPtr(),
539 using Kokkos::ViewAllocateWithoutInitializing;
540 nonconst_keys_type keys_d(ViewAllocateWithoutInitializing(
"FixedHashTable::keys"),
543 Kokkos::deep_copy(execution_space(), keys_d, keys_k);
545 const KeyType initMinKey = ::KokkosKernels::ArithTraits<KeyType>::max();
558 const KeyType initMaxKey = ::KokkosKernels::ArithTraits<KeyType>::is_integer ? ::KokkosKernels::ArithTraits<KeyType>::min() : -::KokkosKernels::ArithTraits<KeyType>::max();
559 this->init(keys_d, startingValue, initMinKey, initMaxKey,
560 initMinKey, initMinKey,
false);
563template <
class KeyType,
class ValueType,
class DeviceType>
566 const KeyType firstContigKey,
567 const KeyType lastContigKey,
568 const ValueType startingValue)
569 : minVal_(startingValue)
570 , maxVal_(keys.size() == 0 ? startingValue : static_cast<ValueType>(startingValue + keys.size() - 1))
571 , firstContigKey_(firstContigKey)
572 , lastContigKey_(lastContigKey)
573 , checkedForDuplicateKeys_(false) {
574 const KeyType initMinKey = ::KokkosKernels::ArithTraits<KeyType>::max();
587 const KeyType initMaxKey = ::KokkosKernels::ArithTraits<KeyType>::is_integer ? ::KokkosKernels::ArithTraits<KeyType>::min() : -::KokkosKernels::ArithTraits<KeyType>::max();
588 this->init(keys, startingValue, initMinKey, initMaxKey,
589 firstContigKey, lastContigKey,
true);
592template <
class KeyType,
class ValueType,
class DeviceType>
595 const KeyType firstContigKey,
596 const KeyType lastContigKey,
597 const ValueType startingValue)
598 : minVal_(startingValue)
599 , maxVal_(keys.size() == 0 ? startingValue : static_cast<ValueType>(startingValue + keys.size() - 1))
600 , firstContigKey_(firstContigKey)
601 , lastContigKey_(lastContigKey)
602 , checkedForDuplicateKeys_(false) {
603 typedef typename keys_type::non_const_type nonconst_keys_type;
608 host_input_keys_type keys_k(keys.size() == 0 ? NULL : keys.getRawPtr(),
610 using Kokkos::ViewAllocateWithoutInitializing;
611 nonconst_keys_type keys_d(ViewAllocateWithoutInitializing(
"FixedHashTable::keys"),
614 Kokkos::deep_copy(keys_d, keys_k);
616 const KeyType initMinKey = ::KokkosKernels::ArithTraits<KeyType>::max();
629 const KeyType initMaxKey = ::KokkosKernels::ArithTraits<KeyType>::is_integer ? ::KokkosKernels::ArithTraits<KeyType>::min() : -::KokkosKernels::ArithTraits<KeyType>::max();
630 this->init(keys_d, startingValue, initMinKey, initMaxKey,
631 firstContigKey, lastContigKey,
true);
634template <
class KeyType,
class ValueType,
class DeviceType>
637 const ValueType startingValue)
638 : minVal_(startingValue)
639 , maxVal_(keys.size() == 0 ? startingValue : static_cast<ValueType>(startingValue + keys.size() - 1))
640 , checkedForDuplicateKeys_(false) {
641 const KeyType initMinKey = ::KokkosKernels::ArithTraits<KeyType>::max();
654 const KeyType initMaxKey = ::KokkosKernels::ArithTraits<KeyType>::is_integer ? ::KokkosKernels::ArithTraits<KeyType>::min() : -::KokkosKernels::ArithTraits<KeyType>::max();
655 this->init(keys, startingValue, initMinKey, initMaxKey,
656 initMinKey, initMinKey,
false);
659template <
class KeyType,
class ValueType,
class DeviceType>
662 const Teuchos::ArrayView<const ValueType>& vals)
663 : contiguousValues_(false)
664 , checkedForDuplicateKeys_(false) {
668 host_input_keys_type keys_k(keys.size() == 0 ? NULL : keys.getRawPtr(),
670 host_input_vals_type vals_k(vals.size() == 0 ? NULL : vals.getRawPtr(),
672 const KeyType initMinKey = ::KokkosKernels::ArithTraits<KeyType>::max();
685 const KeyType initMaxKey = ::KokkosKernels::ArithTraits<KeyType>::is_integer ? ::KokkosKernels::ArithTraits<KeyType>::min() : -::KokkosKernels::ArithTraits<KeyType>::max();
686 this->init(keys_k, vals_k, initMinKey, initMaxKey);
689template <
class KeyType,
class ValueType,
class DeviceType>
691 init(
const keys_type& keys,
692 ValueType startingValue,
695 KeyType firstContigKey,
696 KeyType lastContigKey,
697 const bool computeInitContigKeys) {
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();
708 const size_type maxValST =
static_cast<size_type
>(theMaxVal);
709 TEUCHOS_TEST_FOR_EXCEPTION(keys.extent(0) > maxValST, std::invalid_argument, prefix <<
"The "
711 << keys.extent(0) <<
" does not fit in "
713 << TypeNameTraits<offset_type>::name() <<
", whose "
715 << theMaxVal <<
". This means that it is not possible to "
716 "use this constructor.");
718 TEUCHOS_TEST_FOR_EXCEPTION(
static_cast<unsigned long long>(numKeys) >
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.");
727 TEUCHOS_TEST_FOR_EXCEPTION(numKeys >
static_cast<offset_type
>(INT_MAX), std::logic_error, prefix <<
"This class currently only works when the number of keys is <= INT_MAX = " << INT_MAX <<
". If this is a problem for you, please talk to the Tpetra "
730 const bool buildInParallel =
731 FHT::worthBuildingFixedHashTableInParallel<execution_space>();
742 if (computeInitContigKeys) {
756 auto keys_h = Kokkos::create_mirror_view_and_copy(Kokkos::HostSpace(),
758 firstContigKey_ = keys_h[0];
762 lastContigKey_ = firstContigKey_ + 1;
768 for (offset_type k = 1; k < numKeys; ++k) {
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) {
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 execution_space().fence();
848 auto countsHost = Kokkos::create_mirror_view(hostMemSpace, counts);
850 for (offset_type k = 0; k < theNumKeys; ++k) {
851 using key_type =
typename keys_type::non_const_value_type;
852 const key_type key = theKeysHost[k];
854 using hash_value_type =
typename hash_type::result_type;
855 const hash_value_type hashVal = hash_type::hashFunc(key, size);
856 TEUCHOS_TEST_FOR_EXCEPTION(hashVal < hash_value_type(0) ||
857 hashVal >= hash_value_type(countsHost.extent(0)),
859 "Tpetra::Details::FixedHashTable "
860 "constructor: Sequential CountBuckets found a key "
862 <<
" that results in an out-of-bounds hash value.");
864 ++countsHost[hashVal];
867 Kokkos::deep_copy(execution_space(), counts, countsHost);
873 execution_space().fence();
876 typename ptr_type::non_const_type ptr(
"Tpetra::FixedHashTable::ptr", size + 1);
892 if (buildInParallel) {
896 if (!buildInParallel || debug) {
897 Kokkos::HostSpace hostMemSpace;
898 auto counts_h = Kokkos::create_mirror_view_and_copy(hostMemSpace, counts);
899 auto ptr_h = Kokkos::create_mirror_view(hostMemSpace, ptr);
901#ifdef KOKKOS_ENABLE_SERIAL
902 Kokkos::Serial hostExecSpace;
904 Kokkos::DefaultHostExecutionSpace hostExecSpace;
909 Kokkos::deep_copy(execution_space(), ptr, ptr_h);
913 for (offset_type i = 0; i < size; ++i) {
914 if (ptr_h[i + 1] != ptr_h[i] + counts_h[i]) {
918 TEUCHOS_TEST_FOR_EXCEPTION(bad, std::logic_error,
919 "Tpetra::Details::FixedHashTable "
920 "constructor: computeOffsetsFromCounts gave an incorrect "
928 execution_space().fence();
932 typedef typename val_type::non_const_type nonconst_val_type;
933 nonconst_val_type val(ViewAllocateWithoutInitializing(
"Tpetra::FixedHashTable::pairs"),
937 typedef FHT::FillPairs<
typename val_type::non_const_type, keys_type,
938 typename ptr_type::non_const_type>
940 typename functor_type::value_type result(initMinKey, initMaxKey);
942 const ValueType newStartingValue = startingValue +
static_cast<ValueType
>(startIndex);
943 if (buildInParallel) {
944 functor_type functor(val, counts, ptr, theKeys, newStartingValue,
945 initMinKey, initMaxKey);
946 typedef Kokkos::RangePolicy<execution_space, offset_type> range_type;
947 Kokkos::parallel_reduce(
"Tpetra::Details::FixedHashTable::FillPairs", range_type(0, theNumKeys), functor, result);
949 Kokkos::HostSpace hostMemSpace;
950 auto counts_h = Kokkos::create_mirror_view_and_copy(hostMemSpace, counts);
951 auto ptr_h = Kokkos::create_mirror_view_and_copy(hostMemSpace, ptr);
952 auto val_h = Kokkos::create_mirror_view_and_copy(hostMemSpace, val);
953 for (offset_type k = 0; k < theNumKeys; ++k) {
954 typedef typename hash_type::result_type hash_value_type;
955 const KeyType key = theKeysHost[k];
956 if (key > result.maxKey_) {
957 result.maxKey_ = key;
959 if (key < result.minKey_) {
960 result.minKey_ = key;
962 const ValueType theVal = newStartingValue +
static_cast<ValueType
>(k);
963 const hash_value_type hashVal = hash_type::hashFunc(key, size);
966 const offset_type count = counts_h[hashVal];
969 result.success_ =
false;
972 const offset_type curPos = ptr_h[hashVal + 1] - count;
973 val_h[curPos].first = key;
974 val_h[curPos].second = theVal;
977 Kokkos::deep_copy(counts, counts_h);
978 Kokkos::deep_copy(val, val_h);
993 minKey_ = result.minKey_;
994 maxKey_ = result.maxKey_;
998template <
class KeyType,
class ValueType,
class DeviceType>
1000 init(
const host_input_keys_type& keys,
1001 const host_input_vals_type& vals,
1003 KeyType initMaxKey) {
1004 Tpetra::Details::ProfilingRegion pr(
"Tpetra::Details::FixedHashTable::init(4-arg)");
1005 const offset_type numKeys =
static_cast<offset_type
>(keys.extent(0));
1006 TEUCHOS_TEST_FOR_EXCEPTION(
static_cast<unsigned long long>(numKeys) >
static_cast<unsigned long long>(::KokkosKernels::ArithTraits<ValueType>::max()),
1007 std::invalid_argument,
1008 "Tpetra::Details::FixedHashTable: The number of "
1010 << numKeys <<
" is greater than the maximum representable "
1012 << ::KokkosKernels::ArithTraits<ValueType>::max() <<
".");
1013 TEUCHOS_TEST_FOR_EXCEPTION(numKeys >
static_cast<offset_type
>(INT_MAX), std::logic_error,
1015 "Details::FixedHashTable: This class currently only works when the number "
1016 "of keys is <= INT_MAX = "
1017 << INT_MAX <<
". If this is a problem for you"
1018 ", please talk to the Tpetra developers.");
1025 const offset_type size = hash_type::getRecommendedSize(numKeys);
1026#ifdef HAVE_TPETRA_DEBUG
1027 TEUCHOS_TEST_FOR_EXCEPTION(
1028 size == 0 && numKeys != 0, std::logic_error,
1029 "Tpetra::Details::FixedHashTable constructor: "
1030 "getRecommendedSize("
1031 << numKeys <<
") returned zero, "
1032 "even though the number of keys "
1033 << numKeys <<
" is nonzero. "
1034 "Please report this bug to the Tpetra developers.");
1043 Kokkos::HostSpace hostMemSpace;
1044 typename ptr_type::non_const_type ptr(
"Tpetra::FixedHashTable::ptr", size + 1);
1045 auto ptr_h = Kokkos::create_mirror_view_and_copy(hostMemSpace, ptr);
1049 using Kokkos::ViewAllocateWithoutInitializing;
1050 typedef typename val_type::non_const_type nonconst_val_type;
1051 nonconst_val_type val(ViewAllocateWithoutInitializing(
"Tpetra::FixedHashTable::pairs"),
1053 auto val_h = Kokkos::create_mirror_view_and_copy(hostMemSpace, val);
1056 for (offset_type k = 0; k < numKeys; ++k) {
1057 const typename hash_type::result_type hashVal =
1058 hash_type::hashFunc(keys[k], size);
1060 ++ptr_h[hashVal + 1];
1070 for (offset_type i = 0; i < size; ++i) {
1071 ptr_h[i + 1] += ptr_h[i];
1076 typename ptr_type::non_const_type::host_mirror_type curRowStart(
"Tpetra::FixedHashTable::curRowStart", size);
1080 for (offset_type k = 0; k < numKeys; ++k) {
1081 typedef typename hash_type::result_type hash_value_type;
1082 const KeyType key = keys[k];
1083 if (key > result.maxKey_) {
1084 result.maxKey_ = key;
1086 if (key < result.minKey_) {
1087 result.minKey_ = key;
1089 const ValueType theVal = vals[k];
1090 if (theVal > maxVal_) {
1093 if (theVal < minVal_) {
1096 const hash_value_type hashVal = hash_type::hashFunc(key, size);
1098 const offset_type offset = curRowStart[hashVal];
1099 const offset_type curPos = ptr_h[hashVal] + offset;
1100 if (curPos >= ptr_h[hashVal + 1]) {
1101 result.success_ =
false;
1103 val_h[curPos].first = key;
1104 val_h[curPos].second = theVal;
1105 ++curRowStart[hashVal];
1109 TEUCHOS_TEST_FOR_EXCEPTION(!result.success_, std::logic_error,
1110 "Tpetra::Details::FixedHashTable::"
1111 "init: Filling the hash table failed! Please report this bug to the "
1112 "Tpetra developers.");
1115 Kokkos::deep_copy(ptr, ptr_h);
1116 Kokkos::deep_copy(val, val_h);
1120 minKey_ = result.minKey_;
1121 maxKey_ = result.maxKey_;
1125template <
class KeyType,
class ValueType,
class DeviceType>
1128 if (!checkedForDuplicateKeys_) {
1129 hasDuplicateKeys_ = checkForDuplicateKeys();
1130 checkedForDuplicateKeys_ =
true;
1132 return hasDuplicateKeys_;
1135template <
class KeyType,
class ValueType,
class DeviceType>
1138 const offset_type size = this->getSize();
1142 if (size == 0 || this->numPairs() == 0) {
1145 typedef FHT::CheckForDuplicateKeys<ptr_type, val_type> functor_type;
1146 functor_type functor(val_, ptr_);
1148 typedef Kokkos::RangePolicy<execution_space, offset_type> range_type;
1149 Kokkos::parallel_reduce(
"Tpetra::Details::FixedHashTable::CheckForDuplicateKeys", range_type(0, size), functor, hasDupKeys);
1150 return hasDupKeys > 0;
1154template <
class KeyType,
class ValueType,
class DeviceType>
1158 std::ostringstream oss;
1159 oss <<
"FixedHashTable<"
1160 << Teuchos::TypeNameTraits<KeyType>::name() <<
","
1161 << Teuchos::TypeNameTraits<ValueType>::name() <<
">: "
1162 <<
"{ numKeys: " << val_.extent(0)
1163 <<
", tableSize: " << this->getSize() <<
" }";
1167template <
class KeyType,
class ValueType,
class DeviceType>
1169 describe(Teuchos::FancyOStream& out,
1170 const Teuchos::EVerbosityLevel verbLevel)
const {
1173 using Teuchos::OSTab;
1174 using Teuchos::rcpFromRef;
1175 using Teuchos::TypeNameTraits;
1176 using Teuchos::VERB_DEFAULT;
1177 using Teuchos::VERB_EXTREME;
1178 using Teuchos::VERB_LOW;
1179 using Teuchos::VERB_NONE;
1184 Teuchos::EVerbosityLevel vl = verbLevel;
1185 if (vl == VERB_DEFAULT) vl = VERB_LOW;
1187 if (vl == VERB_NONE) {
1189 }
else if (vl == VERB_LOW) {
1192 out <<
"FixedHashTable:" << endl;
1194 OSTab tab1(rcpFromRef(out));
1200 out <<
"Template parameters:" << endl;
1202 OSTab tab2(rcpFromRef(out));
1203 out <<
"KeyType: " << TypeNameTraits<KeyType>::name() << endl
1204 <<
"ValueType: " << TypeNameTraits<ValueType>::name() << endl;
1207 const offset_type tableSize = this->getSize();
1208 const offset_type numKeys = val_.extent(0);
1210 out <<
"Table parameters:" << endl;
1212 OSTab tab2(rcpFromRef(out));
1213 out <<
"numKeys: " << numKeys << endl
1214 <<
"tableSize: " << tableSize << endl;
1217 if (vl >= VERB_EXTREME) {
1218 out <<
"Contents: ";
1219 if (tableSize == 0 || numKeys == 0) {
1220 out <<
"[]" << endl;
1222 out <<
"[ " << endl;
1224 OSTab tab2(rcpFromRef(out));
1225 for (offset_type i = 0; i < tableSize; ++i) {
1226 OSTab tab3(rcpFromRef(out));
1228 for (offset_type k = ptr_[i]; k < ptr_[i + 1]; ++k) {
1229 out <<
"(" << val_[k].first <<
"," << val_[k].second <<
")";
1230 if (k + 1 < ptr_[i + 1]) {