presage  0.8.7
presage.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 
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 }