Tpetra parallel linear algebra  Version of the Day
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
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 
16 namespace Tpetra {
17 
18 namespace Details {
19 
20 template <typename KeyType, typename ValueType>
21 int 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 
38 template <typename KeyType, typename ValueType>
39 int 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 
68 template <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 
85 template <typename KeyType, typename ValueType>
87  HashTable(const HashTable &obj)
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 
106 template <typename KeyType, typename ValueType>
107 HashTable<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 
122 template <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 
130 template <typename KeyType, typename ValueType>
131 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 
157 template <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 
167 template <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  {
191  OSTab tab1(rcpFromRef(out));
192 
193  const std::string label = this->getObjectLabel();
194  if (label != "") {
195  out << "label: " << label << endl;
196  }
197  out << "Template parameters: {" << endl;
198  {
199  OSTab tab2(rcpFromRef(out));
200  out << "KeyType: " << TypeNameTraits<KeyType>::name() << endl
201  << "ValueType" << TypeNameTraits<ValueType>::name() << endl;
202  }
203  out << "}" << endl
204  << "Table parameters: {" << endl;
205  {
206  OSTab tab2(rcpFromRef(out));
207  out << "Size_: " << Size_ << endl;
208  }
209  out << "}" << endl;
210 #ifdef HAVE_TPETRA_DEBUG
211  out << "Debug info: {" << endl;
212  {
213  OSTab tab2(rcpFromRef(out));
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  {
227  OSTab tab2(rcpFromRef(out));
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
HashTable(const int size, const unsigned int seed=(2654435761U))
ValueType get(const KeyType key)
Get the value corresponding to the given key.
void add(const KeyType key, const ValueType value)
Add a key and its value to the hash table.
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.