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