presage  0.8.7
dejavuPredictor.cpp
Go to the documentation of this file.
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 }