~ubuntu-branches/ubuntu/oneiric/mozc/oneiric

« back to all changes in this revision

Viewing changes to converter/immutable_converter.cc

  • Committer: Bazaar Package Importer
  • Author(s): Nobuhiro Iwamatsu
  • Date: 2010-07-14 03:26:47 UTC
  • mfrom: (1.1.1 upstream)
  • Revision ID: james.westby@ubuntu.com-20100714032647-13qjisj6m8cm8jdx
Tags: 0.12.410.102-1
* New upstream release (Closes: #588971).
  - Add mozc-server, mozc-utils-gui and scim-mozc packages.
* Update debian/rules.
  Add --gypdir option to build_mozc.py.
* Update debian/control.
  - Bumped standards-version to 3.9.0.
  - Update description.
* Add mozc icon (Closes: #588972).
* Add patch which revises issue 18.
  ibus_mozc_issue18.patch
* kFreeBSD build support.
  support_kfreebsd.patch

Show diffs side-by-side

added added

removed removed

Lines of Context:
27
27
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28
28
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
29
 
30
 
#include "converter/immutable_converter.h"
 
30
#include "converter/immutable_converter_interface.h"
31
31
 
32
32
#include <algorithm>
33
33
#include <climits>
36
36
#include <vector>
37
37
#include "base/base.h"
38
38
#include "base/config_file_stream.h"
39
 
#include "base/thread.h"
 
39
#include "base/singleton.h"
40
40
#include "base/util.h"
41
 
#include "converter/dictionary_data.h"
42
 
#include "converter/dictionary_preloader.h"
43
41
#include "converter/key_corrector.h"
 
42
#include "converter/lattice.h"
44
43
#include "converter/segments.h"
45
 
#include "converter/converter_data.h"
46
 
#include "converter/connector.h"
 
44
#include "converter/connector_interface.h"
47
45
#include "converter/nbest_generator.h"
48
 
#include "converter/pos.h"
 
46
#include "converter/pos_matcher.h"
49
47
#include "converter/segmenter.h"
 
48
#include "dictionary/dictionary_interface.h"
50
49
#include "session/config_handler.h"
51
50
#include "session/config.pb.h"
52
 
#include "dictionary/dictionary.h"
53
51
 
54
52
namespace mozc {
55
 
 
56
53
namespace {
57
54
 
58
55
const size_t kMaxSegmentsSize   = 256;
61
58
const int    kDefaultNumberCost = 3000;
62
59
const int    kEOSPenalty        = 700;
63
60
 
64
 
// const char kLastNamePos[] = "姓";
65
 
// const char kFistNamePos[] = "名";
66
 
const char kLastNamePos[] = "\xE5\xA7\x93";
67
 
const char kFistNamePos[] = "\xE5\x90\x8D";
68
 
 
69
61
enum {
70
62
  CONNECTED,
71
63
  WEAK_CONNECTED,
72
64
  NOT_CONNECTED,
73
65
};
74
66
 
75
 
Node *InitBOSNode(ConverterData *data, uint16 length) {
76
 
  Node *bos_node = data->NewNode();
77
 
  bos_node->rid = 0;
78
 
  bos_node->lid = 0;
79
 
  bos_node->key.clear();
80
 
  bos_node->value = "BOS";
81
 
  bos_node->node_type = Node::BOS_NODE;
82
 
  bos_node->wcost = 0;
83
 
  bos_node->cost = 0;
84
 
  bos_node->begin_pos = length;
85
 
  bos_node->end_pos = length;
86
 
  return bos_node;
87
 
}
88
 
 
89
 
// For EOS node, we use both pure EOS node
90
 
// and "サ変名詞". Since many users still inputs via single-segment-conversion,
91
 
// the right word of user input is not always end of sentence.
92
 
// If you see the side effect of this treatment,
93
 
// set some penalty to node->wcost.
94
 
Node *InitEOSNode(ConverterData *data, uint16 length) {
95
 
  Node *eos_node = data->NewNode();
96
 
  eos_node->rid = 0;   // pure EOS
97
 
  eos_node->lid = 0;
98
 
  eos_node->key.clear();
99
 
  eos_node->value = "EOS";
100
 
  eos_node->node_type = Node::EOS_NODE;
101
 
  eos_node->wcost = 0;
102
 
  eos_node->cost = 0;
103
 
  eos_node->begin_pos = length;
104
 
  eos_node->end_pos = length;
105
 
 
106
 
  Node *eos_noun_node = data->NewNode();
107
 
  // "サ変名詞"
108
 
  // POS::unknown_id(), POS::unknown_id()
109
 
  // returns IDs for "サ変名詞"
110
 
  eos_noun_node->rid = POS::unknown_id();
111
 
  eos_noun_node->lid = POS::unknown_id();
112
 
  eos_noun_node->key.clear();
113
 
  eos_noun_node->value = "EOS";
114
 
  eos_noun_node->node_type = Node::EOS_NODE;
115
 
  eos_noun_node->wcost = kEOSPenalty;   // add some a constant as penalty
116
 
  eos_noun_node->cost = 0;
117
 
  eos_noun_node->begin_pos = length;
118
 
  eos_noun_node->end_pos = length;
119
 
 
120
 
  // chain nodes
121
 
  eos_node->bnext = eos_noun_node;
122
 
 
123
 
  return eos_node;
124
 
}
125
 
 
126
 
void InsertNodes(size_t pos, Node *node, ConverterData *data) {
127
 
  Node **begin_nodes_list = data->begin_nodes_list();
128
 
  Node **end_nodes_list = data->end_nodes_list();
129
 
 
130
 
  for (Node *rnode = node; rnode != NULL; rnode = rnode->bnext) {
131
 
    rnode->begin_pos = static_cast<uint16>(pos);
132
 
    rnode->end_pos = static_cast<uint16>(pos + rnode->key.size());
133
 
    rnode->prev = NULL;
134
 
    rnode->next = NULL;
135
 
    rnode->cost = 0;
136
 
    const size_t x = rnode->key.size() + pos;
137
 
    rnode->enext = end_nodes_list[x];
138
 
    end_nodes_list[x] = rnode;
139
 
  }
140
 
 
141
 
  if (begin_nodes_list[pos] == NULL) {
142
 
    begin_nodes_list[pos] = node;
143
 
  } else {
144
 
    for (Node *rnode = node; rnode != NULL; rnode = rnode->bnext) {
145
 
      if (rnode->bnext == NULL) {
146
 
        rnode->bnext = begin_nodes_list[pos];
147
 
        begin_nodes_list[pos] = node;
148
 
        break;
149
 
      }
150
 
    }
151
 
  }
152
 
}
153
 
 
154
 
// TODO(taku): move it to KeyCorrector
155
 
int GetCorrectedCostPenalty(const string &key) {
156
 
  // "んん" and "っっ" must be mis-spelling.
157
 
  // if (key.find("んん") != string::npos ||
158
 
  //     key.find("っっ") != string::npos) {
159
 
  if (key.find("\xE3\x82\x93\xE3\x82\x93") != string::npos ||
160
 
      key.find("\xE3\x81\xA3\xE3\x81\xA3") != string::npos) {
161
 
    return 0;
162
 
  }
163
 
  // add 3000 to the original word cost
164
 
  const int kCorrectedCostPenalty = 3000;
165
 
  return kCorrectedCostPenalty;
166
 
}
167
 
 
168
67
void InsertCorrectedNodes(size_t pos, const string &key,
169
 
                          const KeyCorrector &key_corrector,
170
 
                          Dictionary *dictionary,
171
 
                          ConverterData *data) {
 
68
                          const KeyCorrector *key_corrector,
 
69
                          DictionaryInterface *dictionary,
 
70
                          Lattice *lattice) {
 
71
  if (key_corrector == NULL) {
 
72
    return;
 
73
  }
172
74
  size_t length = 0;
173
 
  const char *str = key_corrector.GetCorrectedPrefix(pos, &length);
 
75
  const char *str = key_corrector->GetCorrectedPrefix(pos, &length);
174
76
  if (str == NULL || length == 0) {
175
77
    return;
176
78
  }
177
79
 
178
 
  Node *r_node = dictionary->LookupPrefix(str, length, data);
 
80
  Node *rnode = dictionary->LookupPrefix(str, length,
 
81
                                         lattice->node_allocator());
179
82
  Node *prev = NULL;
180
 
  for (Node *node = r_node; node != NULL; node = node->bnext) {
 
83
  for (Node *node = rnode; node != NULL; node = node->bnext) {
181
84
    const size_t offset =
182
 
        key_corrector.GetOriginalOffset(pos, node->key.size());
 
85
        key_corrector->GetOriginalOffset(pos, node->key.size());
183
86
    if (KeyCorrector::IsValidPosition(offset) && offset > 0) {
184
87
      // rewrite key
185
88
      node->key = key.substr(pos, offset);
186
 
      node->wcost += GetCorrectedCostPenalty(node->key);
 
89
      node->wcost += KeyCorrector::GetCorrectedCostPenalty(node->key);
187
90
      prev = node;
188
91
    } else {
189
92
      if (prev == NULL) {
190
 
        r_node = node;    // drop the first node
 
93
        rnode = node;    // drop the first node
191
94
      } else {
192
95
        prev->bnext = node->bnext;    // change the chain
193
96
      }
194
97
    }
195
98
  }
196
99
 
197
 
  if (r_node != NULL) {
198
 
    InsertNodes(pos, r_node, data);
 
100
  if (rnode != NULL) {
 
101
    lattice->Insert(pos, rnode);
199
102
  }
200
103
}
201
104
 
252
155
  group->push_back(static_cast<uint16>(segments->segments_size() - 1));
253
156
}
254
157
 
255
 
void DecomposeNumber(const string &input,
256
 
                     string *number, string *suffix) {
 
158
bool IsNumber(const char c) {
 
159
  return c >= '0' && c <= '9';
 
160
}
 
161
 
 
162
void DecomposeNumberAndSuffix(const string &input,
 
163
                              string *number, string *suffix) {
257
164
  const char *begin = input.data();
258
165
  const char *end = input.data() + input.size();
259
166
  size_t pos = 0;
260
167
  while (begin < end) {
261
 
    if (*begin >= '0' && *begin <= '9') {
 
168
    if (IsNumber(*begin)) {
262
169
      ++pos;
263
170
      ++begin;
264
171
      continue;
269
176
  *suffix = input.substr(pos, input.size() - pos);
270
177
}
271
178
 
 
179
void DecomposePrefixAndNumber(const string &input,
 
180
                              string *prefix, string *number) {
 
181
  const char *begin = input.data();
 
182
  const char *end = input.data() + input.size() - 1;
 
183
  size_t pos = input.size();
 
184
  while (begin <= end) {
 
185
    if (IsNumber(*end)) {
 
186
      --pos;
 
187
      --end;
 
188
      continue;
 
189
    }
 
190
    break;
 
191
  }
 
192
  *prefix = input.substr(0, pos);
 
193
  *number = input.substr(pos, input.size() - pos);
 
194
}
 
195
 
 
196
 
272
197
void NormalizeHistorySegments(Segments *segments) {
273
198
  for (size_t i = 0; i < segments->history_segments_size(); ++i) {
274
199
    Segment *segment = segments->mutable_history_segment(i);
296
221
        key == c->content_value &&
297
222
        key == c->content_key &&
298
223
        Util::GetScriptType(key) == Util::NUMBER &&
299
 
        key[key.size() - 1] >= '0' && key[key.size() - 1] <= '9') {
 
224
        IsNumber(key[key.size() - 1])) {
300
225
      key = key.substr(key.size() - 1, 1);  // use the last digit only
301
226
      segment->set_key(key);
302
227
      c->value = key;
305
230
    }
306
231
  }
307
232
}
308
 
}   // anonymous namespace
309
233
 
310
 
class ImmutableConverterImpl: public ImmutableConverter {
 
234
class ImmutableConverterImpl: public ImmutableConverterInterface {
311
235
 public:
312
236
  virtual bool Convert(Segments *segments) const;
313
 
  virtual Dictionary *GetDictionary() const;
314
237
  ImmutableConverterImpl();
315
238
  virtual ~ImmutableConverterImpl() {}
316
239
 
317
240
 private:
318
 
  Node *Lookup(const char *begin,
319
 
               const char *end,
320
 
               ConverterData *data) const;
 
241
  Node *Lookup(const char *begin, const char *end,
 
242
               Lattice *lattice) const;
321
243
 
322
 
  void Resegment(size_t pos, ConverterData *data) const;
 
244
  void Resegment(size_t pos, Lattice *lattice) const;
323
245
 
324
246
  // return true resegmentation happened
325
 
  bool ResegmentArabicNumberAndSuffix(size_t pos, ConverterData *data) const;
326
 
  bool ResegmentPersonalName(size_t pos, ConverterData *data) const;
 
247
  bool ResegmentArabicNumberAndSuffix(size_t pos, Lattice *lattice) const;
 
248
  bool ResegmentPrefixAndArabicNumber(size_t pos, Lattice *lattice) const;
 
249
  bool ResegmentPersonalName(size_t pos, Lattice *lattice) const;
327
250
 
328
251
  bool MakeLattice(Segments *segments) const;
329
252
  bool ModifyLattice(Segments *segments) const;
342
265
    return connector_->GetTransitionCost(lnode->rid, rnode->lid) + rnode->wcost;
343
266
  }
344
267
 
345
 
  scoped_ptr<ConnectorInterface> connector_;
346
 
  scoped_ptr<Dictionary> dictionary_;
 
268
  ConnectorInterface *connector_;
 
269
  DictionaryInterface *dictionary_;
347
270
 
348
271
  int32 last_to_first_name_transition_cost_;
349
272
  DISALLOW_COPY_AND_ASSIGN(ImmutableConverterImpl);
350
273
};
351
274
 
352
275
ImmutableConverterImpl::ImmutableConverterImpl()
353
 
    : dictionary_(new Dictionary),
 
276
    : connector_(ConnectorFactory::GetConnector()),
 
277
      dictionary_(DictionaryFactory::GetDictionary()),
354
278
      last_to_first_name_transition_cost_(0) {
355
 
  size_t connection_size = 0;
356
 
  const char *connection_data =
357
 
      DictionaryData::GetConnectionData(&connection_size);
358
 
  CHECK(connection_data);
359
 
  CHECK_GT(connection_size, 0);
360
 
  connector_.reset(ConnectorInterface::OpenFromArray(connection_data,
361
 
                                                     connection_size));
362
 
  CHECK(connector_.get());
363
 
 
364
 
  DictionaryInterface *sys_dic = dictionary_->Add(Dictionary::SYSTEM);
365
 
  CHECK(sys_dic);
366
 
 
367
 
  size_t dictionary_size = 0;
368
 
  const char *dictionary_data =
369
 
      DictionaryData::GetDictionaryData(&dictionary_size);
370
 
  CHECK(dictionary_data);
371
 
  CHECK_GT(dictionary_size, 0);
372
 
 
373
 
  CHECK(sys_dic->OpenFromArray(dictionary_data,
374
 
                               dictionary_size));
375
 
 
376
 
  DictionaryInterface *user_dic = dictionary_->Add(Dictionary::USER);
377
 
  CHECK(user_dic);
378
 
 
379
279
  last_to_first_name_transition_cost_
380
280
      = connector_->GetTransitionCost(
381
 
          POS::last_name_id(), POS::first_name_id());
382
 
 
383
 
  DictionaryPreloader::PreloadIfApplicable();
384
 
}
385
 
 
386
 
Dictionary *ImmutableConverterImpl::GetDictionary() const {
387
 
  return dictionary_.get();
388
 
}
389
 
 
390
 
void ImmutableConverterImpl::Resegment(size_t pos, ConverterData *data) const {
391
 
  if (ResegmentArabicNumberAndSuffix(pos, data)) {
392
 
    VLOG(1) << "ResegmentArabicNumberAndSuffix returned true";
393
 
    return;
394
 
  }
395
 
 
396
 
  if (ResegmentPersonalName(pos, data)) {
 
281
          POSMatcher::GetLastNameId(), POSMatcher::GetFirstNameId());
 
282
}
 
283
 
 
284
void ImmutableConverterImpl::Resegment(size_t pos, Lattice *lattice) const {
 
285
  if (ResegmentArabicNumberAndSuffix(pos, lattice)) {
 
286
    VLOG(1) << "ResegmentArabicNumberAndSuffix returned true";
 
287
    return;
 
288
  }
 
289
 
 
290
  if (ResegmentPrefixAndArabicNumber(pos, lattice)) {
 
291
    VLOG(1) << "ResegmentArabicNumberAndSuffix returned true";
 
292
    return;
 
293
  }
 
294
 
 
295
  if (ResegmentPersonalName(pos, lattice)) {
397
296
    VLOG(1) << "ResegmentPersonalName returned true";
398
297
    return;
399
298
  }
402
301
// Currently, only arabic_number + suffix patterns are resegmented
403
302
// TODO(taku): consider kanji number into consideration
404
303
bool ImmutableConverterImpl::ResegmentArabicNumberAndSuffix(
405
 
    size_t pos, ConverterData *data) const {
406
 
  Node **begin_nodes_list = data->begin_nodes_list();
407
 
  const Node *bnode = begin_nodes_list[pos];
 
304
    size_t pos, Lattice *lattice) const {
 
305
  const Node *bnode = lattice->begin_nodes(pos);
408
306
  if (bnode == NULL) {
409
307
    VLOG(1) << "bnode is NULL";
410
308
    return false;
414
312
 
415
313
  for (const Node *compound_node = bnode;
416
314
       compound_node != NULL; compound_node = compound_node->bnext) {
417
 
    if (bnode->value.size() > 0 &&
418
 
        bnode->value[0] >= '0' && bnode->value[0] <= '9' &&
419
 
        bnode->key[0] >= '0' && bnode->key[0] <= '9' &&
420
 
        POS::IsNumber(compound_node->lid) &&
421
 
        !POS::IsNumber(compound_node->rid)) {
 
315
    if (!compound_node->value.empty() && !compound_node->key.empty() &&
 
316
        POSMatcher::IsNumber(compound_node->lid) &&
 
317
        !POSMatcher::IsNumber(compound_node->rid) &&
 
318
        IsNumber(compound_node->value[0]) && IsNumber(compound_node->key[0])) {
422
319
      string number_value, number_key;
423
320
      string suffix_value, suffix_key;
424
 
      DecomposeNumber(compound_node->value, &number_value, &suffix_value);
425
 
      DecomposeNumber(compound_node->key,   &number_key, &suffix_key);
 
321
      DecomposeNumberAndSuffix(compound_node->value,
 
322
                               &number_value, &suffix_value);
 
323
      DecomposeNumberAndSuffix(compound_node->key,
 
324
                               &number_key, &suffix_key);
426
325
 
427
326
      if (suffix_value.empty() || suffix_key.empty()) {
428
327
        continue;
434
333
        continue;
435
334
      }
436
335
 
437
 
      const int32 wcost = compound_node->wcost / 2;
 
336
      // do -1 so that resegmented nodes are boosted
 
337
      // over compound node.
 
338
      const int32 wcost = max(compound_node->wcost / 2 - 1, 0);
438
339
 
439
 
      Node *number_node = data->NewNode();
 
340
      Node *number_node = lattice->NewNode();
440
341
      CHECK(number_node);
441
342
      number_node->key = number_key;
442
343
      number_node->value = number_value;
447
348
      number_node->bnext = NULL;
448
349
 
449
350
      // insert number into the lattice
450
 
      InsertNodes(pos, number_node, data);
 
351
      lattice->Insert(pos, number_node);
451
352
 
452
 
      Node *suffix_node = data->NewNode();
 
353
      Node *suffix_node = lattice->NewNode();
453
354
      CHECK(suffix_node);
454
355
      suffix_node->key = suffix_key;
455
356
      suffix_node->value = suffix_value;
462
363
      suffix_node->constrained_prev = number_node;
463
364
 
464
365
      // insert suffix into the lattice
465
 
      InsertNodes(pos + number_node->key.size(), suffix_node, data);
 
366
      lattice->Insert(pos + number_node->key.size(), suffix_node);
466
367
      VLOG(1) << "Resegmented: " << compound_node->value << " "
467
368
              << number_node->value << " " << suffix_node->value;
468
369
 
473
374
  return modified;
474
375
}
475
376
 
 
377
bool ImmutableConverterImpl::ResegmentPrefixAndArabicNumber(
 
378
    size_t pos, Lattice *lattice) const {
 
379
  const Node *bnode = lattice->begin_nodes(pos);
 
380
  if (bnode == NULL) {
 
381
    VLOG(1) << "bnode is NULL";
 
382
    return false;
 
383
  }
 
384
 
 
385
  bool modified = false;
 
386
 
 
387
  for (const Node *compound_node = bnode;
 
388
       compound_node != NULL; compound_node = compound_node->bnext) {
 
389
    // Unlike ResegmentArabicNumberAndSuffix, we don't
 
390
    // check POS as words ending with Arabic numbers are pretty rare.
 
391
    if (compound_node->value.size() > 1 && compound_node->key.size() > 1 &&
 
392
        !IsNumber(compound_node->value[0]) &&
 
393
        !IsNumber(compound_node->key[0]) &&
 
394
        IsNumber(compound_node->value[compound_node->value.size() - 1]) &&
 
395
        IsNumber(compound_node->key[compound_node->key.size() - 1])) {
 
396
      string number_value, number_key;
 
397
      string prefix_value, prefix_key;
 
398
      DecomposePrefixAndNumber(compound_node->value,
 
399
                               &prefix_value, &number_value);
 
400
      DecomposePrefixAndNumber(compound_node->key,
 
401
                               &prefix_key, &number_key);
 
402
 
 
403
      if (prefix_value.empty() || prefix_key.empty()) {
 
404
        continue;
 
405
      }
 
406
 
 
407
      // not compatibile
 
408
      if (number_value != number_key) {
 
409
        LOG(WARNING) << "Incompatible key/value number pair";
 
410
        continue;
 
411
      }
 
412
 
 
413
      // do -1 so that resegmented nodes are boosted
 
414
      // over compound node.
 
415
      const int32 wcost = max(compound_node->wcost / 2 - 1, 0);
 
416
 
 
417
      Node *prefix_node = lattice->NewNode();
 
418
      CHECK(prefix_node);
 
419
      prefix_node->key = prefix_key;
 
420
      prefix_node->value = prefix_value;
 
421
      prefix_node->lid = compound_node->lid;
 
422
      prefix_node->rid = 0;   // 0 to 0 transition cost is 0
 
423
      prefix_node->wcost = wcost;
 
424
      prefix_node->node_type = Node::NOR_NODE;
 
425
      prefix_node->bnext = NULL;
 
426
 
 
427
      // insert number into the lattice
 
428
      lattice->Insert(pos, prefix_node);
 
429
 
 
430
      Node *number_node = lattice->NewNode();
 
431
      CHECK(number_node);
 
432
      number_node->key = number_key;
 
433
      number_node->value = number_value;
 
434
      number_node->lid = 0;
 
435
      number_node->rid = compound_node->rid;
 
436
      number_node->wcost = wcost;
 
437
      number_node->node_type = Node::NOR_NODE;
 
438
      number_node->bnext = NULL;
 
439
 
 
440
      number_node->constrained_prev = prefix_node;
 
441
 
 
442
      // insert number into the lattice
 
443
      lattice->Insert(pos + prefix_node->key.size(), number_node);
 
444
      VLOG(1) << "Resegmented: " << compound_node->value << " "
 
445
              << prefix_node->value << " " << number_node->value;
 
446
 
 
447
      modified = true;
 
448
    }
 
449
  }
 
450
 
 
451
  return modified;
 
452
}
 
453
 
476
454
bool ImmutableConverterImpl::ResegmentPersonalName(
477
 
    size_t pos, ConverterData *data) const {
478
 
  Node **begin_nodes_list = data->begin_nodes_list();
479
 
  const Node *bnode = begin_nodes_list[pos];
 
455
    size_t pos, Lattice *lattice) const {
 
456
  const Node *bnode = lattice->begin_nodes(pos);
480
457
  if (bnode == NULL) {
481
458
    VLOG(1) << "bnode is NULL";
482
459
    return false;
488
465
  for (const Node *compound_node = bnode;
489
466
       compound_node != NULL; compound_node = compound_node->bnext) {
490
467
    // left word is last name and right word is first name
491
 
    if (compound_node->lid != POS::last_name_id() ||
492
 
        compound_node->rid != POS::first_name_id()) {
 
468
    if (compound_node->lid != POSMatcher::GetLastNameId() ||
 
469
        compound_node->rid != POSMatcher::GetFirstNameId()) {
493
470
      continue;
494
471
    }
495
472
 
524
501
          compound_node->key.size() > lnode->key.size() &&
525
502
          compound_node->value.find(lnode->value) == 0) {
526
503
        // rnode(first_name) is a suffix of compound, Constraint 1.
527
 
        for (const Node *rnode = begin_nodes_list[pos + lnode->key.size()];
 
504
        for (const Node *rnode = lattice->begin_nodes(pos + lnode->key.size());
528
505
             rnode != NULL; rnode = rnode->bnext) {
529
506
          if ((lnode->value.size() + rnode->value.size())
530
507
              == compound_node->value.size() &&
548
525
 
549
526
    // Constraint 4.a
550
527
    if (len >= 4 &&
551
 
        (best_last_name_node->lid != POS::last_name_id() &&
552
 
         best_first_name_node->rid != POS::first_name_id())) {
 
528
        (best_last_name_node->lid != POSMatcher::GetLastNameId() &&
 
529
         best_first_name_node->rid != POSMatcher::GetFirstNameId())) {
553
530
      continue;
554
531
    }
555
532
 
556
533
    // Constraint 4.b
557
534
    if (len == 3 &&
558
 
        (best_last_name_node->lid != POS::last_name_id() ||
559
 
         best_first_name_node->rid != POS::first_name_id())) {
 
535
        (best_last_name_node->lid != POSMatcher::GetLastNameId() ||
 
536
         best_first_name_node->rid != POSMatcher::GetFirstNameId())) {
560
537
      continue;
561
538
    }
562
539
 
574
551
    const int32 wcost = (compound_node->wcost -
575
552
                         last_to_first_name_transition_cost_) / 2;
576
553
 
577
 
    Node *last_name_node = data->NewNode();
 
554
    Node *last_name_node = lattice->NewNode();
578
555
    CHECK(last_name_node);
579
556
    last_name_node->key = best_last_name_node->key;
580
557
    last_name_node->value = best_last_name_node->value;
581
558
    last_name_node->lid = compound_node->lid;
582
 
    last_name_node->rid = POS::last_name_id();
 
559
    last_name_node->rid = POSMatcher::GetLastNameId();
583
560
    last_name_node->wcost = wcost;
584
561
    last_name_node->node_type = Node::NOR_NODE;
585
562
    last_name_node->bnext = NULL;
586
563
 
587
564
    // insert last_name into the lattice
588
 
    InsertNodes(pos, last_name_node, data);
 
565
    lattice->Insert(pos, last_name_node);
589
566
 
590
 
    Node *first_name_node = data->NewNode();
 
567
    Node *first_name_node = lattice->NewNode();
591
568
    CHECK(first_name_node);
592
569
    first_name_node->key = best_first_name_node->key;
593
570
    first_name_node->value = best_first_name_node->value;
594
 
    first_name_node->lid = POS::first_name_id();
 
571
    first_name_node->lid = POSMatcher::GetFirstNameId();
595
572
    first_name_node->rid = compound_node->rid;
596
573
    first_name_node->wcost = wcost;
597
574
    first_name_node->node_type = Node::NOR_NODE;
600
577
    first_name_node->constrained_prev = last_name_node;
601
578
 
602
579
    // insert first_name into the lattice
603
 
    InsertNodes(pos + last_name_node->key.size(), first_name_node, data);
 
580
    lattice->Insert(pos + last_name_node->key.size(), first_name_node);
604
581
 
605
582
    VLOG(2) << "Resegmented: " << compound_node->value << " "
606
583
            << last_name_node->value << " " << first_name_node->value;
613
590
 
614
591
Node *ImmutableConverterImpl::Lookup(const char *begin,
615
592
                                     const char *end,
616
 
                                     ConverterData *data) const {
617
 
  data->set_max_nodes_size(8192);
 
593
                                     Lattice *lattice) const {
 
594
  lattice->node_allocator()->set_max_nodes_size(8192);
618
595
  Node *result_node =
619
596
      dictionary_->LookupPrefix(begin,
620
597
                                static_cast<int>(end - begin),
621
 
                                data);
 
598
                                lattice->node_allocator());
622
599
 
623
600
  size_t mblen = 0;
624
601
  const uint16 w = Util::UTF8ToUCS2(begin, end, &mblen);
626
603
  const Util::ScriptType first_script_type = Util::GetScriptType(w);
627
604
  const Util::FormType first_form_type = Util::GetFormType(w);
628
605
 
629
 
  Node *new_node = data->NewNode();
 
606
  Node *new_node = lattice->NewNode();
 
607
  CHECK(new_node);
630
608
  if (first_script_type == Util::NUMBER) {
631
 
    new_node->lid = POS::number_id();
632
 
    new_node->rid = POS::number_id();
 
609
    new_node->lid = POSMatcher::GetNumberId();
 
610
    new_node->rid = POSMatcher::GetNumberId();
633
611
  } else {
634
 
    new_node->lid = POS::unknown_id();
635
 
    new_node->rid = POS::unknown_id();
 
612
    new_node->lid = POSMatcher::GetUnknownId();
 
613
    new_node->rid = POSMatcher::GetUnknownId();
636
614
  }
637
615
 
638
616
  new_node->wcost = kMaxCost;
667
645
 
668
646
  if (num_char > 1) {
669
647
    mblen = static_cast<uint32>(p - begin);
670
 
    Node *new_node = data->NewNode();
 
648
    Node *new_node = lattice->NewNode();
 
649
    CHECK(new_node);
671
650
    if (first_script_type == Util::NUMBER) {
672
 
      new_node->lid = POS::number_id();
673
 
      new_node->rid = POS::number_id();
 
651
      new_node->lid = POSMatcher::GetNumberId();
 
652
      new_node->rid = POSMatcher::GetNumberId();
674
653
    } else {
675
 
      new_node->lid = POS::unknown_id();
676
 
      new_node->rid = POS::unknown_id();
 
654
      new_node->lid = POSMatcher::GetUnknownId();
 
655
      new_node->rid = POSMatcher::GetUnknownId();
677
656
    }
678
657
    new_node->wcost = kMaxCost / 2;
679
658
    new_node->value.assign(begin, mblen);
688
667
 
689
668
bool ImmutableConverterImpl::Viterbi(Segments *segments,
690
669
                                     const vector<uint16> &group) const {
691
 
  ConverterData *data = segments->converter_data();
692
 
  Node **begin_nodes_list = data->begin_nodes_list();
693
 
  Node **end_nodes_list = data->end_nodes_list();
 
670
  Lattice *lattice = segments->lattice();
 
671
  DCHECK(lattice);
694
672
 
695
 
  const string &key = segments->converter_data()->key();
 
673
  const string &key = lattice->key();
696
674
 
697
675
  for (size_t pos = 0; pos <= key.size(); ++pos) {
698
 
    for (Node *rnode = begin_nodes_list[pos];
 
676
    for (Node *rnode = lattice->begin_nodes(pos);
699
677
         rnode != NULL; rnode = rnode->bnext) {
700
 
      int bestCost = INT_MAX;
701
 
      Node* bestNode = NULL;
702
 
      for (Node *lnode = end_nodes_list[pos];
 
678
      int best_cost = INT_MAX;
 
679
      Node* best_node = NULL;
 
680
      for (Node *lnode = lattice->end_nodes(pos);
703
681
           lnode != NULL; lnode = lnode->enext) {
704
682
        int cost = 0;
705
683
        switch (GetConnectionType(lnode, rnode, group, segments)) {
730
708
            break;
731
709
        }
732
710
 
733
 
        if (cost < bestCost) {
734
 
          bestNode = lnode;
735
 
          bestCost = cost;
 
711
        if (cost < best_cost) {
 
712
          best_node = lnode;
 
713
          best_cost = cost;
736
714
        }
737
715
      }
738
 
      rnode->prev = bestNode;
739
 
      rnode->cost = bestCost;
 
716
      rnode->prev = best_node;
 
717
      rnode->cost = best_cost;
740
718
    }
741
719
  }
742
720
 
743
721
  // we may have multiple EOS nodes
744
 
  {
745
 
    Node *eos_node = segments->eos_node();
746
 
    for (Node *node = segments->eos_node();
747
 
         node != NULL; node = node->bnext) {
748
 
      // find the best eos_node having the smallest cost
749
 
      if (node->cost < eos_node->cost) {
750
 
        eos_node = node;
751
 
      }
 
722
  Node *eos_node = lattice->eos_nodes();
 
723
  for (Node *node = lattice->eos_nodes();
 
724
       node != NULL; node = node->bnext) {
 
725
    // find the best eos_node having the smallest cost
 
726
    if (node->cost < eos_node->cost) {
 
727
      eos_node = node;
752
728
    }
753
 
    // overwrite eos_node
754
 
    data->set_eos_node(eos_node);
755
729
  }
756
730
 
757
 
  Node *node = segments->eos_node();
 
731
  Node *node = eos_node;
758
732
  Node *prev = NULL;
759
733
 
760
734
  while (node->prev != NULL) {
763
737
    node = prev;
764
738
  }
765
739
 
766
 
  if (segments->bos_node() != prev) {
 
740
  if (lattice->bos_nodes() != prev) {
767
741
    LOG(WARNING) << "cannot make lattice";
768
742
    return false;
769
743
  }
777
751
  // when after ResizeSegment lattice is already made.
778
752
  NormalizeHistorySegments(segments);
779
753
 
780
 
  if (segments->has_lattice() && !segments->has_resized()) {
 
754
  Lattice *lattice = segments->lattice();
 
755
  DCHECK(lattice);
 
756
 
 
757
  if (lattice->has_lattice() && !segments->has_resized()) {
781
758
    string key;
782
759
    for (size_t i = 0; i < segments->segments_size(); ++i) {
783
760
      key += segments->segment(i).key();
784
761
    }
785
 
    if (key != segments->converter_data()->key()) {
 
762
    if (key != lattice->key()) {
786
763
      LOG(WARNING) << "inconsistent input key";
787
764
      return false;
788
765
    }
815
792
  }
816
793
 
817
794
  const string key = history_key + conversion_key;
 
795
  lattice->SetKey(key);
818
796
 
819
 
  ConverterData *data = segments->converter_data();
820
 
  KeyCorrector::InputMode mode = KeyCorrector::ROMAN;
821
 
  if (GET_CONFIG(preedit_method) != config::Config::ROMAN) {
822
 
    mode = KeyCorrector::KANA;
 
797
  for (Node *node = lattice->eos_nodes();
 
798
       node != NULL; node = node->bnext) {
 
799
    if (node->lid != 0 || node->rid != 0) {
 
800
      node->wcost = kEOSPenalty;
 
801
    }
823
802
  }
824
 
  data->set_key(key, mode);
825
 
 
826
 
  Node *bosNode = InitBOSNode(data, 0);
827
 
  Node *eosNode = InitEOSNode(data, static_cast<uint16>(key.size()));
828
 
 
829
 
  data->set_bos_node(bosNode);
830
 
  data->set_eos_node(eosNode);
831
 
 
832
 
  Node **end_nodes_list = data->end_nodes_list();
833
 
  Node **begin_nodes_list = data->begin_nodes_list();
834
 
  end_nodes_list[0] = bosNode;
835
 
  begin_nodes_list[key.size()] = eosNode;
836
803
 
837
804
  size_t segments_pos = 0;
838
805
  const char *key_end = key.data() + key.size();
850
817
 
851
818
    // basically, we add a new node as an
852
819
    // empty (BOS/EOS) node
853
 
    Node *rnode = data->NewNode();
 
820
    Node *rnode = lattice->NewNode();
 
821
    CHECK(rnode);
854
822
    rnode->lid = 0;
855
823
    rnode->rid = 0;
856
824
    rnode->wcost = 0;
858
826
    rnode->key = seg.key();
859
827
    rnode->node_type = Node::HIS_NODE;
860
828
    rnode->bnext = NULL;
861
 
    InsertNodes(segments_pos, rnode, data);
 
829
    lattice->Insert(segments_pos, rnode);
862
830
 
863
831
    // For the last history segment,  we also insert a new node having
864
832
    // a rid as a contextual information. Viterbi algorithm will find the
868
836
    // We changed it from 2000 to 500 after bigram.
869
837
    const int kContextNodePenalty = 500;
870
838
    if (s + 1 == history_segments_size) {
871
 
      Node *rnode2 = data->NewNode();
 
839
      Node *rnode2 = lattice->NewNode();
 
840
      CHECK(rnode2);
872
841
      rnode2->lid = 0;
873
842
      rnode2->rid = c.rid;
874
843
      rnode2->wcost = kContextNodePenalty;
876
845
      rnode2->key = seg.key();
877
846
      rnode2->node_type = Node::HIS_NODE;
878
847
      rnode2->bnext = NULL;
879
 
      InsertNodes(segments_pos, rnode2, data);
 
848
      lattice->Insert(segments_pos, rnode2);
880
849
    }
881
850
 
882
851
    // Dictionary lookup for the candidates which are
887
856
    // Here, try to find "おいかわたくや(及川卓也)" from dictionary
888
857
    // and insert "卓也" as a new word node with a modified cost
889
858
    if (s + 1 == history_segments_size) {
890
 
      const Node *node = Lookup(key_begin + segments_pos, key_end, data);
 
859
      const Node *node = Lookup(key_begin + segments_pos, key_end,
 
860
                                lattice);
891
861
      for (const Node *compound_node = node; compound_node != NULL;
892
862
           compound_node = compound_node->bnext) {
893
863
        // No overlapps
899
869
        }
900
870
 
901
871
        // make new virtual node
902
 
        Node *new_node = data->NewNode();
 
872
        Node *new_node = lattice->NewNode();
903
873
        CHECK(new_node);
904
874
 
905
875
        // get the suffix part ("たくや/卓也")
949
919
        new_node->constrained_prev = rnode;
950
920
 
951
921
        // Added as new node
952
 
        InsertNodes(segments_pos + rnode->key.size(), new_node, data);
 
922
        lattice->Insert(segments_pos + rnode->key.size(), new_node);
953
923
 
954
924
        VLOG(2) << "Added: " << new_node->key << " " << new_node->value;
955
925
      }
960
930
    last_rid = rnode->rid;
961
931
  }
962
932
 
963
 
  if (end_nodes_list[history_key.size()] == NULL) {
 
933
  if (lattice->end_nodes(history_key.size()) == NULL) {
964
934
    LOG(WARNING) << "cannot build lattice from input";
965
935
    return false;
966
936
  }
967
937
 
968
 
  // Dictionary Lookup for conversion segment
969
 
  const KeyCorrector &key_corrector = data->key_corrector();
 
938
  // Do not use KeyCorrector if user changes the boundary.
 
939
  // http://b/issue?id=2804996
 
940
  scoped_ptr<KeyCorrector> key_corrector;
 
941
  if (!segments->has_resized()) {
 
942
    KeyCorrector::InputMode mode = KeyCorrector::ROMAN;
 
943
    if (GET_CONFIG(preedit_method) != config::Config::ROMAN) {
 
944
      mode = KeyCorrector::KANA;
 
945
    }
 
946
    key_corrector.reset(new KeyCorrector(key, mode));
 
947
  }
970
948
 
971
949
  for (size_t pos = history_key.size(); pos < key.size(); ++pos) {
972
 
    if (end_nodes_list[pos] != NULL) {
973
 
      Node *rnode = Lookup(key_begin + pos, key_end, data);
 
950
    if (lattice->end_nodes(pos) != NULL) {
 
951
      Node *rnode = Lookup(key_begin + pos, key_end, lattice);
974
952
      CHECK(rnode != NULL);
975
 
      InsertNodes(pos, rnode, data);
 
953
      lattice->Insert(pos, rnode);
976
954
      // Insert corrected nodes like みんあ -> みんな
977
955
      InsertCorrectedNodes(pos, key,
978
 
                           key_corrector,
979
 
                           dictionary_.get(), data);
 
956
                           key_corrector.get(),
 
957
                           dictionary_, lattice);
980
958
    }
981
959
  }
982
960
 
983
 
  if (end_nodes_list[key.size()] == NULL) {
 
961
  if (lattice->end_nodes(key.size()) == NULL) {
984
962
    LOG(WARNING) << "cannot build lattice from input";
985
963
    return false;
986
964
  }
987
965
 
988
966
  // resegments
989
967
  for (size_t pos = history_key.size(); pos < key.size(); ++pos) {
990
 
    Resegment(pos, data);
 
968
    Resegment(pos, lattice);
991
969
  }
992
970
 
993
971
  return true;
994
972
}
995
973
 
996
974
bool ImmutableConverterImpl::ModifyLattice(Segments *segments) const {
997
 
  ConverterData *data = segments->converter_data();
998
 
  Node **begin_nodes_list = data->begin_nodes_list();
999
 
  const string &key = data->key();
 
975
  Lattice *lattice = segments->lattice();
 
976
  DCHECK(lattice);
 
977
 
 
978
  const string &key = lattice->key();
1000
979
 
1001
980
  // disable all CON_NODE
1002
981
  for (size_t pos = 0; pos <= key.size(); ++pos) {
1003
 
    for (Node *node = begin_nodes_list[pos];
 
982
    for (Node *node = lattice->begin_nodes(pos);
1004
983
         node != NULL; node = node->bnext) {
1005
984
      node->cost = 0;  // reset cost
1006
985
      if (node->node_type == Node::CON_NODE) {
1015
994
    const Segment &seg = segments->segment(s);
1016
995
    if (seg.segment_type() == Segment::FIXED_VALUE) {
1017
996
      const Segment::Candidate &c = seg.candidate(0);
1018
 
      Node *rnode = data->NewNode();
 
997
      Node *rnode = lattice->NewNode();
 
998
      CHECK(rnode);
1019
999
      rnode->lid       = c.lid;
1020
1000
      rnode->rid       = c.rid;
1021
1001
      rnode->wcost     = -kMaxCost;
1024
1004
      rnode->node_type = Node::CON_NODE;
1025
1005
      rnode->con_segment = &seg;
1026
1006
      rnode->bnext     = NULL;
1027
 
      InsertNodes(segments_pos, rnode, data);
 
1007
      lattice->Insert(segments_pos, rnode);
1028
1008
    }
1029
1009
    segments_pos += seg.key().size();
1030
1010
  }
1034
1014
 
1035
1015
bool ImmutableConverterImpl::MakeSegments(Segments *segments,
1036
1016
                                          const vector<uint16> &group) const {
 
1017
  Lattice *lattice = segments->lattice();
 
1018
  DCHECK(lattice);
 
1019
 
1037
1020
  // skip HIS_NODE(s)
1038
 
  Node *prev = segments->bos_node();
1039
 
  for (Node *node = segments->bos_node()->next;
 
1021
  Node *prev = lattice->bos_nodes();
 
1022
  for (Node *node = lattice->bos_nodes()->next;
1040
1023
       node->next != NULL && node->node_type == Node::HIS_NODE;
1041
1024
       node = node->next) {
1042
1025
    prev = node;
1043
1026
  }
1044
1027
 
 
1028
  const size_t history_segments_size = segments->history_segments_size();
 
1029
  const size_t old_segments_size = segments->segments_size();
 
1030
 
1045
1031
  string key;
1046
 
  const size_t history_segments_size = segments->history_segments_size();
1047
 
  const size_t old_segments_size = segments->segments_size();
1048
 
 
1049
1032
  for (Node *node = prev->next; node->next != NULL; node = node->next) {
1050
1033
    key += node->key;
1051
1034
    const Segment &old_seg = segments->segment(group[node->begin_pos]);
1053
1036
    if (node->next->node_type != Node::EOS_NODE &&
1054
1037
        old_seg.segment_type() == Segment::FIXED_BOUNDARY &&
1055
1038
        group[node->begin_pos] == group[node->next->begin_pos]) {
1056
 
       // do nothing
 
1039
      // do nothing
1057
1040
      // Condition 2: prev->next is a boundary. Very strong constraint
1058
1041
    } else if (node->node_type == Node::CON_NODE ||
1059
1042
               (node->next->node_type != Node::EOS_NODE &&
1060
1043
                group[node->begin_pos] != group[node->next->begin_pos]) ||
1061
1044
               Segmenter::IsBoundary(node, node->next)) {
1062
1045
      Segment *segment = segments->add_segment();
 
1046
      DCHECK(segment);
1063
1047
      NBestGenerator *nbest = segment->nbest_generator();
1064
 
      nbest->Init(prev, node->next, connector_.get(),
1065
 
                  segments->converter_data());
 
1048
      DCHECK(nbest);
 
1049
      nbest->Init(prev, node->next, segments->lattice());
1066
1050
      segment->set_key(key);
1067
1051
      segment->Expand(max(static_cast<size_t>(1), old_seg.candidates_size()));
1068
1052
      if (segment->candidates_size() == 0) {
1135
1119
  return true;
1136
1120
}
1137
1121
 
1138
 
ImmutableConverter* ImmutableConverter::Create() {
1139
 
  return new ImmutableConverterImpl;
 
1122
ImmutableConverterInterface *g_immutable_converter = NULL;
 
1123
 
 
1124
}   // anonymous namespace
 
1125
 
 
1126
ImmutableConverterInterface *
 
1127
ImmutableConverterFactory::GetImmutableConverter() {
 
1128
  if (g_immutable_converter == NULL) {
 
1129
    return Singleton<ImmutableConverterImpl>::get();
 
1130
  } else {
 
1131
    return g_immutable_converter;
 
1132
  }
 
1133
}
 
1134
 
 
1135
void ImmutableConverterFactory::SetImmutableConverter(
 
1136
    ImmutableConverterInterface *immutable_converter) {
 
1137
  g_immutable_converter = immutable_converter;
1140
1138
}
1141
1139
}  // namespace mozc