presage  0.9.2~beta
presage.cpp
Go to the documentation of this file.
1 
2 /******************************************************
3  * Presage, an extensible predictive text entry system
4  * ---------------------------------------------------
5  *
6  * Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk>
7 
8  This program is free software; you can redistribute it and/or modify
9  it under the terms of the GNU General Public License as published by
10  the Free Software Foundation; either version 2 of the License, or
11  (at your option) any later version.
12 
13  This program is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  GNU General Public License for more details.
17 
18  You should have received a copy of the GNU General Public License along
19  with this program; if not, write to the Free Software Foundation, Inc.,
20  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21  *
22  **********(*)*/
23 
24 
25 #include "presage.h"
26 
27 #include "core/profileManager.h"
28 #include "core/predictorRegistry.h"
30 #include "core/selector.h"
32 
34  throw (PresageException)
35 {
36  profileManager = new ProfileManager();
37  configuration = profileManager->get_configuration();
38  predictorRegistry = new PredictorRegistry(configuration);
39  contextTracker = new ContextTracker(configuration, predictorRegistry, callback);
40  predictorActivator = new PredictorActivator(configuration, predictorRegistry, contextTracker);
41  selector = new Selector(configuration, contextTracker);
42 }
43 
44 Presage::Presage (PresageCallback* callback, const std::string config_filename)
45  throw (PresageException)
46 {
47  profileManager = new ProfileManager(config_filename);
48  configuration = profileManager->get_configuration();
49  predictorRegistry = new PredictorRegistry(configuration);
50  contextTracker = new ContextTracker(configuration, predictorRegistry, callback);
51  predictorActivator = new PredictorActivator(configuration, predictorRegistry, contextTracker);
52  selector = new Selector(configuration, contextTracker);
53 }
54 
56 {
57  delete selector;
58  delete predictorActivator;
59  delete contextTracker;
60  delete predictorRegistry;
61  delete profileManager;
62 }
63 
64 std::vector<std::string> Presage::predict ()
65  throw (PresageException)
66 {
67  std::vector<std::string> result;
68 
69  unsigned int multiplier = 1;
70  Prediction prediction = predictorActivator->predict(multiplier++, 0);
71  result = selector->select(prediction);
72 
73  Prediction previous_prediction = prediction;
74  while ((result.size() < (selector->get_suggestions()))
75  && (prediction = predictorActivator->predict(multiplier++, 0)).size() > previous_prediction.size()) {
76  // while the number of predicted tokens is lower than desired,
77  // search harder (i.e. higher multiplier) for a prediction of
78  // sufficient size (i.e. that satisfies selector), as long as
79  // the result of current prediction is greater than the
80  // previous prediction (i.e. we are finding new tokens).
81  result = selector->select(prediction);
82  previous_prediction = prediction;
83  }
84 
86 
87  return result;
88 }
89 
90 std::multimap<double, std::string> Presage::predict (std::vector<std::string> filter)
91  throw (PresageException)
92 {
93  std::multimap<double, std::string> result;
94 
95  std::vector<std::string> selection;
96  const char** internal_filter = 0;
97  if(filter.size()>0)
98  {
99  // convert filter to internal representation - currently a null
100  // terminated const char**
101  internal_filter = new const char*[filter.size() + 1];
102  for (std::vector<std::string>::size_type i = 0; i < filter.size(); i++) {
103  internal_filter[i] = filter[i].c_str();
104  }
105  internal_filter[filter.size()] = 0;
106  }
107 
108  unsigned int multiplier = 1;
109  Prediction prediction = predictorActivator->predict(multiplier++, internal_filter);
110  selection = selector->select(prediction);
111 
112  Prediction previous_prediction = prediction;
113  while ((selection.size() < (selector->get_suggestions()))
114  && (prediction = predictorActivator->predict(multiplier++, internal_filter)).size() > previous_prediction.size()) {
115  // while the number of predicted tokens is lower than desired,
116  // search harder (i.e. higher multiplier) for a prediction of
117  // sufficient size (i.e. that satisfies selector), as long as
118  // the selection of current prediction is greater than the
119  // previous prediction (i.e. we are finding new tokens).
120  selection = selector->select(prediction);
121  previous_prediction = prediction;
122  }
123 
124  delete[] internal_filter;
125 
126  for (std::vector<std::string>::const_iterator it = selection.begin();
127  it != selection.end();
128  it++) {
129  std::pair<const double, std::string> p(prediction.getSuggestion(*it).getProbability(),
130  (*it));
131  result.insert(p);
132  }
133 
134  contextTracker->update();
135 
136  return result;
137 }
138 
139 void Presage::learn(const std::string text) const
140  throw (PresageException)
141 {
142  contextTracker->learn(text); // TODO: can pass additional param to
143  // learn to specify offline learning
144 }
145 
147  throw (PresageException)
148 {
149  return const_cast<PresageCallback*>(contextTracker->callback(callback));
150 }
151 
152 std::string Presage::completion (const std::string str)
153  throw (PresageException)
154 {
155  // There are two types of completions: normal and erasing.
156  // normal_completion = prefix + remainder
157  // erasing_completion = eraser + prefix + remainder
158  //
159  // or, given that token = prefix + remainder
160  // normal_completion = token
161  // erasing_completion = eraser + token
162  //
163  // where eraser = ^H+ (one or more backspace characters)
164  //
165  // offset to first non ^H character in completion (^H are inserted
166  // by abbreviation expansion predictor to erase abbreviation from
167  // stream)
168  //
169  std::string result;
170 
171  std::string::size_type offset = str.find_first_not_of('\b');
172  if (offset == 0) {
173  // normal completion,
174  // ensure that current prefix is a substring of completion
175  // token and set result
176  //
177  if (contextTracker->isCompletionValid(str)) {
178  std::string prefix = contextTracker->getPrefix();
179  result = str.substr(prefix.size());
180  } else {
181  std::string message = "[Presage] Error: token '";
182  message += str;
183  message += "' does not match prefix: ";
184  message += contextTracker->getPrefix();
186  }
187  } else {
188  // erasing completion,
189  // pass it to tracker in its entirety
190  //
191  result = str;
192  }
193 
194  // if (append_trailing_space_is_on()) // TODO: make this configurable
195  result += ' ';
196 
197  return result;
198 }
199 
200 std::string Presage::context () const
201  throw (PresageException)
202 {
203  return contextTracker->getPastStream();
204 }
205 
207  throw (PresageException)
208 {
209  return contextTracker->contextChange();
210 }
211 
212 std::string Presage::prefix () const
213  throw (PresageException)
214 {
215  return contextTracker->getPrefix();
216 }
217 
218 std::string Presage::config (const std::string variable) const
219  throw (PresageException)
220 {
221  return configuration->find (variable)->get_value ();
222 }
223 
224 void Presage::config (const std::string variable, const std::string value) const
225  throw (PresageException)
226 {
227  configuration->insert (variable, value);
228 }
229 
230 void Presage::save_config () const
231  throw (PresageException)
232 {
234 }
235 
236 std::string Presage::version () const
237  throw (PresageException)
238 {
239  return VERSION;
240 }
241 
242 
243 
244 struct _presage {
247 };
248 
250 {
251 public:
253  void* past_arg,
255  void* future_arg)
256  : m_get_past_stream_cb (past),
257  m_get_past_stream_cb_arg (past_arg),
258  m_get_future_stream_cb (future),
259  m_get_future_stream_cb_arg (future_arg)
260  { }
261 
262  virtual ~CPresageCallback() { }
263 
264  std::string get_past_stream() const {
266  }
267 
268  std::string get_future_stream() const {
270  }
271 
272 private:
277 };
278 
279 #define presage_exception_handler(CODE) \
280  try \
281  { \
282  CODE; \
283  } \
284  catch (PresageException& ex) \
285  { \
286  return ex.code (); \
287  } \
288  return PRESAGE_OK;
289 
290 #define presage_exception_handler_with_result(CODE) \
291  try \
292  { \
293  CODE; \
294  } \
295  catch (PresageException& ex) \
296  { \
297  (*result) = 0; \
298  return ex.code (); \
299  } \
300  return PRESAGE_OK;
301 
302 static char* alloc_c_str (const std::string& str)
303 {
304  char* result_c_str = (char*) malloc (str.size() + 1);
305  if (result_c_str)
306  strcpy (result_c_str, str.c_str());
307  return result_c_str;
308 }
309 
311  void* past_stream_cb_arg,
312  _presage_callback_get_future_stream future_stream_cb,
313  void* future_stream_cb_arg,
314  presage_t* result)
315 {
317  (
318  (*result) = (presage_t) malloc (sizeof (_presage));
319  if (*result != NULL)
320  {
321  (*result)->presage_callback_object = new CPresageCallback (past_stream_cb,
322  past_stream_cb_arg,
323  future_stream_cb,
324  future_stream_cb_arg);
325  (*result)->presage_object = new Presage ((*result)->presage_callback_object);
326  }
327 
328  );
329 }
330 
332  void* past_stream_cb_arg,
333  _presage_callback_get_future_stream future_stream_cb,
334  void* future_stream_cb_arg,
335  const char* config,
336  presage_t* result)
337 {
339  (
340  (*result) = (presage_t) malloc (sizeof (_presage));
341  if (*result != NULL)
342  {
343 
344  (*result)->presage_callback_object = new CPresageCallback (past_stream_cb,
345  past_stream_cb_arg,
346  future_stream_cb,
347  future_stream_cb_arg);
348  (*result)->presage_object = new Presage ((*result)->presage_callback_object, config);
349  }
350  );
351 }
352 
354 {
355  if (prsg)
356  {
357  delete prsg->presage_object;
358  delete prsg->presage_callback_object;
359 
360  free (prsg);
361  }
362 }
363 
364 void presage_free_string (char* str)
365 {
366  free (str);
367 }
368 
369 void presage_free_string_array (char** strs)
370 {
371  if (strs)
372  {
373  for (size_t t = 0; strs[t] != 0; t++)
374  free (strs[t]);
375 
376  free (strs);
377  }
378 }
379 
381 {
382  if (prediction)
383  {
384  for (size_t i = 0; prediction[i].token != 0; ++i)
385  free (prediction[i].token);
386 
387  free (prediction);
388  }
389 }
390 
392 {
394  (
395  std::vector<std::string> prediction = prsg->presage_object->predict();
396 
397  size_t prediction_c_str_size = prediction.size() + 1;
398  char** prediction_c_str = (char**) malloc (prediction_c_str_size * sizeof(char*));
399  if (prediction_c_str != NULL)
400  {
401  memset (prediction_c_str, 0, prediction_c_str_size * sizeof(char*));
402 
403  size_t i = 0;
404  while (i < prediction_c_str_size - 1) {
405  prediction_c_str[i] = (char*) malloc (prediction[i].size() + 1);
406  if (prediction_c_str[i] != NULL)
407  strcpy (prediction_c_str[i], prediction[i].c_str());
408  i++;
409  }
410  prediction_c_str[i] = 0;
411  }
412 
413  *result = prediction_c_str;
414  );
415 }
416 
418 {
419  // These typedefs are needed because the presage_exception_handler_with result
420  // macro below will choke on the comma in the type declarations.
421  // Typedef'ing them outside of the scope of the macro argument works. Yahoo!
422  //
423  typedef std::multimap<double, std::string> prediction_map_t;
424  typedef std::multimap<double, std::string>::const_reverse_iterator prediction_map_const_reverse_iterator_t;
425 
427  (
428  std::vector<std::string> filt;
429  for (size_t i = 0; filter[i] != 0; i++)
430  {
431  filt.push_back(filter[i]);
432  }
433 
434  prediction_map_t prediction = prsg->presage_object->predict (filt);
435  size_t prediction_result_size = prediction.size() + 1;
436  presage_prediction_t prediction_result = (presage_prediction_t) malloc (prediction_result_size * sizeof (*prediction_result));
437 
438  if (prediction_result != NULL)
439  {
440  memset (prediction_result, 0, prediction_result_size * sizeof (*prediction_result));
441 
442  size_t i = 0;
443  for (prediction_map_const_reverse_iterator_t it = prediction.rbegin();
444  it != prediction.rend();
445  ++it)
446  {
447  prediction_result[i].token = (char*) malloc ((it->second).size() + 1);
448  if (prediction_result[i].token != NULL)
449  {
450  strcpy (prediction_result[i].token, (it->second).c_str());
451  }
452  prediction_result[i].probability = it->first;
453 
454  i++;
455  }
456  }
457 
458  *result = prediction_result;
459  );
460 }
461 
463 {
465  (
466  prsg->presage_object->learn (text);
467  );
468 }
469 
470 presage_error_code_t presage_completion (presage_t prsg, const char* token, char** result)
471 {
473  (
474  *result = alloc_c_str (prsg->presage_object->completion (token));
475  );
476 }
477 
479 {
481  (
482  *result = alloc_c_str (prsg->presage_object->context ());
483  );
484 }
485 
487 {
489  (
490  *result = prsg->presage_object->context_change ();
491  );
492 }
493 
495 {
497  (
498  *result = alloc_c_str (prsg->presage_object->prefix ());
499  );
500 }
501 
502 presage_error_code_t presage_config (presage_t prsg, const char* variable, char** result)
503 {
505  (
506  *result = alloc_c_str (prsg->presage_object->config (variable));
507  );
508 }
509 
510 presage_error_code_t presage_config_set (presage_t prsg, const char* variable, const char* value)
511 {
513  (
514  prsg->presage_object->config (variable, value)
515  );
516 }
517 
519 {
521  (
522  prsg->presage_object->save_config ()
523  );
524 }
525 
527 {
529  (
530  *result = alloc_c_str (prsg->presage_object->version ());
531  );
532 }
std::string config(const std::string variable) const
Gets the value of specified configuration variable.
Definition: presage.cpp:218
PredictorRegistry * predictorRegistry
Definition: presage.h:255
Prediction predict(unsigned int multiplier, const char **filter)
presage_error_code_t
Selector * selector
Definition: presage.h:258
void presage_free(presage_t prsg)
Definition: presage.cpp:353
presage_error_code_t presage_save_config(presage_t prsg)
Definition: presage.cpp:518
presage_error_code_t presage_prefix(presage_t prsg, char **result)
Definition: presage.cpp:494
std::string get_past_stream() const
Definition: presage.cpp:264
void presage_free_prediction(presage_prediction_t prediction)
Definition: presage.cpp:380
presage_error_code_t presage_predict(presage_t prsg, char ***result)
Definition: presage.cpp:391
std::vector< std::string > predict()
Obtain a prediction.
Definition: presage.cpp:64
PresageCallback * callback(PresageCallback *callback)
Callback getter/setter.
Definition: presage.cpp:146
presage_error_code_t presage_learn(presage_t prsg, const char *text)
Definition: presage.cpp:462
std::string getPastStream() const
void * m_get_future_stream_cb_arg
Definition: presage.cpp:276
presage_error_code_t presage_config(presage_t prsg, const char *variable, char **result)
Definition: presage.cpp:502
presage_error_code_t presage_predict_with_filter(presage_t prsg, const char **filter, presage_prediction_t *result)
Definition: presage.cpp:417
Presage(PresageCallback *callback)
Definition: presage.cpp:33
void save_profile() const
double getProbability() const
Definition: suggestion.cpp:69
Presage * presage_object
Definition: presage.cpp:246
PresageCallback * presage_callback_object
Definition: presage.cpp:245
#define presage_exception_handler_with_result(CODE)
Definition: presage.cpp:290
void presage_free_string_array(char **strs)
Definition: presage.cpp:369
static char * alloc_c_str(const std::string &str)
Definition: presage.cpp:302
#define presage_exception_handler(CODE)
Definition: presage.cpp:279
presage_error_code_t presage_context(presage_t prsg, char **result)
Definition: presage.cpp:478
PredictorActivator * predictorActivator
Definition: presage.h:257
presage_error_code_t presage_context_change(presage_t prsg, int *result)
Definition: presage.cpp:486
ContextTracker * contextTracker
Definition: presage.h:256
std::string config
Definition: presageDemo.cpp:70
presage_suggestion_t * presage_prediction_t
Definition: presage.h:285
Suggestion getSuggestion(int=0) const
Definition: prediction.cpp:73
std::string version() const
Returns presage release version.
Definition: presage.cpp:236
presage_error_code_t presage_new_with_config(_presage_callback_get_past_stream past_stream_cb, void *past_stream_cb_arg, _presage_callback_get_future_stream future_stream_cb, void *future_stream_cb_arg, const char *config, presage_t *result)
Definition: presage.cpp:331
presage_error_code_t presage_config_set(presage_t prsg, const char *variable, const char *value)
Definition: presage.cpp:510
void * m_get_past_stream_cb_arg
Definition: presage.cpp:274
bool context_change() const
Returns true if a context change occured.
Definition: presage.cpp:206
~Presage()
Definition: presage.cpp:55
presage_error_code_t presage_version(presage_t prsg, char **result)
Definition: presage.cpp:526
presage_error_code_t presage_new(_presage_callback_get_past_stream past_stream_cb, void *past_stream_cb_arg, _presage_callback_get_future_stream future_stream_cb, void *future_stream_cb_arg, presage_t *result)
Definition: presage.cpp:310
_presage_callback_get_past_stream m_get_past_stream_cb
Definition: presage.cpp:273
size_t size() const
Definition: prediction.cpp:68
ProfileManager * profileManager
Definition: presage.h:253
const char *(* _presage_callback_get_future_stream)(void *)
Presage, the intelligent predictive text entry platform.
Definition: presage.h:107
std::string prefix() const
Returns the current prefix.
Definition: presage.cpp:212
CPresageCallback(_presage_callback_get_past_stream past, void *past_arg, _presage_callback_get_future_stream future, void *future_arg)
Definition: presage.cpp:252
std::string context() const
Returns the text entered so far.
Definition: presage.cpp:200
void save_config() const
Save current configuration to file.
Definition: presage.cpp:230
std::vector< std::string > select(Prediction)
Definition: selector.cpp:55
presage_error_code_t presage_completion(presage_t prsg, const char *token, char **result)
Definition: presage.cpp:470
std::string get_future_stream() const
Definition: presage.cpp:268
Tracks user interaction and context.
void learn(const std::string text) const
Learn from text offline.
Definition: presage.cpp:139
size_t get_suggestions() const
Definition: selector.cpp:246
void presage_free_string(char *str)
Definition: presage.cpp:364
std::string getPrefix() const
const char *(* _presage_callback_get_past_stream)(void *)
_presage_callback_get_future_stream m_get_future_stream_cb
Definition: presage.cpp:275
std::string completion(std::string str)
Request presage to return the completion string for the given predicted token.
Definition: presage.cpp:152
virtual ~CPresageCallback()
Definition: presage.cpp:262