presage  0.8.8
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 
140  throw (PresageException)
141 {
142  return const_cast<PresageCallback*>(contextTracker->callback(callback));
143 }
144 
145 std::string Presage::completion (const std::string str)
146  throw (PresageException)
147 {
148  // There are two types of completions: normal and erasing.
149  // normal_completion = prefix + remainder
150  // erasing_completion = eraser + prefix + remainder
151  //
152  // or, given that token = prefix + remainder
153  // normal_completion = token
154  // erasing_completion = eraser + token
155  //
156  // where eraser = ^H+ (one or more backspace characters)
157  //
158  // offset to first non ^H character in completion (^H are inserted
159  // by abbreviation expansion predictor to erase abbreviation from
160  // stream)
161  //
162  std::string result;
163 
164  std::string::size_type offset = str.find_first_not_of('\b');
165  if (offset == 0) {
166  // normal completion,
167  // ensure that current prefix is a substring of completion
168  // token and set result
169  //
170  if (contextTracker->isCompletionValid(str)) {
171  std::string prefix = contextTracker->getPrefix();
172  result = str.substr(prefix.size());
173  } else {
174  std::string message = "[Presage] Error: token '";
175  message += str;
176  message += "' does not match prefix: ";
177  message += contextTracker->getPrefix();
179  }
180  } else {
181  // erasing completion,
182  // pass it to tracker in its entirety
183  //
184  result = str;
185  }
186 
187  // if (append_trailing_space_is_on()) // TODO: make this configurable
188  result += ' ';
189 
190  return result;
191 }
192 
193 std::string Presage::context () const
194  throw (PresageException)
195 {
196  return contextTracker->getPastStream();
197 }
198 
200  throw (PresageException)
201 {
202  return contextTracker->contextChange();
203 }
204 
205 std::string Presage::prefix () const
206  throw (PresageException)
207 {
208  return contextTracker->getPrefix();
209 }
210 
211 std::string Presage::config (const std::string variable) const
212  throw (PresageException)
213 {
214  return configuration->find (variable)->get_value ();
215 }
216 
217 void Presage::config (const std::string variable, const std::string value) const
218  throw (PresageException)
219 {
220  configuration->find (variable)->set_value (value);
221 }
222 
223 void Presage::save_config () const
224  throw (PresageException)
225 {
227 }
228 
229 
230 
231 struct _presage {
234 };
235 
237 {
238 public:
240  void* past_arg,
242  void* future_arg)
243  : m_get_past_stream_cb (past),
244  m_get_past_stream_cb_arg (past_arg),
245  m_get_future_stream_cb (future),
246  m_get_future_stream_cb_arg (future_arg)
247  { }
248 
249  virtual ~CPresageCallback() { }
250 
251  std::string get_past_stream() const {
253  }
254 
255  std::string get_future_stream() const {
257  }
258 
259 private:
264 };
265 
266 #define presage_exception_handler(CODE) \
267  try \
268  { \
269  CODE; \
270  } \
271  catch (PresageException& ex) \
272  { \
273  return ex.code (); \
274  } \
275  return PRESAGE_OK;
276 
277 #define presage_exception_handler_with_result(CODE) \
278  try \
279  { \
280  CODE; \
281  } \
282  catch (PresageException& ex) \
283  { \
284  (*result) = 0; \
285  return ex.code (); \
286  } \
287  return PRESAGE_OK;
288 
289 static char* alloc_c_str (const std::string& str)
290 {
291  char* result_c_str = (char*) malloc (str.size() + 1);
292  if (result_c_str)
293  strcpy (result_c_str, str.c_str());
294  return result_c_str;
295 }
296 
298  void* past_stream_cb_arg,
299  _presage_callback_get_future_stream future_stream_cb,
300  void* future_stream_cb_arg,
301  presage_t* result)
302 {
304  (
305  (*result) = (presage_t) malloc (sizeof (_presage));
306 
307  (*result)->presage_callback_object = new CPresageCallback (past_stream_cb,
308  past_stream_cb_arg,
309  future_stream_cb,
310  future_stream_cb_arg);
311  (*result)->presage_object = new Presage ((*result)->presage_callback_object);
312 
313  );
314 }
315 
317  void* past_stream_cb_arg,
318  _presage_callback_get_future_stream future_stream_cb,
319  void* future_stream_cb_arg,
320  const char* config,
321  presage_t* result)
322 {
324  (
325  (*result) = (presage_t) malloc (sizeof (_presage));
326 
327  (*result)->presage_callback_object = new CPresageCallback (past_stream_cb,
328  past_stream_cb_arg,
329  future_stream_cb,
330  future_stream_cb_arg);
331  (*result)->presage_object = new Presage ((*result)->presage_callback_object, config);
332  );
333 }
334 
336 {
337  if (prsg)
338  {
339  delete prsg->presage_object;
340  delete prsg->presage_callback_object;
341 
342  free (prsg);
343  }
344 }
345 
346 void presage_free_string (char* str)
347 {
348  free (str);
349 }
350 
351 void presage_free_string_array (char** strs)
352 {
353  if (strs) {
354  for (size_t t = 0; strs[t] != 0; t++) {
355  free (strs[t]);
356  }
357  free (strs);
358  }
359 }
360 
362 {
364  (
365  std::vector<std::string> prediction = prsg->presage_object->predict();
366 
367  size_t prediction_c_str_size = prediction.size() + 1;
368  char** prediction_c_str = (char**) malloc (prediction_c_str_size * sizeof(char*));
369  memset (prediction_c_str, 0, prediction_c_str_size * sizeof(char*));
370 
371  size_t i = 0;
372  while (i < prediction_c_str_size - 1) {
373  prediction_c_str[i] = (char*) malloc (prediction[i].size() + 1);
374  strcpy (prediction_c_str[i], prediction[i].c_str());
375  i++;
376  }
377  prediction_c_str[i] = 0;
378 
379  *result = prediction_c_str;
380  );
381 }
382 
383 presage_error_code_t presage_completion (presage_t prsg, const char* token, char** result)
384 {
386  (
387  *result = alloc_c_str (prsg->presage_object->completion (token));
388  );
389 }
390 
392 {
394  (
395  *result = alloc_c_str (prsg->presage_object->context ());
396  );
397 }
398 
400 {
402  (
403  *result = prsg->presage_object->context_change ();
404  );
405 }
406 
408 {
410  (
411  *result = alloc_c_str (prsg->presage_object->prefix ());
412  );
413 }
414 
415 presage_error_code_t presage_config (presage_t prsg, const char* variable, char** result)
416 {
418  (
419  *result = alloc_c_str (prsg->presage_object->config (variable));
420  );
421 }
422 
423 presage_error_code_t presage_config_set (presage_t prsg, const char* variable, const char* value)
424 {
426  (
427  prsg->presage_object->config (variable, value)
428  );
429 }
430 
432 {
434  (
435  prsg->presage_object->save_config ()
436  );
437 }