IFPACK  Development
 All Classes Files Functions Variables Enumerations Friends
Ifpack_HashTable.h
00001 /*@HEADER
00002 // ***********************************************************************
00003 //
00004 //       Ifpack: Object-Oriented Algebraic Preconditioner Package
00005 //                 Copyright (2002) Sandia Corporation
00006 //
00007 // Under terms of Contract DE-AC04-94AL85000, there is a non-exclusive
00008 // license for use of this work by or on behalf of the U.S. Government.
00009 //
00010 // Redistribution and use in source and binary forms, with or without
00011 // modification, are permitted provided that the following conditions are
00012 // met:
00013 //
00014 // 1. Redistributions of source code must retain the above copyright
00015 // notice, this list of conditions and the following disclaimer.
00016 //
00017 // 2. Redistributions in binary form must reproduce the above copyright
00018 // notice, this list of conditions and the following disclaimer in the
00019 // documentation and/or other materials provided with the distribution.
00020 //
00021 // 3. Neither the name of the Corporation nor the names of the
00022 // contributors may be used to endorse or promote products derived from
00023 // this software without specific prior written permission.
00024 //
00025 // THIS SOFTWARE IS PROVIDED BY SANDIA CORPORATION "AS IS" AND ANY
00026 // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00027 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
00028 // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL SANDIA CORPORATION OR THE
00029 // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00030 // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00031 // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00032 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00033 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00034 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00035 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00036 //
00037 // Questions? Contact Michael A. Heroux (maherou@sandia.gov)
00038 //
00039 // ***********************************************************************
00040 //@HEADER
00041 */
00042 
00043 /* \file Ifpack_HashTable.h
00044  *
00045  * \brief HashTable used in Ifpack_ICT and Ifpack_ILUT.
00046  *
00047  * \author Marzio Sala, ETHZ/D-INFK.
00048  *
00049  * \date Last modified on 30-Jun-06.
00050  */
00051 
00052 #ifndef IFPACK_HASHTABLE_H
00053 #define IFPACK_HASHTABLE_H
00054 
00055 #include "Ifpack_ConfigDefs.h"
00056 
00057 // ============================================================================
00058 // Hash table with good performances and high level of memory reuse.
00059 // Given a maximum number of keys n_keys, this class allocates chunks of memory
00060 // to store n_keys keys and values. 
00061 //
00062 // Usage:
00063 //
00064 // 1) Instantiate a object,
00065 //
00066 //    Ifpack_HashTable Hash(n_keys);
00067 //
00068 //    n_keys - maximum number of keys (This will be the n_keys with zero 
00069 //             collisons.)
00070 //
00071 // 3) use it, then delete it:
00072 //
00073 //    Hash.get(key, value)       --> returns the value stored on key, or 0.0 
00074 //                                   if not found.
00075 //    Hash.set(key, value)       --> sets the value in the hash table, replace
00076 //                                   existing values.
00077 //    Hash.set(key, value, true) --> to sum into an already inserted value
00078 //    Hash.arrayify(...)
00079 //
00080 // 4) clean memory:
00081 //
00082 //    Hash.reset();
00083 //
00084 // \author Marzio Sala, ETHZ/COLAB
00085 //
00086 // \date 30-Jun-06
00087 // ============================================================================ 
00088 template<typename key_type>
00089 class TIfpack_HashTable 
00090 {
00091   public:
00093     TIfpack_HashTable(const int n_keys = 1031, const int n_sets = 1)
00094     {
00095       n_keys_ = getRecommendedHashSize(n_keys) ;
00096       n_sets_ = n_sets;
00097       seed_ = (2654435761U);
00098 
00099       keys_.reserve(50);
00100       vals_.reserve(50);
00101 
00102       keys_.resize(n_sets_);
00103       vals_.resize(n_sets_);
00104 
00105       for (int i = 0; i < n_sets_; ++i)
00106       {
00107         keys_[i].resize(n_keys_);
00108         vals_[i].resize(n_keys_);
00109       }
00110 
00111       counter_.resize(n_keys_);
00112       for (int i = 0; i < n_keys_; ++i) counter_[i] = 0;
00113     }
00114 
00116     inline double get(const key_type key)
00117     {
00118       int hashed_key = doHash(key);
00119 
00120       for (int set_ptr = 0; set_ptr < counter_[hashed_key]; ++set_ptr)
00121       {
00122         if (keys_[set_ptr][hashed_key] == key)  
00123           return(vals_[set_ptr][hashed_key]);
00124       }
00125 
00126       return(0.0);
00127     }
00128 
00130     inline void set(const key_type key, const double value,
00131                     const bool addToValue = false)
00132     {
00133       int hashed_key = doHash(key);
00134       int& hashed_counter = counter_[hashed_key];
00135 
00136       for (int set_ptr = 0; set_ptr < hashed_counter; ++set_ptr)
00137       {
00138         if (keys_[set_ptr][hashed_key] == key)
00139         {
00140           if (addToValue)
00141             vals_[set_ptr][hashed_key] += value;
00142           else
00143             vals_[set_ptr][hashed_key] = value;
00144           return;
00145         }
00146       }
00147 
00148       if (hashed_counter < n_sets_)
00149       {
00150         keys_[hashed_counter][hashed_key] = key;
00151         vals_[hashed_counter][hashed_key] = value;
00152         ++hashed_counter;
00153         return;
00154       }
00155 
00156       std::vector<key_type> new_key;
00157       std::vector<double> new_val;
00158 
00159       keys_.push_back(new_key);
00160       vals_.push_back(new_val);
00161       keys_[n_sets_].resize(n_keys_);
00162       vals_[n_sets_].resize(n_keys_);
00163 
00164       keys_[n_sets_][hashed_key] = key;
00165       vals_[n_sets_][hashed_key] = value;
00166       ++hashed_counter;
00167       ++n_sets_;
00168     }
00169 
00174     inline void reset()
00175     {
00176       memset(&counter_[0], 0, sizeof(int) * n_keys_);
00177     }
00178 
00180     inline int getNumEntries() const 
00181     {
00182       int n_entries = 0;
00183       for (int key = 0; key < n_keys_; ++key)
00184         n_entries += counter_[key];
00185       return(n_entries);
00186     }
00187 
00189     void arrayify(key_type* key_array, double* val_array)
00190     {
00191       int count = 0;
00192       for (int key = 0; key < n_keys_; ++key)
00193         for (int set_ptr = 0; set_ptr < counter_[key]; ++set_ptr)
00194         {
00195           key_array[count] = keys_[set_ptr][key];
00196           val_array[count] = vals_[set_ptr][key];
00197           ++count;
00198         }
00199     }
00200 
00202     void print()
00203     {
00204       cout << "n_keys = " << n_keys_ << endl;
00205       cout << "n_sets = " << n_sets_ << endl;
00206     }
00207 
00208     int getRecommendedHashSize (int n)
00209     {
00210         /* Prime number approximately in the middle of the range [2^x..2^(x+1)]
00211          * is in primes[x-1]. Every prime number stored is approximately two 
00212          * times the previous one, so hash table size doubles every time.
00213          */
00214         int primes[] = {
00215         3, 7, 13, 23, 53, 97, 193, 389, 769, 1543, 3079, 6151, 12289, 24593,
00216         49157, 98317, 196613, 393241, 786433, 1572869, 3145739, 6291469,
00217         12582917, 25165842, 50331653, 100663319, 201326611, 402653189,
00218         805306457, 1610612741 } ;
00219         int i, hsize ;
00220 
00221         /* SRSR : err on the side of performance and choose the next largest 
00222          * prime number. One can also choose primes[i-1] below to cut the 
00223          * memory by half.
00224          */
00225         hsize = primes[29] ;
00226         for (i = 6 ; i < 30 ; i++)
00227         {
00228             if (n <= primes[i])
00229             {
00230                 /*hsize = (i == 0 ? n : primes[i-1]) ;*/
00231                 hsize = primes[i] ;
00232                 break ;
00233             }
00234         }
00235 
00236         return hsize ;
00237     }
00238 
00239   private:
00241     inline int doHash(const key_type key)
00242     {
00243       return (key % n_keys_);
00244       //return ((seed_ ^ key) % n_keys_);
00245     }
00246 
00247     int n_keys_;
00248     int n_sets_;
00249     std::vector<std::vector<double> > vals_;
00250     std::vector<std::vector<key_type> > keys_;
00251     std::vector<int> counter_;
00252     unsigned int seed_;
00253 };
00254 
00255 class Ifpack_HashTable : public TIfpack_HashTable<int>
00256 {
00257   public:
00258     Ifpack_HashTable(const int n_keys = 1031, const int n_sets = 1)
00259       : TIfpack_HashTable<int>(n_keys, n_sets)
00260     {
00261     }
00262 };
00263 
00264 class Ifpack_HashTable64 : public TIfpack_HashTable<long long>
00265 {
00266   public:
00267     Ifpack_HashTable64(const int n_keys = 1031, const int n_sets = 1)
00268       : TIfpack_HashTable<long long>(n_keys, n_sets)
00269     {
00270     }
00271 };
00272 
00273 #endif
 All Classes Files Functions Variables Enumerations Friends