44 #ifndef TPETRA_DETAILS_FIXEDHASHTABLE_DEF_HPP
45 #define TPETRA_DETAILS_FIXEDHASHTABLE_DEF_HPP
47 #include "Tpetra_Details_FixedHashTable_decl.hpp"
49 #ifdef TPETRA_USE_MURMUR_HASH
50 # include "Kokkos_Functional.hpp"
51 #endif // TPETRA_USE_MURMUR_HASH
52 #include "Kokkos_ArithTraits.hpp"
53 #include "Teuchos_TypeNameTraits.hpp"
55 #include <type_traits>
78 template<
class ExecSpace>
79 bool worthBuildingFixedHashTableInParallel () {
80 return ExecSpace::concurrency() > 1;
101 template<
class CountsViewType,
103 class SizeType =
typename KeysViewType::size_type>
106 typedef CountsViewType counts_view_type;
107 typedef KeysViewType keys_view_type;
108 typedef typename CountsViewType::execution_space execution_space;
109 typedef typename CountsViewType::memory_space memory_space;
110 typedef SizeType size_type;
111 typedef typename keys_view_type::non_const_value_type key_type;
127 const keys_view_type& keys,
128 const size_type size) :
138 KOKKOS_INLINE_FUNCTION
void
144 Kokkos::atomic_increment (&counts_[hashVal]);
147 using value_type = Kokkos::pair<int, key_type>;
152 KOKKOS_INLINE_FUNCTION
void
157 const key_type keyVal = keys_[i];
159 if (hashVal < hash_value_type (0) ||
160 hashVal >= hash_value_type (counts_.extent (0))) {
165 Kokkos::atomic_increment (&counts_[hashVal]);
170 KOKKOS_INLINE_FUNCTION
void init (value_type& dst)
const
173 dst.second = key_type (0);
176 KOKKOS_INLINE_FUNCTION
void
177 join (
volatile value_type& dst,
178 const volatile value_type& src)
const
180 const bool good = dst.first == 0 || src.first == 0;
181 dst.first = good ? 0 : dst.first;
187 counts_view_type counts_;
189 keys_view_type keys_;
204 template<
class KeyType>
206 KOKKOS_INLINE_FUNCTION
208 minKey_ (::Kokkos::Details::ArithTraits<KeyType>::max ()),
221 maxKey_ (::Kokkos::Details::ArithTraits<KeyType>::is_integer ?
222 ::Kokkos::Details::ArithTraits<KeyType>::min () :
223 -::Kokkos::Details::ArithTraits<KeyType>::max ()),
226 static_assert (std::is_arithmetic<KeyType>::value,
"FillPairsResult: "
227 "KeyType must be some kind of number type.");
230 KOKKOS_INLINE_FUNCTION
231 FillPairsResult (
const KeyType& initMinKey,
232 const KeyType& initMaxKey) :
237 static_assert (std::is_arithmetic<KeyType>::value,
"FillPairsResult: "
238 "KeyType must be some kind of number type.");
275 template<
class PairsViewType,
277 class CountsViewType,
278 class SizeType =
typename KeysViewType::size_type>
281 typedef typename CountsViewType::non_const_type counts_view_type;
282 typedef typename counts_view_type::const_type offsets_view_type;
284 typedef PairsViewType pairs_view_type;
285 typedef typename KeysViewType::const_type keys_view_type;
286 typedef typename offsets_view_type::execution_space execution_space;
287 typedef typename offsets_view_type::memory_space memory_space;
288 typedef SizeType size_type;
290 typedef typename keys_view_type::non_const_value_type key_type;
291 typedef typename pairs_view_type::non_const_value_type pair_type;
315 const counts_view_type& counts,
316 const offsets_view_type& ptr,
317 const keys_view_type& keys,
318 const typename pair_type::second_type startingValue) :
323 size_ (counts.extent (0)),
324 startingValue_ (startingValue),
325 initMinKey_ (::Kokkos::Details::ArithTraits<key_type>::max ()),
326 initMaxKey_ (::Kokkos::Details::ArithTraits<key_type>::is_integer ?
327 ::Kokkos::Details::ArithTraits<key_type>::min () :
328 -::Kokkos::Details::ArithTraits<key_type>::max ())
350 const counts_view_type& counts,
351 const offsets_view_type& ptr,
352 const keys_view_type& keys,
353 const typename pair_type::second_type startingValue,
354 const key_type initMinKey,
355 const key_type initMaxKey) :
360 size_ (counts.extent (0)),
361 startingValue_ (startingValue),
362 initMinKey_ (initMinKey),
363 initMaxKey_ (initMaxKey)
374 KOKKOS_INLINE_FUNCTION
void
375 join (
volatile value_type& dst,
376 const volatile value_type& src)
const
378 if (src.maxKey_ > dst.maxKey_) {
379 dst.maxKey_ = src.maxKey_;
381 if (src.minKey_ < dst.minKey_) {
382 dst.minKey_ = src.minKey_;
384 dst.success_ = dst.success_ && src.success_;
391 KOKKOS_INLINE_FUNCTION
void
395 typedef typename offsets_view_type::non_const_value_type offset_type;
396 typedef typename pair_type::second_type val_type;
397 typedef typename std::remove_reference< decltype( counts_[0] ) >::type atomic_incr_type;
399 const key_type key = keys_[i];
406 const val_type theVal = startingValue_ +
static_cast<val_type
> (i);
410 const offset_type count = Kokkos::atomic_fetch_add (&counts_[hashVal], atomic_incr_type(-1));
415 const offset_type curPos = ptr_[hashVal+1] - count;
417 pairs_[curPos].first = key;
418 pairs_[curPos].second = theVal;
423 pairs_view_type pairs_;
424 counts_view_type counts_;
425 offsets_view_type ptr_;
426 keys_view_type keys_;
428 typename pair_type::second_type startingValue_;
430 key_type initMinKey_;
432 key_type initMaxKey_;
458 template<
class OffsetsViewType,
460 class SizeType =
typename OffsetsViewType::size_type>
463 typedef typename OffsetsViewType::const_type offsets_view_type;
464 typedef typename PairsViewType::const_type pairs_view_type;
465 typedef typename offsets_view_type::execution_space execution_space;
466 typedef typename offsets_view_type::memory_space memory_space;
467 typedef SizeType size_type;
470 typedef int value_type;
477 const offsets_view_type& ptr) :
480 size_ (ptr_.extent (0) == 0 ?
486 KOKKOS_INLINE_FUNCTION
void init (value_type& dst)
const
492 KOKKOS_INLINE_FUNCTION
void
493 join (
volatile value_type& dst,
494 const volatile value_type& src)
const
496 dst = dst + src > 0?1:0;
500 KOKKOS_INLINE_FUNCTION
void
503 typedef typename offsets_view_type::non_const_value_type offset_type;
504 typedef typename pairs_view_type::non_const_value_type pair_type;
505 typedef typename pair_type::first_type key_type;
511 const offset_type beg = ptr_[i];
512 const offset_type end = ptr_[i+1];
513 bool foundDuplicateKey =
false;
518 for (offset_type j = beg + 1; j < end; ++j) {
519 const key_type curKey = pairs_[j].first;
520 for (offset_type k = beg; k < j; ++k) {
521 if (pairs_[k].first == curKey) {
522 foundDuplicateKey =
true;
527 dst = (dst>0) || foundDuplicateKey?1:0;
532 pairs_view_type pairs_;
533 offsets_view_type ptr_;
543 template<
class KeyType,
class ValueType,
class DeviceType>
553 return keys_.extent (0) == val_.extent (0);
556 template<
class KeyType,
class ValueType,
class DeviceType>
565 template<
class KeyType,
class ValueType,
class DeviceType>
568 minKey_ (::Kokkos::Details::ArithTraits<KeyType>::max ()),
569 maxKey_ (::Kokkos::Details::ArithTraits<KeyType>::is_integer ?
570 ::Kokkos::Details::ArithTraits<KeyType>::min () :
571 -::Kokkos::Details::ArithTraits<KeyType>::max ()),
572 minVal_ (::Kokkos::Details::ArithTraits<ValueType>::max ()),
573 maxVal_ (::Kokkos::Details::ArithTraits<ValueType>::is_integer ?
574 ::Kokkos::Details::ArithTraits<ValueType>::min () :
575 -::Kokkos::Details::ArithTraits<ValueType>::max ()),
576 firstContigKey_ (::Kokkos::Details::ArithTraits<KeyType>::max ()),
577 lastContigKey_ (::Kokkos::Details::ArithTraits<KeyType>::is_integer ?
578 ::Kokkos::Details::ArithTraits<KeyType>::min () :
579 -::Kokkos::Details::ArithTraits<KeyType>::max ()),
580 contiguousValues_ (true),
581 checkedForDuplicateKeys_ (true),
582 hasDuplicateKeys_ (false)
584 #ifdef HAVE_TPETRA_DEBUG
586 #endif // HAVE_TPETRA_DEBUG
589 template<
class KeyType,
class ValueType,
class DeviceType>
593 minKey_ (::Kokkos::Details::ArithTraits<KeyType>::max ()),
594 maxKey_ (::Kokkos::Details::ArithTraits<KeyType>::is_integer ?
595 ::Kokkos::Details::ArithTraits<KeyType>::min () :
596 -::Kokkos::Details::ArithTraits<KeyType>::max ()),
598 maxVal_ (keys.size () == 0 ?
599 static_cast<ValueType> (0) :
600 static_cast<ValueType> (keys.size () - 1)),
601 firstContigKey_ (::Kokkos::Details::ArithTraits<KeyType>::max ()),
602 lastContigKey_ (::Kokkos::Details::ArithTraits<KeyType>::is_integer ?
603 ::Kokkos::Details::ArithTraits<KeyType>::min () :
604 -::Kokkos::Details::ArithTraits<KeyType>::max ()),
605 contiguousValues_ (true),
606 checkedForDuplicateKeys_ (false),
607 hasDuplicateKeys_ (false)
609 const ValueType startingValue =
static_cast<ValueType
> (0);
610 const KeyType initMinKey = this->minKey_;
611 const KeyType initMaxKey = this->maxKey_;
612 this->init (keys, startingValue, initMinKey, initMaxKey,
613 initMinKey, initMinKey,
false);
615 #ifdef HAVE_TPETRA_DEBUG
617 #endif // HAVE_TPETRA_DEBUG
620 template<
class KeyType,
class ValueType,
class DeviceType>
623 const bool keepKeys) :
624 minKey_ (::Kokkos::Details::ArithTraits<KeyType>::max ()),
625 maxKey_ (::Kokkos::Details::ArithTraits<KeyType>::is_integer ?
626 ::Kokkos::Details::ArithTraits<KeyType>::min () :
627 -::Kokkos::Details::ArithTraits<KeyType>::max ()),
629 maxVal_ (keys.size () == 0 ?
630 static_cast<ValueType> (0) :
631 static_cast<ValueType> (keys.size () - 1)),
632 firstContigKey_ (::Kokkos::Details::ArithTraits<KeyType>::max ()),
633 lastContigKey_ (::Kokkos::Details::ArithTraits<KeyType>::is_integer ?
634 ::Kokkos::Details::ArithTraits<KeyType>::min () :
635 -::Kokkos::Details::ArithTraits<KeyType>::max ()),
636 contiguousValues_ (true),
637 checkedForDuplicateKeys_ (false),
638 hasDuplicateKeys_ (false)
640 typedef typename keys_type::non_const_type nonconst_keys_type;
645 const ValueType startingValue =
static_cast<ValueType
> (0);
646 host_input_keys_type keys_k (keys.size () == 0 ? NULL : keys.getRawPtr (),
648 using Kokkos::ViewAllocateWithoutInitializing;
649 nonconst_keys_type keys_d (ViewAllocateWithoutInitializing (
"FixedHashTable::keys"),
652 const KeyType initMinKey = this->minKey_;
653 const KeyType initMaxKey = this->maxKey_;
654 this->init (keys_d, startingValue, initMinKey, initMaxKey,
655 initMinKey, initMinKey,
false);
658 #ifdef HAVE_TPETRA_DEBUG
659 typedef typename keys_type::size_type size_type;
660 TEUCHOS_TEST_FOR_EXCEPTION
661 (keys_.extent (0) !=
static_cast<size_type
> (keys.size ()),
662 std::logic_error,
"Tpetra::Details::FixedHashTable constructor: "
663 "keepKeys is true, but on return, keys_.extent(0) = " <<
664 keys_.extent (0) <<
" != keys.size() = " << keys.size () <<
665 ". Please report this bug to the Tpetra developers.");
666 #endif // HAVE_TPETRA_DEBUG
669 #ifdef HAVE_TPETRA_DEBUG
671 #endif // HAVE_TPETRA_DEBUG
674 template<
class KeyType,
class ValueType,
class DeviceType>
677 const ValueType startingValue,
678 const bool keepKeys) :
679 minKey_ (::Kokkos::Details::ArithTraits<KeyType>::max ()),
680 maxKey_ (::Kokkos::Details::ArithTraits<KeyType>::is_integer ?
681 ::Kokkos::Details::ArithTraits<KeyType>::min () :
682 -::Kokkos::Details::ArithTraits<KeyType>::max ()),
683 minVal_ (startingValue),
684 maxVal_ (keys.size () == 0 ?
686 static_cast<ValueType> (startingValue + keys.size () - 1)),
687 firstContigKey_ (::Kokkos::Details::ArithTraits<KeyType>::max ()),
688 lastContigKey_ (::Kokkos::Details::ArithTraits<KeyType>::is_integer ?
689 ::Kokkos::Details::ArithTraits<KeyType>::min () :
690 -::Kokkos::Details::ArithTraits<KeyType>::max ()),
691 contiguousValues_ (true),
692 checkedForDuplicateKeys_ (false),
693 hasDuplicateKeys_ (false)
695 typedef typename keys_type::non_const_type nonconst_keys_type;
700 host_input_keys_type keys_k (keys.size () == 0 ? NULL : keys.getRawPtr (),
702 using Kokkos::ViewAllocateWithoutInitializing;
703 nonconst_keys_type keys_d (ViewAllocateWithoutInitializing (
"FixedHashTable::keys"),
707 const KeyType initMinKey = ::Kokkos::Details::ArithTraits<KeyType>::max ();
720 const KeyType initMaxKey = ::Kokkos::Details::ArithTraits<KeyType>::is_integer ?
721 ::Kokkos::Details::ArithTraits<KeyType>::min () :
722 -::Kokkos::Details::ArithTraits<KeyType>::max ();
723 this->init (keys_d, startingValue, initMinKey, initMaxKey,
724 initMinKey, initMinKey,
false);
727 #ifdef HAVE_TPETRA_DEBUG
728 typedef typename keys_type::size_type size_type;
729 TEUCHOS_TEST_FOR_EXCEPTION
730 (keys_.extent (0) !=
static_cast<size_type
> (keys.size ()),
731 std::logic_error,
"Tpetra::Details::FixedHashTable constructor: "
732 "keepKeys is true, but on return, keys_.extent(0) = " <<
733 keys_.extent (0) <<
" != keys.size() = " << keys.size () <<
734 ". Please report this bug to the Tpetra developers.");
735 #endif // HAVE_TPETRA_DEBUG
738 #ifdef HAVE_TPETRA_DEBUG
740 #endif // HAVE_TPETRA_DEBUG
743 template<
class KeyType,
class ValueType,
class DeviceType>
746 const KeyType firstContigKey,
747 const KeyType lastContigKey,
748 const ValueType startingValue,
749 const bool keepKeys) :
750 minKey_ (::Kokkos::Details::ArithTraits<KeyType>::max ()),
751 maxKey_ (::Kokkos::Details::ArithTraits<KeyType>::is_integer ?
752 ::Kokkos::Details::ArithTraits<KeyType>::min () :
753 -::Kokkos::Details::ArithTraits<KeyType>::max ()),
754 minVal_ (startingValue),
755 maxVal_ (keys.size () == 0 ?
757 static_cast<ValueType> (startingValue + keys.size () - 1)),
758 firstContigKey_ (firstContigKey),
759 lastContigKey_ (lastContigKey),
760 contiguousValues_ (true),
761 checkedForDuplicateKeys_ (false),
762 hasDuplicateKeys_ (false)
764 const KeyType initMinKey = ::Kokkos::Details::ArithTraits<KeyType>::max ();
777 const KeyType initMaxKey = ::Kokkos::Details::ArithTraits<KeyType>::is_integer ?
778 ::Kokkos::Details::ArithTraits<KeyType>::min () :
779 -::Kokkos::Details::ArithTraits<KeyType>::max ();
780 this->init (keys, startingValue, initMinKey, initMaxKey,
781 firstContigKey, lastContigKey,
true);
784 #ifdef HAVE_TPETRA_DEBUG
785 typedef typename keys_type::size_type size_type;
786 TEUCHOS_TEST_FOR_EXCEPTION
787 (keys_.extent (0) !=
static_cast<size_type
> (keys.size ()),
788 std::logic_error,
"Tpetra::Details::FixedHashTable constructor: "
789 "keepKeys is true, but on return, keys_.extent(0) = " <<
790 keys_.extent (0) <<
" != keys.size() = " << keys.size () <<
791 ". Please report this bug to the Tpetra developers.");
792 #endif // HAVE_TPETRA_DEBUG
795 #ifdef HAVE_TPETRA_DEBUG
797 #endif // HAVE_TPETRA_DEBUG
800 template<
class KeyType,
class ValueType,
class DeviceType>
803 const KeyType firstContigKey,
804 const KeyType lastContigKey,
805 const ValueType startingValue,
806 const bool keepKeys) :
807 minKey_ (::Kokkos::Details::ArithTraits<KeyType>::max ()),
808 maxKey_ (::Kokkos::Details::ArithTraits<KeyType>::is_integer ?
809 ::Kokkos::Details::ArithTraits<KeyType>::min () :
810 -::Kokkos::Details::ArithTraits<KeyType>::max ()),
811 minVal_ (startingValue),
812 maxVal_ (keys.size () == 0 ?
814 static_cast<ValueType> (startingValue + keys.size () - 1)),
815 firstContigKey_ (firstContigKey),
816 lastContigKey_ (lastContigKey),
817 contiguousValues_ (true),
818 checkedForDuplicateKeys_ (false),
819 hasDuplicateKeys_ (false)
821 typedef typename keys_type::non_const_type nonconst_keys_type;
826 host_input_keys_type keys_k (keys.size () == 0 ? NULL : keys.getRawPtr (),
828 using Kokkos::ViewAllocateWithoutInitializing;
829 nonconst_keys_type keys_d (ViewAllocateWithoutInitializing (
"FixedHashTable::keys"),
833 const KeyType initMinKey = ::Kokkos::Details::ArithTraits<KeyType>::max ();
846 const KeyType initMaxKey = ::Kokkos::Details::ArithTraits<KeyType>::is_integer ?
847 ::Kokkos::Details::ArithTraits<KeyType>::min () :
848 -::Kokkos::Details::ArithTraits<KeyType>::max ();
849 this->init (keys_d, startingValue, initMinKey, initMaxKey,
850 firstContigKey, lastContigKey,
true);
853 #ifdef HAVE_TPETRA_DEBUG
854 typedef typename keys_type::size_type size_type;
855 TEUCHOS_TEST_FOR_EXCEPTION
856 (keys_.extent (0) !=
static_cast<size_type
> (keys.size ()),
857 std::logic_error,
"Tpetra::Details::FixedHashTable constructor: "
858 "keepKeys is true, but on return, keys_.extent(0) = " <<
859 keys_.extent (0) <<
" != keys.size() = " << keys.size () <<
860 ". Please report this bug to the Tpetra developers.");
861 #endif // HAVE_TPETRA_DEBUG
864 #ifdef HAVE_TPETRA_DEBUG
866 #endif // HAVE_TPETRA_DEBUG
869 template<
class KeyType,
class ValueType,
class DeviceType>
872 const ValueType startingValue) :
874 minKey_ (::Kokkos::Details::ArithTraits<KeyType>::max ()),
875 maxKey_ (::Kokkos::Details::ArithTraits<KeyType>::is_integer ?
876 ::Kokkos::Details::ArithTraits<KeyType>::min () :
877 -::Kokkos::Details::ArithTraits<KeyType>::max ()),
878 minVal_ (startingValue),
879 maxVal_ (keys.size () == 0 ?
881 static_cast<ValueType> (startingValue + keys.size () - 1)),
882 firstContigKey_ (::Kokkos::Details::ArithTraits<KeyType>::max ()),
883 lastContigKey_ (::Kokkos::Details::ArithTraits<KeyType>::is_integer ?
884 ::Kokkos::Details::ArithTraits<KeyType>::min () :
885 -::Kokkos::Details::ArithTraits<KeyType>::max ()),
886 contiguousValues_ (true),
887 checkedForDuplicateKeys_ (false),
888 hasDuplicateKeys_ (false)
890 const KeyType initMinKey = ::Kokkos::Details::ArithTraits<KeyType>::max ();
903 const KeyType initMaxKey = ::Kokkos::Details::ArithTraits<KeyType>::is_integer ?
904 ::Kokkos::Details::ArithTraits<KeyType>::min () :
905 -::Kokkos::Details::ArithTraits<KeyType>::max ();
906 this->init (keys, startingValue, initMinKey, initMaxKey,
907 initMinKey, initMinKey,
false);
909 #ifdef HAVE_TPETRA_DEBUG
911 #endif // HAVE_TPETRA_DEBUG
914 template<
class KeyType,
class ValueType,
class DeviceType>
917 const Teuchos::ArrayView<const ValueType>& vals) :
918 minKey_ (::Kokkos::Details::ArithTraits<KeyType>::max ()),
919 maxKey_ (::Kokkos::Details::ArithTraits<KeyType>::is_integer ?
920 ::Kokkos::Details::ArithTraits<KeyType>::min () :
921 -::Kokkos::Details::ArithTraits<KeyType>::max ()),
922 minVal_ (::Kokkos::Details::ArithTraits<ValueType>::max ()),
923 maxVal_ (::Kokkos::Details::ArithTraits<ValueType>::is_integer ?
924 ::Kokkos::Details::ArithTraits<ValueType>::min () :
925 -::Kokkos::Details::ArithTraits<ValueType>::max ()),
926 firstContigKey_ (::Kokkos::Details::ArithTraits<KeyType>::max ()),
927 lastContigKey_ (::Kokkos::Details::ArithTraits<KeyType>::is_integer ?
928 ::Kokkos::Details::ArithTraits<KeyType>::min () :
929 -::Kokkos::Details::ArithTraits<KeyType>::max ()),
930 contiguousValues_ (false),
931 checkedForDuplicateKeys_ (false),
932 hasDuplicateKeys_ (false)
937 host_input_keys_type keys_k (keys.size () == 0 ? NULL : keys.getRawPtr (),
939 host_input_vals_type vals_k (vals.size () == 0 ? NULL : vals.getRawPtr (),
941 const KeyType initMinKey = ::Kokkos::Details::ArithTraits<KeyType>::max ();
954 const KeyType initMaxKey = ::Kokkos::Details::ArithTraits<KeyType>::is_integer ?
955 ::Kokkos::Details::ArithTraits<KeyType>::min () :
956 -::Kokkos::Details::ArithTraits<KeyType>::max ();
957 this->init (keys_k, vals_k, initMinKey, initMaxKey);
959 #ifdef HAVE_TPETRA_DEBUG
961 #endif // HAVE_TPETRA_DEBUG
964 template<
class KeyType,
class ValueType,
class DeviceType>
967 init (
const keys_type& keys,
968 ValueType startingValue,
971 KeyType firstContigKey,
972 KeyType lastContigKey,
973 const bool computeInitContigKeys)
975 using Kokkos::subview;
976 using Kokkos::ViewAllocateWithoutInitializing;
977 using Teuchos::TypeNameTraits;
978 typedef typename std::decay<decltype (keys.extent (0)) >::type size_type;
979 const char prefix[] =
"Tpetra::Details::FixedHashTable: ";
981 const offset_type numKeys =
static_cast<offset_type
> (keys.extent (0));
983 const offset_type theMaxVal = ::Kokkos::Details::ArithTraits<offset_type>::max ();
984 const size_type maxValST =
static_cast<size_type
> (theMaxVal);
985 TEUCHOS_TEST_FOR_EXCEPTION
986 (keys.extent (0) > maxValST, std::invalid_argument, prefix <<
"The "
987 "number of keys " << keys.extent (0) <<
" does not fit in "
988 "offset_type = " << TypeNameTraits<offset_type>::name () <<
", whose "
989 "max value is " << theMaxVal <<
". This means that it is not possible to "
990 "use this constructor.");
992 TEUCHOS_TEST_FOR_EXCEPTION
993 (static_cast<unsigned long long> (numKeys) >
994 static_cast<unsigned long long> (::Kokkos::Details::ArithTraits<ValueType>::max ()),
995 std::invalid_argument,
"Tpetra::Details::FixedHashTable: The number of "
996 "keys " << numKeys <<
" is greater than the maximum representable "
997 "ValueType value " << ::Kokkos::Details::ArithTraits<ValueType>::max () <<
". "
998 "This means that it is not possible to use this constructor.");
999 TEUCHOS_TEST_FOR_EXCEPTION
1000 (numKeys > static_cast<offset_type> (INT_MAX), std::logic_error, prefix <<
1001 "This class currently only works when the number of keys is <= INT_MAX = "
1002 << INT_MAX <<
". If this is a problem for you, please talk to the Tpetra "
1005 const bool buildInParallel =
1006 FHT::worthBuildingFixedHashTableInParallel<execution_space> ();
1017 if (computeInitContigKeys) {
1036 firstContigKey_ = keys[0];
1040 lastContigKey_ = firstContigKey_ + 1;
1046 for (offset_type k = 1; k < numKeys; ++k) {
1047 if (lastContigKey_ != keys[k]) {
1056 firstContigKey_ = firstContigKey;
1057 lastContigKey_ = lastContigKey;
1060 offset_type startIndex;
1062 initMinKey = std::min (initMinKey, firstContigKey_);
1063 initMaxKey = std::max (initMaxKey, lastContigKey_);
1064 startIndex =
static_cast<offset_type
> (lastContigKey_ - firstContigKey_);
1069 const offset_type theNumKeys = numKeys - startIndex;
1070 const offset_type size = hash_type::getRecommendedSize (theNumKeys);
1071 #ifdef HAVE_TPETRA_DEBUG
1072 TEUCHOS_TEST_FOR_EXCEPTION(
1073 size == 0 && numKeys != 0, std::logic_error,
1074 "Tpetra::Details::FixedHashTable constructor: "
1075 "getRecommendedSize(" << numKeys <<
") returned zero, "
1076 "even though the number of keys " << numKeys <<
" is nonzero. "
1077 "Please report this bug to the Tpetra developers.");
1078 #endif // HAVE_TPETRA_DEBUG
1080 subview (keys, std::pair<offset_type, offset_type> (startIndex, numKeys));
1087 typedef typename ptr_type::non_const_type counts_type;
1088 counts_type counts (
"FixedHashTable::counts", size);
1099 if (buildInParallel) {
1100 FHT::CountBuckets<counts_type, keys_type> functor (counts, theKeys, size);
1101 using execution_space =
typename counts_type::execution_space;
1102 using range_type = Kokkos::RangePolicy<execution_space, offset_type>;
1103 const char kernelLabel[] =
"Tpetra::Details::FixedHashTable CountBuckets";
1105 using key_type =
typename keys_type::non_const_value_type;
1106 Kokkos::pair<int, key_type> err;
1107 Kokkos::parallel_reduce (kernelLabel, range_type (0, theNumKeys),
1109 TEUCHOS_TEST_FOR_EXCEPTION
1110 (err.first != 0, std::logic_error,
"Tpetra::Details::FixedHashTable "
1111 "constructor: CountBuckets found a key " << err.second <<
" that "
1112 "results in an out-of-bounds hash value.");
1115 Kokkos::parallel_for (kernelLabel, range_type (0, theNumKeys), functor);
1123 auto countsHost = Kokkos::create_mirror_view (counts);
1127 for (offset_type k = 0; k < theNumKeys; ++k) {
1128 using key_type =
typename keys_type::non_const_value_type;
1129 const key_type key = theKeys[k];
1131 using hash_value_type =
typename hash_type::result_type;
1132 const hash_value_type hashVal = hash_type::hashFunc (key, size);
1133 TEUCHOS_TEST_FOR_EXCEPTION
1134 (hashVal < hash_value_type (0) ||
1135 hashVal >= hash_value_type (countsHost.extent (0)),
1136 std::logic_error,
"Tpetra::Details::FixedHashTable "
1137 "constructor: Sequential CountBuckets found a key " << key
1138 <<
" that results in an out-of-bounds hash value.");
1140 ++countsHost[hashVal];
1148 execution_space().fence ();
1151 typename ptr_type::non_const_type ptr (
"FixedHashTable::ptr", size+1);
1167 if (buildInParallel) {
1171 if (! buildInParallel || debug) {
1172 Kokkos::HostSpace hostMemSpace;
1173 auto counts_h = Kokkos::create_mirror_view (hostMemSpace, counts);
1175 auto ptr_h = Kokkos::create_mirror_view (hostMemSpace, ptr);
1177 #ifdef KOKKOS_ENABLE_SERIAL
1178 Kokkos::Serial hostExecSpace;
1180 Kokkos::DefaultHostExecutionSpace hostExecSpace;
1181 #endif // KOKKOS_ENABLE_SERIAL
1188 for (offset_type i = 0; i < size; ++i) {
1189 if (ptr_h[i+1] != ptr_h[i] + counts_h[i]) {
1193 TEUCHOS_TEST_FOR_EXCEPTION
1194 (bad, std::logic_error,
"Tpetra::Details::FixedHashTable "
1195 "constructor: computeOffsetsFromCounts gave an incorrect "
1203 execution_space().fence ();
1207 using Kokkos::ViewAllocateWithoutInitializing;
1208 typedef typename val_type::non_const_type nonconst_val_type;
1209 nonconst_val_type val (ViewAllocateWithoutInitializing (
"FixedHashTable::pairs"),
1213 typedef FHT::FillPairs<
typename val_type::non_const_type, keys_type,
1214 typename ptr_type::non_const_type> functor_type;
1215 typename functor_type::value_type result (initMinKey, initMaxKey);
1217 const ValueType newStartingValue = startingValue +
static_cast<ValueType
> (startIndex);
1218 if (buildInParallel) {
1219 functor_type functor (val, counts, ptr, theKeys, newStartingValue,
1220 initMinKey, initMaxKey);
1221 typedef Kokkos::RangePolicy<execution_space, offset_type> range_type;
1222 Kokkos::parallel_reduce (range_type (0, theNumKeys), functor, result);
1225 for (offset_type k = 0; k < theNumKeys; ++k) {
1226 typedef typename hash_type::result_type hash_value_type;
1227 const KeyType key = theKeys[k];
1228 if (key > result.maxKey_) {
1229 result.maxKey_ = key;
1231 if (key < result.minKey_) {
1232 result.minKey_ = key;
1234 const ValueType theVal = newStartingValue +
static_cast<ValueType
> (k);
1235 const hash_value_type hashVal = hash_type::hashFunc (key, size);
1241 const offset_type count = counts[hashVal];
1244 result.success_ =
false;
1249 const offset_type curPos = ptr[hashVal+1] - count;
1252 val[curPos].first = key;
1253 val[curPos].second = theVal;
1270 minKey_ = result.minKey_;
1271 maxKey_ = result.maxKey_;
1276 template<
class KeyType,
class ValueType,
class DeviceType>
1278 FixedHashTable<KeyType, ValueType, DeviceType>::
1279 init (
const host_input_keys_type& keys,
1280 const host_input_vals_type& vals,
1284 const offset_type numKeys =
static_cast<offset_type
> (keys.extent (0));
1285 TEUCHOS_TEST_FOR_EXCEPTION
1286 (static_cast<unsigned long long> (numKeys) > static_cast<unsigned long long> (::Kokkos::Details::ArithTraits<ValueType>::max ()),
1287 std::invalid_argument,
"Tpetra::Details::FixedHashTable: The number of "
1288 "keys " << numKeys <<
" is greater than the maximum representable "
1289 "ValueType value " << ::Kokkos::Details::ArithTraits<ValueType>::max () <<
".");
1290 TEUCHOS_TEST_FOR_EXCEPTION
1291 (numKeys > static_cast<offset_type> (INT_MAX), std::logic_error,
"Tpetra::"
1292 "Details::FixedHashTable: This class currently only works when the number "
1293 "of keys is <= INT_MAX = " << INT_MAX <<
". If this is a problem for you"
1294 ", please talk to the Tpetra developers.");
1301 const offset_type size = hash_type::getRecommendedSize (numKeys);
1302 #ifdef HAVE_TPETRA_DEBUG
1303 TEUCHOS_TEST_FOR_EXCEPTION(
1304 size == 0 && numKeys != 0, std::logic_error,
1305 "Tpetra::Details::FixedHashTable constructor: "
1306 "getRecommendedSize(" << numKeys <<
") returned zero, "
1307 "even though the number of keys " << numKeys <<
" is nonzero. "
1308 "Please report this bug to the Tpetra developers.");
1309 #endif // HAVE_TPETRA_DEBUG
1319 typename ptr_type::non_const_type ptr (
"FixedHashTable::ptr", size + 1);
1323 using Kokkos::ViewAllocateWithoutInitializing;
1324 typedef typename val_type::non_const_type nonconst_val_type;
1325 nonconst_val_type val (ViewAllocateWithoutInitializing (
"FixedHashTable::pairs"),
1329 for (offset_type k = 0; k < numKeys; ++k) {
1330 const typename hash_type::result_type hashVal =
1331 hash_type::hashFunc (keys[k], size);
1343 for (offset_type i = 0; i < size; ++i) {
1349 typename ptr_type::non_const_type curRowStart (
"FixedHashTable::curRowStart", size);
1352 FHT::FillPairsResult<KeyType> result (initMinKey, initMaxKey);
1353 for (offset_type k = 0; k < numKeys; ++k) {
1354 typedef typename hash_type::result_type hash_value_type;
1355 const KeyType key = keys[k];
1356 if (key > result.maxKey_) {
1357 result.maxKey_ = key;
1359 if (key < result.minKey_) {
1360 result.minKey_ = key;
1362 const ValueType theVal = vals[k];
1363 if (theVal > maxVal_) {
1366 if (theVal < minVal_) {
1369 const hash_value_type hashVal = hash_type::hashFunc (key, size);
1371 const offset_type offset = curRowStart[hashVal];
1372 const offset_type curPos = ptr[hashVal] + offset;
1373 if (curPos >= ptr[hashVal+1]) {
1374 result.success_ =
false;
1377 val[curPos].first = key;
1378 val[curPos].second = theVal;
1379 ++curRowStart[hashVal];
1383 TEUCHOS_TEST_FOR_EXCEPTION
1384 (! result.success_, std::logic_error,
"Tpetra::Details::FixedHashTable::"
1385 "init: Filling the hash table failed! Please report this bug to the "
1386 "Tpetra developers.");
1391 minKey_ = result.minKey_;
1392 maxKey_ = result.maxKey_;
1396 template <
class KeyType,
class ValueType,
class DeviceType>
1401 if (! checkedForDuplicateKeys_) {
1402 hasDuplicateKeys_ = checkForDuplicateKeys ();
1403 checkedForDuplicateKeys_ =
true;
1405 return hasDuplicateKeys_;
1408 template <
class KeyType,
class ValueType,
class DeviceType>
1413 const offset_type size = this->getSize ();
1417 if (size == 0 || this->numPairs () == 0) {
1421 typedef FHT::CheckForDuplicateKeys<ptr_type, val_type> functor_type;
1422 functor_type functor (val_, ptr_);
1424 typedef Kokkos::RangePolicy<execution_space, offset_type> range_type;
1425 Kokkos::parallel_reduce (range_type (0, size), functor, hasDupKeys);
1426 return hasDupKeys > 0;
1430 template <
class KeyType,
class ValueType,
class DeviceType>
1435 std::ostringstream oss;
1436 oss <<
"FixedHashTable<"
1437 << Teuchos::TypeNameTraits<KeyType>::name () <<
","
1438 << Teuchos::TypeNameTraits<ValueType>::name () <<
">: "
1439 <<
"{ numKeys: " << val_.extent (0)
1440 <<
", tableSize: " << this->getSize () <<
" }";
1444 template <
class KeyType,
class ValueType,
class DeviceType>
1448 const Teuchos::EVerbosityLevel verbLevel)
const
1452 using Teuchos::OSTab;
1453 using Teuchos::rcpFromRef;
1454 using Teuchos::TypeNameTraits;
1455 using Teuchos::VERB_DEFAULT;
1456 using Teuchos::VERB_NONE;
1457 using Teuchos::VERB_LOW;
1458 using Teuchos::VERB_EXTREME;
1463 Teuchos::EVerbosityLevel vl = verbLevel;
1464 if (vl == VERB_DEFAULT) vl = VERB_LOW;
1466 if (vl == VERB_NONE) {
1469 else if (vl == VERB_LOW) {
1470 out << this->description() << endl;
1473 out <<
"FixedHashTable:" << endl;
1475 OSTab tab1 (rcpFromRef (out));
1481 out <<
"Template parameters:" << endl;
1483 OSTab tab2 (rcpFromRef (out));
1484 out <<
"KeyType: " << TypeNameTraits<KeyType>::name () << endl
1485 <<
"ValueType: " << TypeNameTraits<ValueType>::name () << endl;
1488 const offset_type tableSize = this->getSize ();
1489 const offset_type numKeys = val_.extent (0);
1491 out <<
"Table parameters:" << endl;
1493 OSTab tab2 (rcpFromRef (out));
1494 out <<
"numKeys: " << numKeys << endl
1495 <<
"tableSize: " << tableSize << endl;
1498 if (vl >= VERB_EXTREME) {
1499 out <<
"Contents: ";
1500 if (tableSize == 0 || numKeys == 0) {
1501 out <<
"[]" << endl;
1503 out <<
"[ " << endl;
1505 OSTab tab2 (rcpFromRef (out));
1506 for (offset_type i = 0; i < tableSize; ++i) {
1507 OSTab tab3 (rcpFromRef (out));
1509 for (offset_type k = ptr_[i]; k < ptr_[i+1]; ++k) {
1510 out <<
"(" << val_[k].first <<
"," << val_[k].second <<
")";
1511 if (k + 1 < ptr_[i+1]) {
1537 #define TPETRA_DETAILS_FIXEDHASHTABLE_INSTANT_DEFAULTNODE(LO,GO) \
1538 template class FixedHashTable< GO , LO >;
1549 #define TPETRA_DETAILS_FIXEDHASHTABLE_INSTANT(LO, GO, DEVICE) \
1550 template class FixedHashTable< GO , LO , DEVICE >;
1552 #endif // TPETRA_DETAILS_FIXEDHASHTABLE_DEF_HPP
CheckForDuplicateKeys(const pairs_view_type &pairs, const offsets_view_type &ptr)
Constructor.
Parallel reduce functor for filling the FixedHashTable, and computing the min and max keys...
FillPairs(const pairs_view_type &pairs, const counts_view_type &counts, const offsets_view_type &ptr, const keys_view_type &keys, const typename pair_type::second_type startingValue, const key_type initMinKey, const key_type initMaxKey)
Constructor that takes initial min and max key values.
KOKKOS_INLINE_FUNCTION void init(value_type &dst) const
Set the initial value of the reduction result.
KOKKOS_INLINE_FUNCTION void join(volatile value_type &dst, const volatile value_type &src) const
Combine two intermediate reduction results.
KOKKOS_INLINE_FUNCTION void operator()(const size_type &i) const
Do this for every entry of keys_.
void describe(Teuchos::FancyOStream &out, const Teuchos::EVerbosityLevel verbLevel=Teuchos::Describable::verbLevel_default) const
Print this object with the given verbosity to the output stream.
ResultType result_type
Type of the return value of the hash function.
Parallel for functor for counting "buckets" in the FixedHashTable.
static bool debug()
Whether Tpetra is in debug mode.
bool hasKeys() const
Whether it is safe to call getKey().
bool success_
Whether fill succeeded (it can only fail on a bug)
KeyType maxKey_
The current maximum key.
void deep_copy(MultiVector< DS, DL, DG, DN > &dst, const MultiVector< SS, SL, SG, SN > &src)
Copy the contents of the MultiVector src into dst.
The hash function for FixedHashTable.
Declare and define the functions Tpetra::Details::computeOffsetsFromCounts and Tpetra::computeOffsets...
std::string description() const
Implementation of Teuchos::Describable interface.
KOKKOS_INLINE_FUNCTION void operator()(const size_type &i, value_type &dst) const
Parallel loop body; do this for every entry of keys_.
FixedHashTable()
Default constructor; makes an empty table.
FillPairs(const pairs_view_type &pairs, const counts_view_type &counts, const offsets_view_type &ptr, const keys_view_type &keys, const typename pair_type::second_type startingValue)
Constructor.
KOKKOS_INLINE_FUNCTION void init(value_type &dst) const
Set the initial value of the reduction result.
bool hasDuplicateKeys()
Whether the table has any duplicate keys.
static KOKKOS_INLINE_FUNCTION result_type hashFunc(const argument_type &key, const offset_type &size)
The hash function.
CountBuckets(const counts_view_type &counts, const keys_view_type &keys, const size_type size)
Constructor.
KOKKOS_INLINE_FUNCTION void init(value_type &dst) const
Set the initial value of the reduction result.
Functor for checking whether a FixedHashTable has one or more duplicate entries.
OffsetsViewType::non_const_value_type computeOffsetsFromCounts(const ExecutionSpace &execSpace, const OffsetsViewType &ptr, const CountsViewType &counts)
Compute offsets from counts.
KeyType minKey_
The current minimum key.
Reduction result for FillPairs functor below.
KOKKOS_INLINE_FUNCTION void operator()(const size_type &i, value_type &dst) const
Parallel loop body.
Kokkos::View< const KeyType *, Kokkos::LayoutLeft, device_type > keys_type
Type of a 1-D Kokkos::View (array) used to store keys.
Declaration of Tpetra::Details::Behavior, a class that describes Tpetra's behavior.