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 "presage.h" 00026 00027 #include "core/profileManager.h" 00028 #include "core/predictorRegistry.h" 00029 #include "core/context_tracker/contextTracker.h" 00030 #include "core/selector.h" 00031 #include "core/predictorActivator.h" 00032 00033 Presage::Presage (PresageCallback* callback) 00034 throw (PresageException) 00035 { 00036 profileManager = new ProfileManager(); 00037 configuration = profileManager->get_configuration(); 00038 predictorRegistry = new PredictorRegistry(configuration); 00039 contextTracker = new ContextTracker(configuration, predictorRegistry, callback); 00040 predictorActivator = new PredictorActivator(configuration, predictorRegistry, contextTracker); 00041 selector = new Selector(configuration, contextTracker); 00042 00043 //plump::Logger::getLogger()->setLevel(plump::Logger::DEBUG); 00044 //plump.appendPath("./predictors"); 00045 //plump.registerCallback(callback_helloworld, 0); 00046 //plump.discoverPredictors(); 00047 } 00048 00049 Presage::Presage (PresageCallback* callback, const std::string config_filename) 00050 throw (PresageException) 00051 { 00052 profileManager = new ProfileManager(config_filename); 00053 configuration = profileManager->get_configuration(); 00054 00055 predictorRegistry = new PredictorRegistry(configuration); 00056 contextTracker = new ContextTracker(configuration, predictorRegistry, callback); 00057 predictorActivator = new PredictorActivator(configuration, predictorRegistry, contextTracker); 00058 selector = new Selector(configuration, contextTracker); 00059 } 00060 00061 Presage::~Presage() 00062 { 00063 delete selector; 00064 delete predictorActivator; 00065 delete contextTracker; 00066 delete predictorRegistry; 00067 delete profileManager; 00068 } 00069 00070 std::vector<std::string> Presage::predict () 00071 throw (PresageException) 00072 { 00073 std::vector<std::string> result; 00074 00075 unsigned int multiplier = 1; 00076 Prediction prediction = predictorActivator->predict(multiplier++, 0); 00077 result = selector->select(prediction); 00078 00079 Prediction previous_prediction = prediction; 00080 while ((result.size() < (selector->get_suggestions())) 00081 && (prediction = predictorActivator->predict(multiplier++, 0)).size() > previous_prediction.size()) { 00082 // while the number of predicted tokens is lower than desired, 00083 // search harder (i.e. higher multiplier) for a prediction of 00084 // sufficient size (i.e. that satisfies selector), as long as 00085 // the result of current prediction is greater than the 00086 // previous prediction (i.e. we are finding new tokens). 00087 result = selector->select(prediction); 00088 previous_prediction = prediction; 00089 } 00090 00091 contextTracker->update(); 00092 00093 return result; 00094 } 00095 00096 std::multimap<double, std::string> Presage::predict (std::vector<std::string> filter) 00097 throw (PresageException) 00098 { 00099 std::multimap<double, std::string> result; 00100 00101 std::vector<std::string> selection; 00102 const char** internal_filter = 0; 00103 if(filter.size()>0) 00104 { 00105 // convert filter to internal representation - currently a null 00106 // terminated const char** 00107 internal_filter = new const char*[filter.size() + 1]; 00108 for (std::vector<std::string>::size_type i = 0; i < filter.size(); i++) { 00109 internal_filter[i] = filter[i].c_str(); 00110 } 00111 internal_filter[filter.size()] = 0; 00112 } 00113 00114 unsigned int multiplier = 1; 00115 Prediction prediction = predictorActivator->predict(multiplier++, internal_filter); 00116 selection = selector->select(prediction); 00117 00118 Prediction previous_prediction = prediction; 00119 while ((selection.size() < (selector->get_suggestions())) 00120 && (prediction = predictorActivator->predict(multiplier++, internal_filter)).size() > previous_prediction.size()) { 00121 // while the number of predicted tokens is lower than desired, 00122 // search harder (i.e. higher multiplier) for a prediction of 00123 // sufficient size (i.e. that satisfies selector), as long as 00124 // the selection of current prediction is greater than the 00125 // previous prediction (i.e. we are finding new tokens). 00126 selection = selector->select(prediction); 00127 previous_prediction = prediction; 00128 } 00129 00130 delete[] internal_filter; 00131 00132 for (std::vector<std::string>::const_iterator it = selection.begin(); 00133 it != selection.end(); 00134 it++) { 00135 std::pair<const double, std::string> p(prediction.getSuggestion(*it).getProbability(), 00136 (*it)); 00137 result.insert(p); 00138 } 00139 00140 contextTracker->update(); 00141 00142 return result; 00143 } 00144 00145 PresageCallback* Presage::callback (PresageCallback* callback) 00146 throw (PresageException) 00147 { 00148 return const_cast<PresageCallback*>(contextTracker->callback(callback)); 00149 } 00150 00151 std::string Presage::completion (const std::string str) 00152 throw (PresageException) 00153 { 00154 // There are two types of completions: normal and erasing. 00155 // normal_completion = prefix + remainder 00156 // erasing_completion = eraser + prefix + remainder 00157 // 00158 // or, given that token = prefix + remainder 00159 // normal_completion = token 00160 // erasing_completion = eraser + token 00161 // 00162 // where eraser = ^H+ (one or more backspace characters) 00163 // 00164 // offset to first non ^H character in completion (^H are inserted 00165 // by abbreviation expansion predictor to erase abbreviation from 00166 // stream) 00167 // 00168 std::string result; 00169 00170 std::string::size_type offset = str.find_first_not_of('\b'); 00171 if (offset == 0) { 00172 // normal completion, 00173 // ensure that current prefix is a substring of completion 00174 // token and set result 00175 // 00176 if (contextTracker->isCompletionValid(str)) { 00177 std::string prefix = contextTracker->getPrefix(); 00178 result = str.substr(prefix.size()); 00179 } else { 00180 std::string message = "[Presage] Error: token '"; 00181 message += str; 00182 message += "' does not match prefix: "; 00183 message += contextTracker->getPrefix(); 00184 throw PresageException(PRESAGE_TOKEN_PREFIX_MISMATCH_ERROR, message); 00185 } 00186 } else { 00187 // erasing completion, 00188 // pass it to tracker in its entirety 00189 // 00190 result = str; 00191 } 00192 00193 // if (append_trailing_space_is_on()) // TODO: make this configurable 00194 result += ' '; 00195 00196 return result; 00197 } 00198 00199 std::string Presage::context () const 00200 throw (PresageException) 00201 { 00202 return contextTracker->getPastStream(); 00203 } 00204 00205 bool Presage::context_change () const 00206 throw (PresageException) 00207 { 00208 return contextTracker->contextChange(); 00209 } 00210 00211 std::string Presage::prefix () const 00212 throw (PresageException) 00213 { 00214 return contextTracker->getPrefix(); 00215 } 00216 00217 std::string Presage::config (const std::string variable) const 00218 throw (PresageException) 00219 { 00220 return configuration->find (variable)->get_value (); 00221 } 00222 00223 void Presage::config (const std::string variable, const std::string value) const 00224 throw (PresageException) 00225 { 00226 configuration->find (variable)->set_value (value); 00227 } 00228 00229 void Presage::save_config () const 00230 throw (PresageException) 00231 { 00232 profileManager->save_profile (); 00233 } 00234 00235 00236 00237 struct _presage { 00238 PresageCallback* presage_callback_object; 00239 Presage* presage_object; 00240 }; 00241 00242 class CPresageCallback : public PresageCallback 00243 { 00244 public: 00245 CPresageCallback (_presage_callback_get_past_stream past, 00246 void* past_arg, 00247 _presage_callback_get_future_stream future, 00248 void* future_arg) 00249 : m_get_past_stream_cb (past), 00250 m_get_past_stream_cb_arg (past_arg), 00251 m_get_future_stream_cb (future), 00252 m_get_future_stream_cb_arg (future_arg) 00253 { } 00254 00255 virtual ~CPresageCallback() { } 00256 00257 std::string get_past_stream() const { 00258 return (*m_get_past_stream_cb) (m_get_past_stream_cb_arg); 00259 } 00260 00261 std::string get_future_stream() const { 00262 return (*m_get_future_stream_cb) (m_get_future_stream_cb_arg); 00263 } 00264 00265 private: 00266 _presage_callback_get_past_stream m_get_past_stream_cb; 00267 void* m_get_past_stream_cb_arg; 00268 _presage_callback_get_future_stream m_get_future_stream_cb; 00269 void* m_get_future_stream_cb_arg; 00270 }; 00271 00272 #define presage_exception_handler(CODE) \ 00273 try \ 00274 { \ 00275 CODE; \ 00276 } \ 00277 catch (PresageException& ex) \ 00278 { \ 00279 return ex.code (); \ 00280 } \ 00281 return PRESAGE_OK; 00282 00283 #define presage_exception_handler_with_result(CODE) \ 00284 try \ 00285 { \ 00286 CODE; \ 00287 } \ 00288 catch (PresageException& ex) \ 00289 { \ 00290 (*result) = 0; \ 00291 return ex.code (); \ 00292 } \ 00293 return PRESAGE_OK; 00294 00295 static char* alloc_c_str (const std::string& str) 00296 { 00297 char* result_c_str = (char*) malloc (str.size() + 1); 00298 if (result_c_str) 00299 strcpy (result_c_str, str.c_str()); 00300 return result_c_str; 00301 } 00302 00303 presage_error_code_t presage_new (_presage_callback_get_past_stream past_stream_cb, 00304 void* past_stream_cb_arg, 00305 _presage_callback_get_future_stream future_stream_cb, 00306 void* future_stream_cb_arg, 00307 presage_t* result) 00308 { 00309 presage_exception_handler_with_result 00310 ( 00311 (*result) = (presage_t) malloc (sizeof (_presage)); 00312 00313 (*result)->presage_callback_object = new CPresageCallback (past_stream_cb, 00314 past_stream_cb_arg, 00315 future_stream_cb, 00316 future_stream_cb_arg); 00317 (*result)->presage_object = new Presage ((*result)->presage_callback_object); 00318 00319 ); 00320 } 00321 00322 presage_error_code_t presage_new_with_config (_presage_callback_get_past_stream past_stream_cb, 00323 void* past_stream_cb_arg, 00324 _presage_callback_get_future_stream future_stream_cb, 00325 void* future_stream_cb_arg, 00326 const char* config, 00327 presage_t* result) 00328 { 00329 presage_exception_handler_with_result 00330 ( 00331 (*result) = (presage_t) malloc (sizeof (_presage)); 00332 00333 (*result)->presage_callback_object = new CPresageCallback (past_stream_cb, 00334 past_stream_cb_arg, 00335 future_stream_cb, 00336 future_stream_cb_arg); 00337 (*result)->presage_object = new Presage ((*result)->presage_callback_object, config); 00338 ); 00339 } 00340 00341 void presage_free (presage_t prsg) 00342 { 00343 if (prsg) 00344 { 00345 delete prsg->presage_object; 00346 delete prsg->presage_callback_object; 00347 00348 free (prsg); 00349 } 00350 } 00351 00352 void presage_free_string (char* str) 00353 { 00354 free (str); 00355 } 00356 00357 void presage_free_string_array (char** strs) 00358 { 00359 if (strs) { 00360 for (size_t t = 0; strs[t] != 0; t++) { 00361 free (strs[t]); 00362 } 00363 free (strs); 00364 } 00365 } 00366 00367 presage_error_code_t presage_predict (presage_t prsg, char*** result) 00368 { 00369 presage_exception_handler_with_result 00370 ( 00371 std::vector<std::string> prediction = prsg->presage_object->predict(); 00372 00373 size_t prediction_c_str_size = prediction.size() + 1; 00374 char** prediction_c_str = (char**) malloc (prediction_c_str_size * sizeof(char*)); 00375 memset (prediction_c_str, 0, prediction_c_str_size * sizeof(char*)); 00376 00377 size_t i = 0; 00378 while (i < prediction_c_str_size - 1) { 00379 prediction_c_str[i] = (char*) malloc (prediction[i].size() + 1); 00380 strcpy (prediction_c_str[i], prediction[i].c_str()); 00381 i++; 00382 } 00383 prediction_c_str[i] = 0; 00384 00385 *result = prediction_c_str; 00386 ); 00387 } 00388 00389 presage_error_code_t presage_completion (presage_t prsg, const char* token, char** result) 00390 { 00391 presage_exception_handler_with_result 00392 ( 00393 *result = alloc_c_str (prsg->presage_object->completion (token)); 00394 ); 00395 } 00396 00397 presage_error_code_t presage_context (presage_t prsg, char** result) 00398 { 00399 presage_exception_handler_with_result 00400 ( 00401 *result = alloc_c_str (prsg->presage_object->context ()); 00402 ); 00403 } 00404 00405 presage_error_code_t presage_context_change (presage_t prsg, int* result) 00406 { 00407 presage_exception_handler_with_result 00408 ( 00409 *result = prsg->presage_object->context_change (); 00410 ); 00411 } 00412 00413 presage_error_code_t presage_prefix (presage_t prsg, char** result) 00414 { 00415 presage_exception_handler_with_result 00416 ( 00417 *result = alloc_c_str (prsg->presage_object->prefix ()); 00418 ); 00419 } 00420 00421 presage_error_code_t presage_config (presage_t prsg, const char* variable, char** result) 00422 { 00423 presage_exception_handler_with_result 00424 ( 00425 *result = alloc_c_str (prsg->presage_object->config (variable)); 00426 ); 00427 } 00428 00429 presage_error_code_t presage_config_set (presage_t prsg, const char* variable, const char* value) 00430 { 00431 presage_exception_handler 00432 ( 00433 prsg->presage_object->config (variable, value) 00434 ); 00435 } 00436 00437 presage_error_code_t presage_save_config (presage_t prsg) 00438 { 00439 presage_exception_handler 00440 ( 00441 prsg->presage_object->save_config () 00442 ); 00443 }