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 00025 #include "selector.h" 00026 #include "utility.h" 00027 00028 const char* Selector::SUGGESTIONS = "Presage.Selector.SUGGESTIONS"; 00029 const char* Selector::REPEAT_SUGGESTIONS = "Presage.Selector.REPEAT_SUGGESTIONS"; 00030 const char* Selector::GREEDY_SUGGESTION_THRESHOLD = "Presage.Selector.GREEDY_SUGGESTION_THRESHOLD"; 00031 00032 const char* Selector::LOGGER = "Presage.Selector.LOGGER"; 00033 00034 Selector::Selector(Configuration* configuration, ContextTracker* ct) 00035 : contextTracker(ct), 00036 config(configuration), 00037 logger("Selector", std::cerr), 00038 dispatcher(this) 00039 { 00040 // build notification dispatch map 00041 dispatcher.map (config->find (LOGGER), & Selector::set_logger); 00042 dispatcher.map (config->find (SUGGESTIONS), & Selector::set_suggestions); 00043 dispatcher.map (config->find (REPEAT_SUGGESTIONS), & Selector::set_repeat_suggestions); 00044 dispatcher.map (config->find (GREEDY_SUGGESTION_THRESHOLD), & Selector::set_greedy_suggestion_threshold); 00045 00046 // set prefix 00047 previous_prefix = contextTracker->getPrefix(); 00048 } 00049 00050 Selector::~Selector() 00051 { 00052 // nothing to do here, move along 00053 } 00054 00055 std::vector<std::string> Selector::select( Prediction p ) 00056 { 00057 // copy words from Prediction.Suggestion.word in result vector 00058 std::vector<std::string> result; 00059 std::string token; 00060 for (size_t i=0 ; i<p.size() ; i++) { 00061 token = p.getSuggestion(i).getWord(); 00062 result.push_back(token); 00063 logger << DEBUG << "Added token to selector consideration set: " << token << endl; 00064 } 00065 00066 // check whether user has not moved on to a new word 00067 if (contextTracker->contextChange()) { 00068 logger << DEBUG << "Context change detected." << endl; 00069 clearSuggestedWords(); 00070 } else { 00071 logger << DEBUG << "No context change detected." << endl; 00072 } 00073 00074 // filter out suggestions that do not satisfy repetition constraint 00075 if( !repeat_suggestions ) 00076 repetitionFilter( result ); 00077 00078 // filter out suggestions that do not satisfy threshold constraint 00079 if( greedy_suggestion_threshold > 0 ) 00080 thresholdFilter( result ); 00081 00082 // build result 00083 00084 // check that we have enough selected words 00085 if( result.size() < static_cast<unsigned int>(suggestions) ) { 00086 // Job's not done, got to get a bigger Prediction 00087 // we should invoke predict() to get more Suggestions 00088 00089 // could throw an exception that would be caught by predictor 00090 // which would reissue the predict call to get more 00091 // suggestions 00092 00093 // TODO <============================================ 00094 00095 // just abort for now 00096 //std::cerr << "Not enough Suggestions" << std::endl; 00097 //abort(); 00098 00099 } else { 00100 // erase the requested number of words 00101 result.erase( result.begin() + suggestions, result.end() ); 00102 } 00103 00104 // update suggested words set 00105 updateSuggestedWords( result ); 00106 00107 return result; 00108 } 00109 00110 00114 void Selector::update() 00115 { 00116 // check whether user has not moved on to a new word 00117 if (contextTracker->contextChange()) { 00118 clearSuggestedWords(); 00119 } 00120 } 00121 00122 00126 void Selector::updateSuggestedWords( const std::vector<std::string>& v ) 00127 { 00128 std::vector<std::string>::const_iterator i = v.begin(); 00129 while( i != v.end() ) { 00130 logger << DEBUG << "Adding token to suggested token set: " << *i << endl; 00131 suggestedWords.insert( *i ); 00132 i++; 00133 } 00134 00135 logger << DEBUG << "Suggested words: "; 00136 for (StringSet::const_iterator it = suggestedWords.begin(); 00137 it != suggestedWords.end(); 00138 it++) { 00139 logger << *it << ' '; 00140 } 00141 logger << endl; 00142 } 00143 00144 00148 void Selector::clearSuggestedWords() 00149 { 00150 logger << DEBUG << "Clearing previously suggested tokens set." << endl; 00151 suggestedWords.clear(); 00152 } 00153 00162 void Selector::repetitionFilter( std::vector<std::string>& v ) 00163 { 00164 std::vector< std::string > temp; 00165 00166 for( std::vector<std::string>::iterator i = v.begin(); 00167 i != v.end(); 00168 i++ ) { 00169 if( suggestedWords.find( *i ) == suggestedWords.end() ) { 00170 temp.push_back( *i ); 00171 logger << DEBUG << "Token passed repetition filter: " << *i << endl; 00172 } else { 00173 logger << DEBUG << "Token failed repetition filter: " << *i << endl; 00174 } 00175 } 00176 00177 v = temp; 00178 } 00179 00187 void Selector::thresholdFilter( std::vector<std::string>& v ) 00188 { 00189 assert( greedy_suggestion_threshold >= 0 ); 00190 00191 // zero threshold indicates feature is disabled 00192 if( greedy_suggestion_threshold != 0 ) { 00193 00194 int length = contextTracker->getPrefix().size(); 00195 std::vector<std::string>::iterator i = v.begin(); 00196 while (i != v.end()) { 00197 if( (i->size()-length) < greedy_suggestion_threshold) { 00198 logger << INFO << "Removing token: " << *i << endl; 00199 i = v.erase( i ); 00200 } else { 00201 i++; 00202 } 00203 } 00204 } 00205 } 00206 00207 00211 void Selector::set_logger (const std::string& value) 00212 { 00213 logger << setlevel (value); 00214 logger << INFO << "LOGGER: " << value << endl; 00215 } 00216 00217 00221 void Selector::set_suggestions(const std::string& value) 00222 { 00223 logger << INFO << "SUGGESTIONS: " << value << endl; 00224 int result = Utility::toInt(value); 00225 if (result < 0) { 00226 logger << ERROR << "Presage.Selector.SUGGESTIONS value out of range!/a" << endl; 00227 // REVISIT: throw exception 00228 abort(); 00229 } 00230 00231 suggestions = result; 00232 } 00233 00234 00238 void Selector::set_repeat_suggestions(const std::string& value) 00239 { 00240 logger << INFO << "REPEAT_SUGGESTIONS: " << value << endl; 00241 bool result = Utility::isYes(value); 00242 00243 repeat_suggestions = result; 00244 } 00245 00246 00250 void Selector::set_greedy_suggestion_threshold(const std::string& value) 00251 { 00252 logger << INFO << "GREEDY_SUGGESTION_THRESHOLD: " << value << endl; 00253 int result = Utility::toInt(value); 00254 if( result < 0 ) { 00255 logger << ERROR << "GREEDY_SUGGESTION_THRESHOLD value out of range." << value << endl; 00256 // REVISIT: throw exception 00257 abort(); 00258 } 00259 00260 greedy_suggestion_threshold = result; 00261 } 00262 00263 size_t Selector::get_suggestions () const 00264 { 00265 return suggestions; 00266 } 00267 00268 bool Selector::get_repeat_suggestions () const 00269 { 00270 return repeat_suggestions; 00271 } 00272 00273 size_t Selector::get_greedy_suggestion_threshold () const 00274 { 00275 return greedy_suggestion_threshold; 00276 } 00277 00278 void Selector::update (const Observable* variable) 00279 { 00280 logger << DEBUG << "update(" << variable->get_name () << ") called" << endl; 00281 00282 dispatcher.dispatch (variable); 00283 }