|
GiNaC
1.6.2
|
00001 00006 /* 00007 * GiNaC Copyright (C) 1999-2011 Johannes Gutenberg University Mainz, Germany 00008 * 00009 * This program is free software; you can redistribute it and/or modify 00010 * it under the terms of the GNU General Public License as published by 00011 * the Free Software Foundation; either version 2 of the License, or 00012 * (at your option) any later version. 00013 * 00014 * This program is distributed in the hope that it will be useful, 00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00017 * GNU General Public License for more details. 00018 * 00019 * You should have received a copy of the GNU General Public License 00020 * along with this program; if not, write to the Free Software 00021 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00022 */ 00023 00024 #include "function.h" 00025 #include "utils.h" 00026 #include "remember.h" 00027 00028 #include <stdexcept> 00029 00030 namespace GiNaC { 00031 00033 // class remember_table_entry 00035 00036 remember_table_entry::remember_table_entry(function const & f, ex const & r) 00037 : hashvalue(f.gethash()), seq(f.seq), result(r) 00038 { 00039 ++last_access = access_counter; 00040 successful_hits = 0; 00041 } 00042 00043 bool remember_table_entry::is_equal(function const & f) const 00044 { 00045 GINAC_ASSERT(f.seq.size()==seq.size()); 00046 if (f.gethash()!=hashvalue) return false; 00047 size_t num = seq.size(); 00048 for (size_t i=0; i<num; ++i) 00049 if (!seq[i].is_equal(f.seq[i])) return false; 00050 ++last_access = access_counter; 00051 ++successful_hits; 00052 return true; 00053 } 00054 00055 unsigned long remember_table_entry::access_counter = 0; 00056 00058 // class remember_table_list 00060 00061 remember_table_list::remember_table_list(unsigned as, unsigned strat) 00062 { 00063 max_assoc_size = as; 00064 remember_strategy = strat; 00065 } 00066 00067 00068 void remember_table_list::add_entry(function const & f, ex const & result) 00069 { 00070 if ((max_assoc_size!=0) && 00071 (remember_strategy!=remember_strategies::delete_never) && 00072 (size()>=max_assoc_size)) { 00073 // table is full, we must delete an older entry 00074 GINAC_ASSERT(size()>0); // there must be at least one entry 00075 00076 switch (remember_strategy) { 00077 case remember_strategies::delete_cyclic: { 00078 // delete oldest entry (first in list) 00079 erase(begin()); 00080 break; 00081 } 00082 case remember_strategies::delete_lru: { 00083 // delete least recently used entry 00084 iterator it = begin(); 00085 iterator lowest_access_it = it; 00086 unsigned long lowest_access = (*it).get_last_access(); 00087 ++it; 00088 while (it!=end()) { 00089 if ((*it).get_last_access()<lowest_access) { 00090 lowest_access = (*it).get_last_access(); 00091 lowest_access_it = it; 00092 } 00093 ++it; 00094 } 00095 erase(lowest_access_it); 00096 break; 00097 } 00098 case remember_strategies::delete_lfu: { 00099 // delete least frequently used entry 00100 iterator it = begin(); 00101 iterator lowest_hits_it = it; 00102 unsigned lowest_hits = (*it).get_successful_hits(); 00103 ++it; 00104 while (it!=end()) { 00105 if ((*it).get_successful_hits()<lowest_hits) { 00106 lowest_hits = (*it).get_successful_hits(); 00107 lowest_hits_it = it; 00108 } 00109 ++it; 00110 } 00111 erase(lowest_hits_it); 00112 break; 00113 } 00114 default: 00115 throw(std::logic_error("remember_table_list::add_entry(): invalid remember_strategy")); 00116 } 00117 GINAC_ASSERT(size()==max_assoc_size-1); 00118 } 00119 push_back(remember_table_entry(f,result)); 00120 } 00121 00122 bool remember_table_list::lookup_entry(function const & f, ex & result) const 00123 { 00124 const_iterator i = begin(), iend = end(); 00125 while (i != iend) { 00126 if (i->is_equal(f)) { 00127 result = i->get_result(); 00128 return true; 00129 } 00130 ++i; 00131 } 00132 return false; 00133 } 00134 00136 // class remember_table 00138 00139 remember_table::remember_table() 00140 { 00141 table_size=0; 00142 max_assoc_size=0; 00143 remember_strategy=remember_strategies::delete_never; 00144 } 00145 00146 remember_table::remember_table(unsigned s, unsigned as, unsigned strat) 00147 : max_assoc_size(as), remember_strategy(strat) 00148 { 00149 // we keep max_assoc_size and remember_strategy if we need to clear 00150 // all entries 00151 00152 // use some power of 2 next to s 00153 table_size = 1 << log2(s); 00154 init_table(); 00155 } 00156 00157 bool remember_table::lookup_entry(function const & f, ex & result) const 00158 { 00159 unsigned entry = f.gethash() & (table_size-1); 00160 GINAC_ASSERT(entry<size()); 00161 return operator[](entry).lookup_entry(f,result); 00162 } 00163 00164 void remember_table::add_entry(function const & f, ex const & result) 00165 { 00166 unsigned entry = f.gethash() & (table_size-1); 00167 GINAC_ASSERT(entry<size()); 00168 operator[](entry).add_entry(f,result); 00169 } 00170 00171 void remember_table::clear_all_entries() 00172 { 00173 clear(); 00174 init_table(); 00175 } 00176 00177 void remember_table::init_table() 00178 { 00179 reserve(table_size); 00180 for (unsigned i=0; i<table_size; ++i) 00181 push_back(remember_table_list(max_assoc_size,remember_strategy)); 00182 } 00183 00184 std::vector<remember_table> & remember_table::remember_tables() 00185 { 00186 static std::vector<remember_table> rt = std::vector<remember_table>(); 00187 return rt; 00188 } 00189 00190 } // namespace GiNaC