presage
0.8.7
|
00001 00002 /****************************************************** 00003 * Presage, an extensible predictive text entry system 00004 * --------------------------------------------------- 00005 * 00006 * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk> 00007 00008 This program is free software; you can redistribute it and/or modify 00009 it under the terms of the GNU General Public License as published by 00010 the Free Software Foundation; either version 2 of the License, or 00011 (at your option) any later version. 00012 00013 This program is distributed in the hope that it will be useful, 00014 but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00016 GNU General Public License for more details. 00017 00018 You should have received a copy of the GNU General Public License along 00019 with this program; if not, write to the Free Software Foundation, Inc., 00020 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. 00021 * 00022 **********(*)*/ 00023 00024 #include "dejavuPredictor.h" 00025 00026 #include <algorithm> 00027 00028 const char* DejavuPredictor::LOGGER = "Presage.Predictors.DejavuPredictor.LOGGER"; 00029 const char* DejavuPredictor::MEMORY = "Presage.Predictors.DejavuPredictor.MEMORY"; 00030 const char* DejavuPredictor::TRIGGER = "Presage.Predictors.DejavuPredictor.TRIGGER"; 00031 00032 /* 00033 * Implementation idea: predictor remembers previously entered text (by 00034 * storing it in a config defined file); when current token is found 00035 * in the remembered text, the tokens following the current token are 00036 * suggested; this requires "learning" previously entered text. 00037 * 00038 */ 00039 00040 DejavuPredictor::DejavuPredictor(Configuration* config, ContextTracker* ct) 00041 : Predictor(config, 00042 ct, 00043 "DejavuPredictor", 00044 "DejavuPredictor, a parrot predictor", 00045 "DejavuPredictor is a parrot predictor.\n" 00046 "It always returns what it has heard before.\n"), 00047 dispatcher (this) 00048 { 00049 // build notification dispatch map 00050 dispatcher.map (config->find (LOGGER), & DejavuPredictor::set_logger); 00051 dispatcher.map (config->find (MEMORY), & DejavuPredictor::set_memory); 00052 dispatcher.map (config->find (TRIGGER), & DejavuPredictor::set_trigger); 00053 } 00054 00055 DejavuPredictor::~DejavuPredictor() 00056 {} 00057 00058 void DejavuPredictor::set_memory (const std::string& filename) 00059 { 00060 memory = filename; 00061 logger << INFO << "MEMORY: " << filename << endl; 00062 } 00063 00064 void DejavuPredictor::set_trigger (const std::string& number) 00065 { 00066 trigger = Utility::toInt (number); 00067 logger << INFO << "TRIGGER: " << number << endl; 00068 } 00069 00070 Prediction DejavuPredictor::predict(const size_t max_partial_predictions_size, const char** filter) const 00071 { 00072 Prediction result; 00073 00074 std::list<std::string> memory_trigger; 00075 00076 std::ifstream memory_file(memory.c_str()); 00077 if (!memory_file) { 00078 logger << ERROR << "Error opening memory file: " << memory << endl; 00079 } else { 00080 if (init_memory_trigger(memory_trigger)) { 00081 logger << INFO << "Memory trigger init'ed" << endl; 00082 00083 std::list<std::string> rolling_window; 00084 if (init_rolling_window(rolling_window, memory_file)) { 00085 logger << INFO << "Rolling window init'ed" << endl; 00086 00087 std::string token; 00088 while (memory_file >> token) { 00089 logger << INFO << "Considering token: " << token << endl; 00090 00091 if (match(memory_trigger, rolling_window)) { 00092 logger << INFO << "Adding suggestion: " << token << endl; 00093 result.addSuggestion(Suggestion(token, 1.0)); 00094 } 00095 00096 update_rolling_window(rolling_window, token); 00097 } 00098 00099 } else { 00100 logger << INFO << "Rolling window initialized unsuccessful" << endl; 00101 } 00102 } else { 00103 logger << INFO << "Memory trigger initialized unsuccessful" << endl; 00104 } 00105 00106 memory_file.close(); 00107 } 00108 00109 return result; 00110 } 00111 00112 void DejavuPredictor::learn(const std::vector<std::string>& change) 00113 { 00114 // loop through all tokens in change vector 00115 for (std::vector<std::string>::const_iterator it = change.begin(); 00116 it != change.end(); 00117 it++) 00118 { 00119 std::string new_token = *it; 00120 logger << INFO << "Committing new token to memory: " << new_token << endl; 00121 std::ofstream memory_file(memory.c_str(), std::ios::app); 00122 if (!memory_file) { 00123 logger << ERROR << "Error opening memory file: " << memory << endl; 00124 } else { 00125 memory_file << new_token << std::endl; 00126 memory_file.close(); 00127 } 00128 } 00129 } 00130 00136 bool DejavuPredictor::match(const std::list<std::string>& l1, const std::list<std::string>& l2) const 00137 { 00138 return equal(l1.begin(), l1.end(), l2.begin()); 00139 } 00140 00150 bool DejavuPredictor::init_memory_trigger(std::list<std::string>& memory_trigger) const 00151 { 00152 bool result = false; 00153 00154 // fill up the token window list that contains the tokens that 00155 // will trigger a recollection 00156 for (int i = trigger; i > 0; i--) { 00157 logger << INFO << "Memory trigger list: " << contextTracker->getToken(i) << endl; 00158 memory_trigger.push_back(contextTracker->getToken(i)); 00159 } 00160 00161 // check that the current context is rich enough to trigger a 00162 // recollection 00163 if (memory_trigger.end() == find(memory_trigger.begin(), memory_trigger.end(), "")) { 00164 result = true; 00165 } 00166 00167 logger << INFO << "Memory trigger valid: " << result << endl; 00168 00169 return result; 00170 } 00171 00178 bool DejavuPredictor::init_rolling_window(std::list<std::string>& rolling_window, std::ifstream& memory_file) const 00179 { 00180 std::string token; 00181 int count = 0; 00182 // following while test relies on the fact that if first condition 00183 // is true, then the second condition will not be evaluated: in 00184 // other words, a token will not be read from file if count is not 00185 // less than trigger. 00186 while (count < trigger && memory_file >> token) { 00187 logger << INFO << "Rolling window list: " << token << endl; 00188 rolling_window.push_back(token); 00189 count++; 00190 } 00191 00192 return (count == trigger); 00193 } 00194 00199 void DejavuPredictor::update_rolling_window(std::list<std::string>& rolling_window, const std::string& token) const 00200 { 00201 rolling_window.pop_front(); 00202 logger << INFO << "Pushing back on memory list: " << token << endl; 00203 rolling_window.push_back(token); 00204 } 00205 00206 void DejavuPredictor::update (const Observable* var) 00207 { 00208 logger << DEBUG << "About to invoke dispatcher: " << var->get_name () << " - " << var->get_value() << endl; 00209 dispatcher.dispatch (var); 00210 }