blob: c340c6c1a4843f7ab2eb98fcc2057728f63fc2cb [file] [log] [blame]
satok30088252010-12-01 21:22:15 +09001/*
2**
3** Copyright 2010, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9** http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
satok18c28f42010-12-02 18:11:54 +090018#include <string.h>
19
satoke808e432010-12-02 14:53:24 +090020#define LOG_TAG "LatinIME: bigram_dictionary.cpp"
21
satok30088252010-12-01 21:22:15 +090022#include "bigram_dictionary.h"
satok18c28f42010-12-02 18:11:54 +090023#include "dictionary.h"
Jean Chalard588e2f22011-07-25 14:03:19 +090024#include "binary_format.h"
satok30088252010-12-01 21:22:15 +090025
26namespace latinime {
27
satok18c28f42010-12-02 18:11:54 +090028BigramDictionary::BigramDictionary(const unsigned char *dict, int maxWordLength,
29 int maxAlternatives, const bool isLatestDictVersion, const bool hasBigram,
30 Dictionary *parentDictionary)
Jean Chalard588e2f22011-07-25 14:03:19 +090031 : DICT(dict + NEW_DICTIONARY_HEADER_SIZE), MAX_WORD_LENGTH(maxWordLength),
satok18c28f42010-12-02 18:11:54 +090032 MAX_ALTERNATIVES(maxAlternatives), IS_LATEST_DICT_VERSION(isLatestDictVersion),
33 HAS_BIGRAM(hasBigram), mParentDictionary(parentDictionary) {
Ken Wakasade3070a2011-03-19 09:16:42 +090034 if (DEBUG_DICT) {
35 LOGI("BigramDictionary - constructor");
36 LOGI("Has Bigram : %d", hasBigram);
37 }
satok30088252010-12-01 21:22:15 +090038}
39
satok18c28f42010-12-02 18:11:54 +090040BigramDictionary::~BigramDictionary() {
satok30088252010-12-01 21:22:15 +090041}
satok18c28f42010-12-02 18:11:54 +090042
43bool BigramDictionary::addWordBigram(unsigned short *word, int length, int frequency) {
44 word[length] = 0;
45 if (DEBUG_DICT) {
Doug Kwance9efbf2011-07-07 22:53:50 -070046#ifdef FLAG_DBG
satok18c28f42010-12-02 18:11:54 +090047 char s[length + 1];
48 for (int i = 0; i <= length; i++) s[i] = word[i];
Ken Wakasae90b3332011-01-07 15:01:51 +090049 LOGI("Bigram: Found word = %s, freq = %d :", s, frequency);
satok787945b2011-07-14 08:32:57 +090050#endif
satok18c28f42010-12-02 18:11:54 +090051 }
52
53 // Find the right insertion point
54 int insertAt = 0;
55 while (insertAt < mMaxBigrams) {
56 if (frequency > mBigramFreq[insertAt] || (mBigramFreq[insertAt] == frequency
57 && length < Dictionary::wideStrLen(mBigramChars + insertAt * MAX_WORD_LENGTH))) {
58 break;
59 }
60 insertAt++;
61 }
Ken Wakasade3070a2011-03-19 09:16:42 +090062 if (DEBUG_DICT) {
63 LOGI("Bigram: InsertAt -> %d maxBigrams: %d", insertAt, mMaxBigrams);
64 }
satok18c28f42010-12-02 18:11:54 +090065 if (insertAt < mMaxBigrams) {
66 memmove((char*) mBigramFreq + (insertAt + 1) * sizeof(mBigramFreq[0]),
67 (char*) mBigramFreq + insertAt * sizeof(mBigramFreq[0]),
68 (mMaxBigrams - insertAt - 1) * sizeof(mBigramFreq[0]));
69 mBigramFreq[insertAt] = frequency;
70 memmove((char*) mBigramChars + (insertAt + 1) * MAX_WORD_LENGTH * sizeof(short),
71 (char*) mBigramChars + (insertAt ) * MAX_WORD_LENGTH * sizeof(short),
72 (mMaxBigrams - insertAt - 1) * sizeof(short) * MAX_WORD_LENGTH);
73 unsigned short *dest = mBigramChars + (insertAt ) * MAX_WORD_LENGTH;
74 while (length--) {
75 *dest++ = *word++;
76 }
77 *dest = 0; // NULL terminate
Ken Wakasade3070a2011-03-19 09:16:42 +090078 if (DEBUG_DICT) {
79 LOGI("Bigram: Added word at %d", insertAt);
80 }
satok18c28f42010-12-02 18:11:54 +090081 return true;
82 }
83 return false;
84}
85
Jean Chalard588e2f22011-07-25 14:03:19 +090086/* Parameters :
87 * prevWord: the word before, the one for which we need to look up bigrams.
88 * prevWordLength: its length.
89 * codes: what user typed, in the same format as for UnigramDictionary::getSuggestions.
90 * codesSize: the size of the codes array.
91 * bigramChars: an array for output, at the same format as outwords for getSuggestions.
92 * bigramFreq: an array to output frequencies.
93 * maxWordLength: the maximum size of a word.
94 * maxBigrams: the maximum number of bigrams fitting in the bigramChars array.
95 * maxAlteratives: unused.
96 * This method returns the number of bigrams this word has, for backward compatibility.
97 * Note: this is not the number of bigrams output in the array, which is the number of
98 * bigrams this word has WHOSE first letter also matches the letter the user typed.
99 * TODO: this may not be a sensible thing to do. It makes sense when the bigrams are
100 * used to match the first letter of the second word, but once the user has typed more
101 * and the bigrams are used to boost unigram result scores, it makes little sense to
102 * reduce their scope to the ones that match the first letter.
103 */
satok18c28f42010-12-02 18:11:54 +0900104int BigramDictionary::getBigrams(unsigned short *prevWord, int prevWordLength, int *codes,
105 int codesSize, unsigned short *bigramChars, int *bigramFreq, int maxWordLength,
106 int maxBigrams, int maxAlternatives) {
Jean Chalard588e2f22011-07-25 14:03:19 +0900107 // TODO: remove unused arguments, and refrain from storing stuff in members of this class
108 // TODO: have "in" arguments before "out" ones, and make out args explicit in the name
satok18c28f42010-12-02 18:11:54 +0900109 mBigramFreq = bigramFreq;
110 mBigramChars = bigramChars;
111 mInputCodes = codes;
satok18c28f42010-12-02 18:11:54 +0900112 mMaxBigrams = maxBigrams;
113
Jean Chalard588e2f22011-07-25 14:03:19 +0900114 const uint8_t* const root = DICT;
115 int pos = BinaryFormat::getTerminalPosition(root, prevWord, prevWordLength);
satok18c28f42010-12-02 18:11:54 +0900116
Jean Chalard588e2f22011-07-25 14:03:19 +0900117 if (NOT_VALID_WORD == pos) return 0;
118 const int flags = BinaryFormat::getFlagsAndForwardPointer(root, &pos);
119 if (0 == (flags & UnigramDictionary::FLAG_HAS_BIGRAMS)) return 0;
120 if (0 == (flags & UnigramDictionary::FLAG_HAS_MULTIPLE_CHARS)) {
121 BinaryFormat::getCharCodeAndForwardPointer(root, &pos);
122 } else {
123 pos = BinaryFormat::skipOtherCharacters(root, pos);
satok18c28f42010-12-02 18:11:54 +0900124 }
Jean Chalard588e2f22011-07-25 14:03:19 +0900125 pos = BinaryFormat::skipChildrenPosition(flags, pos);
126 pos = BinaryFormat::skipFrequency(flags, pos);
127 int bigramFlags;
128 int bigramCount = 0;
129 do {
130 bigramFlags = BinaryFormat::getFlagsAndForwardPointer(root, &pos);
131 uint16_t bigramBuffer[MAX_WORD_LENGTH];
132 const int bigramPos = BinaryFormat::getAttributeAddressAndForwardPointer(root, bigramFlags,
133 &pos);
134 const int length = BinaryFormat::getWordAtAddress(root, bigramPos, MAX_WORD_LENGTH,
135 bigramBuffer);
satok18c28f42010-12-02 18:11:54 +0900136
Jean Chalard588e2f22011-07-25 14:03:19 +0900137 if (checkFirstCharacter(bigramBuffer)) {
138 const int frequency = UnigramDictionary::MASK_ATTRIBUTE_FREQUENCY & bigramFlags;
139 addWordBigram(bigramBuffer, length, frequency);
satok18c28f42010-12-02 18:11:54 +0900140 }
Jean Chalard588e2f22011-07-25 14:03:19 +0900141 ++bigramCount;
142 } while (0 != (UnigramDictionary::FLAG_ATTRIBUTE_HAS_NEXT & bigramFlags));
143 return bigramCount;
satok18c28f42010-12-02 18:11:54 +0900144}
145
146bool BigramDictionary::checkFirstCharacter(unsigned short *word) {
147 // Checks whether this word starts with same character or neighboring characters of
148 // what user typed.
149
150 int *inputCodes = mInputCodes;
151 int maxAlt = MAX_ALTERNATIVES;
152 while (maxAlt > 0) {
153 if ((unsigned int) *inputCodes == (unsigned int) *word) {
154 return true;
155 }
156 inputCodes++;
157 maxAlt--;
158 }
159 return false;
160}
161
satok30088252010-12-01 21:22:15 +0900162// TODO: Move functions related to bigram to here
163} // namespace latinime