Tpetra parallel linear algebra Version of the Day
Loading...
Searching...
No Matches
Tpetra_HashTable_def.hpp
1// @HEADER
2// *****************************************************************************
3// Tpetra: Templated Linear Algebra Services Package
4//
5// Copyright 2008 NTESS and the Tpetra contributors.
6// SPDX-License-Identifier: BSD-3-Clause
7// *****************************************************************************
8// @HEADER
9
10#ifndef TPETRA_HASHTABLE_DEF_HPP_
11#define TPETRA_HASHTABLE_DEF_HPP_
12
13#include "Tpetra_HashTable_decl.hpp"
14#include "MurmurHash3.hpp"
15
16namespace Tpetra {
17
18namespace Details {
19
20template <typename KeyType, typename ValueType>
21int HashTable<KeyType, ValueType>::hashFunc(const KeyType key) {
22#ifdef TPETRA_USE_MURMUR_HASH
23 uint32_t k;
24 MurmurHash3_x86_32((void *)&key, sizeof(KeyType),
25 1, (void *)&k);
26 return (int)(k % Size_);
27#else
28 // Epetra's version of hash, using it as default as we have observed
29 // this is much faster than murmur hash. However, this is not a good
30 // hash function for all data sets. For our typical use case, this is good.
31 // Use murmur if the maps are sparse.
32 int intkey = (int)((key & 0x000000007fffffffLL) +
33 ((key & 0x7fffffff80000000LL) >> 31));
34 return (int)((Seed_ ^ intkey) % Size_);
35#endif
36}
37
38template <typename KeyType, typename ValueType>
39int HashTable<KeyType, ValueType>::getRecommendedSize(const int size) {
40 // A large list of prime numbers.
41 // Based on a recommendation by Andres Valloud in hash forums.
42 // There are only enough primes here so that between any number N and 2*N,
43 // there will be at least about 8 to choose from (except the first 10).
44 // This is a balance between a small list of primes, and getting a
45 // collection size that doesn't waste too much space. In addition,
46 // the primes in this table were chosen so that they do not divide
47 // 256^k +- a, for 1<=k<=8, and -32<=a<=32. This is so that
48 // using them as a modulo will not have a tendency to just throw away
49 // the most significant bits of the object's hash. The primes (except the
50 // first ten) or not close to any power of two to avoid aliasing
51 // between hash functions based on bit manipulation and the moduli.
52 int primes[] = {
53 3, 7, 13, 23, 53, 97, 193, 389, 769, 1543,
54 2237, 2423, 2617, 2797, 2999, 3167, 3359, 3539,
55 3727, 3911, 4441, 4787, 5119, 5471, 5801, 6143, 6521, 6827, 7177, 7517, 7853, 8887, 9587, 10243, 10937, 11617, 12289, 12967, 13649, 14341, 15013, 15727, 17749, 19121, 20479, 21859, 23209, 24593, 25939, 27329, 28669, 30047, 31469, 35507, 38231, 40961, 43711, 46439, 49157, 51893, 54617, 57347, 60077, 62801, 70583, 75619, 80669, 85703, 90749, 95783, 100823, 105871, 110909, 115963, 120997, 126031, 141157, 151237, 161323, 171401, 181499, 191579, 201653, 211741, 221813, 231893, 241979, 252079, 282311, 302483, 322649, 342803, 362969, 383143, 403301, 423457, 443629, 463787, 483953, 504121, 564617, 604949, 645313, 685609, 725939, 766273, 806609, 846931, 887261, 927587, 967919, 1008239, 1123477, 1198397, 1273289, 1348177, 1423067, 1497983, 1572869, 1647761, 1722667, 1797581, 1872461, 1947359, 2022253, 2246953, 2396759, 2546543, 2696363, 2846161, 2995973, 3145739, 3295541, 3445357, 3595117, 3744941, 3894707, 4044503, 4493921, 4793501, 5093089, 5392679, 5692279, 5991883, 6291469, 6591059, 6890641, 7190243, 7489829, 7789447, 8089033, 8987807, 9586981, 10186177, 10785371, 11384539, 11983729, 12582917, 13182109, 13781291, 14380469, 14979667, 15578861, 16178053, 17895707, 19014187, 20132683, 21251141, 22369661, 23488103, 24606583, 25725083, 26843549, 27962027, 29080529, 30198989, 31317469, 32435981, 35791397, 38028379, 40265327, 42502283, 44739259, 46976221, 49213237, 51450131, 53687099, 55924061, 58161041, 60397993, 62634959, 64871921, 71582857, 76056727, 80530643, 85004567, 89478503, 93952427, 98426347, 102900263, 107374217, 111848111, 116322053, 120795971, 125269877, 129743807, 143165587, 152113427, 161061283, 170009141, 178956983, 187904819, 196852693, 205800547, 214748383, 223696237, 232644089, 241591943, 250539763, 259487603, 268435399};
56
57 int hsize = primes[220];
58 for (int i = 0; i < 221; i++) {
59 if (size <= primes[i]) {
60 hsize = primes[i];
61 break;
62 }
63 }
64
65 return hsize;
66}
67
68template <typename KeyType, typename ValueType>
70 HashTable(const int size, const unsigned int seed)
71 : Container_(NULL)
72 , Seed_(seed) {
73 TEUCHOS_TEST_FOR_EXCEPTION(size < 0, std::runtime_error,
74 "HashTable : ERROR, size cannot be less than zero");
75
76 Size_ = getRecommendedSize(size);
77 Container_ = new Node *[Size_];
78 for (KeyType i = 0; i < Size_; ++i) Container_[i] = NULL;
79#ifdef HAVE_TPETRA_DEBUG
80 maxc_ = 0;
81 nc_ = 0;
82#endif
83}
84
85template <typename KeyType, typename ValueType>
88 : Container_(NULL)
89 , Size_(obj.Size_)
90 , Seed_(obj.Seed_) {
91#ifdef HAVE_TPETRA_DEBUG
92 maxc_ = 0;
93 nc_ = 0;
94#endif
95 Container_ = new Node *[Size_];
96 for (KeyType i = 0; i < Size_; ++i) Container_[i] = NULL;
97 for (KeyType i = 0; i < Size_; ++i) {
98 Node *ptr = obj.Container_[i];
99 while (ptr) {
100 add(ptr->Key, ptr->Value);
101 ptr = ptr->Ptr;
102 }
103 }
104}
105
106template <typename KeyType, typename ValueType>
107HashTable<KeyType, ValueType>::~HashTable() {
108 Node *ptr1;
109 Node *ptr2;
110 for (KeyType i = 0; i < Size_; ++i) {
111 ptr1 = Container_[i];
112 while (ptr1) {
113 ptr2 = ptr1;
114 ptr1 = ptr1->Ptr;
115 delete ptr2;
116 }
117 }
118
119 delete[] Container_;
120}
121
122template <typename KeyType, typename ValueType>
124 add(const KeyType key, const ValueType value) {
125 int v = hashFunc(key);
126 Node *n1 = Container_[v];
127 Container_[v] = new Node(key, value, n1);
128}
129
130template <typename KeyType, typename ValueType>
133 get(const KeyType key) {
134 Node *n = Container_[hashFunc(key)];
135
136#ifdef HAVE_TPETRA_DEBUG
137 int k = 0;
138#endif
139
140 while (n && (n->Key != key)) {
141 n = n->Ptr;
142#ifdef HAVE_TPETRA_DEBUG
143 ((k + 1 > maxc_) ? maxc_ = k + 1 : 0);
144 k++;
145#endif
146 }
147
148#ifdef HAVE_TPETRA_DEBUG
149 if (k != 0) nc_++;
150#endif
151 if (n)
152 return n->Value;
153 else
154 return -1;
155}
156
157template <typename KeyType, typename ValueType>
159 std::ostringstream oss;
160 oss << "HashTable<"
161 << Teuchos::TypeNameTraits<KeyType>::name() << ","
162 << Teuchos::TypeNameTraits<ValueType>::name() << "> "
163 << "{ Size_: " << Size_ << " }";
164 return oss.str();
165}
166
167template <typename KeyType, typename ValueType>
169 Teuchos::FancyOStream &out,
170 const Teuchos::EVerbosityLevel verbLevel) const {
171 using std::endl;
172 using std::setw;
173 using Teuchos::OSTab;
174 using Teuchos::rcpFromRef;
175 using Teuchos::TypeNameTraits;
176 using Teuchos::VERB_DEFAULT;
177 using Teuchos::VERB_EXTREME;
178 using Teuchos::VERB_LOW;
179 using Teuchos::VERB_NONE;
180
181 Teuchos::EVerbosityLevel vl = verbLevel;
182 if (vl == VERB_DEFAULT) vl = VERB_LOW;
183
184 if (vl == VERB_NONE) {
185 // do nothing
186 } else if (vl == VERB_LOW) {
187 out << this->description() << endl;
188 } else { // MEDIUM, HIGH or EXTREME
189 out << "HashTable: {" << endl;
190 {
192
193 const std::string label = this->getObjectLabel();
194 if (label != "") {
195 out << "label: " << label << endl;
196 }
197 out << "Template parameters: {" << endl;
198 {
200 out << "KeyType: " << TypeNameTraits<KeyType>::name() << endl
201 << "ValueType" << TypeNameTraits<ValueType>::name() << endl;
202 }
203 out << "}" << endl
204 << "Table parameters: {" << endl;
205 {
207 out << "Size_: " << Size_ << endl;
208 }
209 out << "}" << endl;
210#ifdef HAVE_TPETRA_DEBUG
211 out << "Debug info: {" << endl;
212 {
214 out << "Maximum number of collisions for any key: " << maxc_ << endl
215 << "Total number of collisions: " << nc_ << endl;
216 }
217 out << "}" << endl;
218#endif // HAVE_TPETRA_DEBUG
219
220 if (vl >= VERB_EXTREME) {
221 out << "Contents: ";
222 if (Container_ == NULL || Size_ == 0) {
223 out << "[]" << endl;
224 } else {
225 out << "[" << endl;
226 {
228 for (KeyType i = 0; i < Size_; ++i) {
229 Node *curNode = Container_[i];
230 if (curNode == NULL) {
231 out << "NULL";
232 } else { // curNode != NULL
233 // Print all the buckets at the current table position i.
234 out << "[";
235 // Print the first bucket.
236 out << "[" << curNode->Key << "," << curNode->Value << "]";
237 curNode = curNode->Ptr;
238 // Print the remaining buckets, if there are any.
239 while (curNode != NULL) {
240 out << ", [" << curNode->Key << "," << curNode->Value << "]";
241 curNode = curNode->Ptr;
242 }
243 out << "]" << endl;
244 } // if curNode == or != NULL
245 if (i + 1 < Size_) {
246 out << ", ";
247 }
248 } // for each table position i
249 }
250 out << "]" << endl;
251 } // The table contains entries
252 } // vl >= VERB_EXTREME
253 }
254 out << "}" << endl;
255 } // if vl > VERB_LOW
256}
257
258} // namespace Details
259} // namespace Tpetra
260
261// Macro that explicitly instantiates HashTable for the given local
262// ordinal (LO) and global ordinal (GO) types. Note that HashTable's
263// template parameters occur in the opposite order of most Tpetra
264// classes. This is because HashTable performs global-to-local
265// lookup, and the convention in templated C++ lookup tables (such as
266// std::map) is <KeyType, ValueType>.
267//
268// This macro must be explanded within the Tpetra::Details namespace.
269#define TPETRA_HASHTABLE_INSTANT_DEFAULTNODE(LO, GO) \
270 template class HashTable<GO, LO>;
271
272#endif
Struct that holds views of the contents of a CrsMatrix.
HashTable(const int size, const unsigned int seed=(2654435761U))
ValueType get(const KeyType key)
Get the value corresponding to the given key.
std::string description() const
Implementation of Teuchos::Describable.
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.
void add(const KeyType key, const ValueType value)
Add a key and its value to the hash table.
Implementation details of Tpetra.
Namespace Tpetra contains the class and methods constituting the Tpetra library.