2
/******************************************************
3
* Presage, an extensible predictive text entry system
4
* ---------------------------------------------------
6
* Copyright (C) 2008 Matteo Vescovi <matteo.vescovi@yahoo.co.uk>
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.
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.
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.
28
const char* Selector::SUGGESTIONS = "Presage.Selector.SUGGESTIONS";
29
const char* Selector::REPEAT_SUGGESTIONS = "Presage.Selector.REPEAT_SUGGESTIONS";
30
const char* Selector::GREEDY_SUGGESTION_THRESHOLD = "Presage.Selector.GREEDY_SUGGESTION_THRESHOLD";
32
const char* Selector::LOGGER = "Presage.Selector.LOGGER";
34
Selector::Selector(Configuration* configuration, ContextTracker* ct)
36
config(configuration),
37
logger("Selector", std::cerr),
40
// build notification dispatch map
41
dispatcher.map (config->find (LOGGER), & Selector::set_logger);
42
dispatcher.map (config->find (SUGGESTIONS), & Selector::set_suggestions);
43
dispatcher.map (config->find (REPEAT_SUGGESTIONS), & Selector::set_repeat_suggestions);
44
dispatcher.map (config->find (GREEDY_SUGGESTION_THRESHOLD), & Selector::set_greedy_suggestion_threshold);
47
previous_prefix = contextTracker->getPrefix();
52
// nothing to do here, move along
55
std::vector<std::string> Selector::select( Prediction p )
57
// copy words from Prediction.Suggestion.word in result vector
58
std::vector<std::string> result;
60
for (size_t i=0 ; i<p.size() ; i++) {
61
token = p.getSuggestion(i).getWord();
62
result.push_back(token);
63
logger << DEBUG << "Added token to selector consideration set: " << token << endl;
66
// check whether user has not moved on to a new word
67
if (contextTracker->contextChange()) {
68
logger << DEBUG << "Context change detected." << endl;
69
clearSuggestedWords();
71
logger << DEBUG << "No context change detected." << endl;
74
// filter out suggestions that do not satisfy repetition constraint
75
if( !repeat_suggestions )
76
repetitionFilter( result );
78
// filter out suggestions that do not satisfy threshold constraint
79
if( greedy_suggestion_threshold > 0 )
80
thresholdFilter( result );
84
// check that we have enough selected words
85
if( result.size() < static_cast<unsigned int>(suggestions) ) {
86
// Job's not done, got to get a bigger Prediction
87
// we should invoke predict() to get more Suggestions
89
// could throw an exception that would be caught by predictor
90
// which would reissue the predict call to get more
93
// TODO <============================================
96
//std::cerr << "Not enough Suggestions" << std::endl;
100
// erase the requested number of words
101
result.erase( result.begin() + suggestions, result.end() );
104
// update suggested words set
105
updateSuggestedWords( result );
111
/** Trigger update of the suggested tokens cache
114
void Selector::update()
116
// check whether user has not moved on to a new word
117
if (contextTracker->contextChange()) {
118
clearSuggestedWords();
123
/** Adds suggestions to the set of previously selected suggestions.
126
void Selector::updateSuggestedWords( const std::vector<std::string>& v )
128
std::vector<std::string>::const_iterator i = v.begin();
129
while( i != v.end() ) {
130
logger << DEBUG << "Adding token to suggested token set: " << *i << endl;
131
suggestedWords.insert( *i );
135
logger << DEBUG << "Suggested words: ";
136
for (StringSet::const_iterator it = suggestedWords.begin();
137
it != suggestedWords.end();
139
logger << *it << ' ';
145
/** Clear the set of previously selected suggestions.
148
void Selector::clearSuggestedWords()
150
logger << DEBUG << "Clearing previously suggested tokens set." << endl;
151
suggestedWords.clear();
154
/** Filters out suggestions that have previously been selected in the current context.
156
* This filter removes the suggestions that have previously been
157
* selected. The set of suggestions that were previously selected is
158
* stored in suggestedWords. This filters removes the words that are
159
* contained in both @param v and suggestedWords.
162
void Selector::repetitionFilter( std::vector<std::string>& v )
164
std::vector< std::string > temp;
166
for( std::vector<std::string>::iterator i = v.begin();
169
if( suggestedWords.find( *i ) == suggestedWords.end() ) {
170
temp.push_back( *i );
171
logger << DEBUG << "Token passed repetition filter: " << *i << endl;
173
logger << DEBUG << "Token failed repetition filter: " << *i << endl;
180
/** Filters out suggestions that could save fewer than THRESHOLD keystrokes.
182
* Assuming prefix.size() == n, suggestion.size() == m, and THRESHOLD
183
* == t, then this filter removes those suggestions for which the
184
* following condition is true: (m - n) < t
187
void Selector::thresholdFilter( std::vector<std::string>& v )
189
assert( greedy_suggestion_threshold >= 0 );
191
// zero threshold indicates feature is disabled
192
if( greedy_suggestion_threshold != 0 ) {
194
int length = contextTracker->getPrefix().size();
195
std::vector<std::string>::iterator i = v.begin();
196
while (i != v.end()) {
197
if( (i->size()-length) < greedy_suggestion_threshold) {
198
logger << INFO << "Removing token: " << *i << endl;
208
/** Set LOGGER option.
211
void Selector::set_logger (const std::string& value)
213
logger << setlevel (value);
214
logger << INFO << "LOGGER: " << value << endl;
218
/** Set SUGGESTIONS option.
221
void Selector::set_suggestions(const std::string& value)
223
logger << INFO << "SUGGESTIONS: " << value << endl;
224
int result = Utility::toInt(value);
226
logger << ERROR << "Presage.Selector.SUGGESTIONS value out of range!/a" << endl;
227
// REVISIT: throw exception
231
suggestions = result;
235
/** Set REPEAT_SUGGESTION option.
238
void Selector::set_repeat_suggestions(const std::string& value)
240
logger << INFO << "REPEAT_SUGGESTIONS: " << value << endl;
241
bool result = Utility::isYes(value);
243
repeat_suggestions = result;
247
/** Set SUGGESTION_THRESHOLD option.
250
void Selector::set_greedy_suggestion_threshold(const std::string& value)
252
logger << INFO << "GREEDY_SUGGESTION_THRESHOLD: " << value << endl;
253
int result = Utility::toInt(value);
255
logger << ERROR << "GREEDY_SUGGESTION_THRESHOLD value out of range." << value << endl;
256
// REVISIT: throw exception
260
greedy_suggestion_threshold = result;
263
size_t Selector::get_suggestions () const
268
bool Selector::get_repeat_suggestions () const
270
return repeat_suggestions;
273
size_t Selector::get_greedy_suggestion_threshold () const
275
return greedy_suggestion_threshold;
278
void Selector::update (const Observable* variable)
280
logger << DEBUG << "update(" << variable->get_name () << ") called" << endl;
282
dispatcher.dispatch (variable);