blob: 07031086c94f44454ebc01ce3f7dd8e77186ece8 [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"
Jean Chalard588e2f22011-07-25 14:03:19 +090023#include "binary_format.h"
Jean Chalard49ba1352012-05-07 20:14:00 +090024#include "bloom_filter.h"
25#include "dictionary.h"
satok30088252010-12-01 21:22:15 +090026
27namespace latinime {
28
satok18c28f42010-12-02 18:11:54 +090029BigramDictionary::BigramDictionary(const unsigned char *dict, int maxWordLength,
satok18c28f42010-12-02 18:11:54 +090030 Dictionary *parentDictionary)
Jean Chalard5b0761e2012-04-06 17:52:18 +090031 : DICT(dict), MAX_WORD_LENGTH(maxWordLength), mParentDictionary(parentDictionary) {
Ken Wakasade3070a2011-03-19 09:16:42 +090032 if (DEBUG_DICT) {
satok9fb6f472012-01-13 18:01:22 +090033 AKLOGI("BigramDictionary - constructor");
Ken Wakasade3070a2011-03-19 09:16:42 +090034 }
satok30088252010-12-01 21:22:15 +090035}
36
satok18c28f42010-12-02 18:11:54 +090037BigramDictionary::~BigramDictionary() {
satok30088252010-12-01 21:22:15 +090038}
satok18c28f42010-12-02 18:11:54 +090039
40bool BigramDictionary::addWordBigram(unsigned short *word, int length, int frequency) {
41 word[length] = 0;
42 if (DEBUG_DICT) {
Doug Kwance9efbf2011-07-07 22:53:50 -070043#ifdef FLAG_DBG
satok18c28f42010-12-02 18:11:54 +090044 char s[length + 1];
45 for (int i = 0; i <= length; i++) s[i] = word[i];
satok9fb6f472012-01-13 18:01:22 +090046 AKLOGI("Bigram: Found word = %s, freq = %d :", s, frequency);
satok787945b2011-07-14 08:32:57 +090047#endif
satok18c28f42010-12-02 18:11:54 +090048 }
49
50 // Find the right insertion point
51 int insertAt = 0;
52 while (insertAt < mMaxBigrams) {
53 if (frequency > mBigramFreq[insertAt] || (mBigramFreq[insertAt] == frequency
54 && length < Dictionary::wideStrLen(mBigramChars + insertAt * MAX_WORD_LENGTH))) {
55 break;
56 }
57 insertAt++;
58 }
Ken Wakasade3070a2011-03-19 09:16:42 +090059 if (DEBUG_DICT) {
satok9fb6f472012-01-13 18:01:22 +090060 AKLOGI("Bigram: InsertAt -> %d maxBigrams: %d", insertAt, mMaxBigrams);
Ken Wakasade3070a2011-03-19 09:16:42 +090061 }
satok18c28f42010-12-02 18:11:54 +090062 if (insertAt < mMaxBigrams) {
63 memmove((char*) mBigramFreq + (insertAt + 1) * sizeof(mBigramFreq[0]),
64 (char*) mBigramFreq + insertAt * sizeof(mBigramFreq[0]),
65 (mMaxBigrams - insertAt - 1) * sizeof(mBigramFreq[0]));
66 mBigramFreq[insertAt] = frequency;
67 memmove((char*) mBigramChars + (insertAt + 1) * MAX_WORD_LENGTH * sizeof(short),
68 (char*) mBigramChars + (insertAt ) * MAX_WORD_LENGTH * sizeof(short),
69 (mMaxBigrams - insertAt - 1) * sizeof(short) * MAX_WORD_LENGTH);
70 unsigned short *dest = mBigramChars + (insertAt ) * MAX_WORD_LENGTH;
71 while (length--) {
72 *dest++ = *word++;
73 }
74 *dest = 0; // NULL terminate
Ken Wakasade3070a2011-03-19 09:16:42 +090075 if (DEBUG_DICT) {
satok9fb6f472012-01-13 18:01:22 +090076 AKLOGI("Bigram: Added word at %d", insertAt);
Ken Wakasade3070a2011-03-19 09:16:42 +090077 }
satok18c28f42010-12-02 18:11:54 +090078 return true;
79 }
80 return false;
81}
82
Jean Chalard588e2f22011-07-25 14:03:19 +090083/* Parameters :
84 * prevWord: the word before, the one for which we need to look up bigrams.
85 * prevWordLength: its length.
86 * codes: what user typed, in the same format as for UnigramDictionary::getSuggestions.
87 * codesSize: the size of the codes array.
88 * bigramChars: an array for output, at the same format as outwords for getSuggestions.
89 * bigramFreq: an array to output frequencies.
90 * maxWordLength: the maximum size of a word.
91 * maxBigrams: the maximum number of bigrams fitting in the bigramChars array.
Jean Chalard588e2f22011-07-25 14:03:19 +090092 * This method returns the number of bigrams this word has, for backward compatibility.
93 * Note: this is not the number of bigrams output in the array, which is the number of
94 * bigrams this word has WHOSE first letter also matches the letter the user typed.
95 * TODO: this may not be a sensible thing to do. It makes sense when the bigrams are
96 * used to match the first letter of the second word, but once the user has typed more
97 * and the bigrams are used to boost unigram result scores, it makes little sense to
98 * reduce their scope to the ones that match the first letter.
99 */
Jean Chalard522a04e2012-04-23 15:37:07 +0900100int BigramDictionary::getBigrams(const int32_t *prevWord, int prevWordLength, int *codes,
satok18c28f42010-12-02 18:11:54 +0900101 int codesSize, unsigned short *bigramChars, int *bigramFreq, int maxWordLength,
satok6ba8de22012-03-28 18:21:04 +0900102 int maxBigrams) {
Jean Chalard588e2f22011-07-25 14:03:19 +0900103 // TODO: remove unused arguments, and refrain from storing stuff in members of this class
104 // TODO: have "in" arguments before "out" ones, and make out args explicit in the name
satok18c28f42010-12-02 18:11:54 +0900105 mBigramFreq = bigramFreq;
106 mBigramChars = bigramChars;
107 mInputCodes = codes;
satok18c28f42010-12-02 18:11:54 +0900108 mMaxBigrams = maxBigrams;
109
Jean Chalard588e2f22011-07-25 14:03:19 +0900110 const uint8_t* const root = DICT;
Jean Chalard351864b2012-04-24 18:06:51 +0900111 int pos = getBigramListPositionForWord(prevWord, prevWordLength);
112 // getBigramListPositionForWord returns 0 if this word isn't in the dictionary or has no bigrams
Jean Chalardee396df2012-04-17 16:02:35 +0900113 if (0 == pos) return 0;
Jean Chalard588e2f22011-07-25 14:03:19 +0900114 int bigramFlags;
115 int bigramCount = 0;
116 do {
117 bigramFlags = BinaryFormat::getFlagsAndForwardPointer(root, &pos);
118 uint16_t bigramBuffer[MAX_WORD_LENGTH];
119 const int bigramPos = BinaryFormat::getAttributeAddressAndForwardPointer(root, bigramFlags,
120 &pos);
121 const int length = BinaryFormat::getWordAtAddress(root, bigramPos, MAX_WORD_LENGTH,
122 bigramBuffer);
satok18c28f42010-12-02 18:11:54 +0900123
Jean Chalardad290d62012-02-15 19:22:26 -0800124 // codesSize == 0 means we are trying to find bigram predictions.
125 if (codesSize < 1 || checkFirstCharacter(bigramBuffer)) {
Jean Chalard588e2f22011-07-25 14:03:19 +0900126 const int frequency = UnigramDictionary::MASK_ATTRIBUTE_FREQUENCY & bigramFlags;
Jean Chalard9715cc42012-03-21 15:26:45 +0900127 if (addWordBigram(bigramBuffer, length, frequency)) {
128 ++bigramCount;
129 }
satok18c28f42010-12-02 18:11:54 +0900130 }
Jean Chalard588e2f22011-07-25 14:03:19 +0900131 } while (0 != (UnigramDictionary::FLAG_ATTRIBUTE_HAS_NEXT & bigramFlags));
132 return bigramCount;
satok18c28f42010-12-02 18:11:54 +0900133}
134
Jean Chalardee396df2012-04-17 16:02:35 +0900135// Returns a pointer to the start of the bigram list.
136// If the word is not found or has no bigrams, this function returns 0.
Jean Chalard351864b2012-04-24 18:06:51 +0900137int BigramDictionary::getBigramListPositionForWord(const int32_t *prevWord,
138 const int prevWordLength) {
Jean Chalard1ff8dc42012-05-02 16:00:24 +0900139 if (0 >= prevWordLength) return 0;
Jean Chalard351864b2012-04-24 18:06:51 +0900140 const uint8_t* const root = DICT;
Jean Chalard9c2a96a2012-04-17 11:38:44 +0900141 int pos = BinaryFormat::getTerminalPosition(root, prevWord, prevWordLength);
142
143 if (NOT_VALID_WORD == pos) return 0;
144 const int flags = BinaryFormat::getFlagsAndForwardPointer(root, &pos);
145 if (0 == (flags & UnigramDictionary::FLAG_HAS_BIGRAMS)) return 0;
146 if (0 == (flags & UnigramDictionary::FLAG_HAS_MULTIPLE_CHARS)) {
147 BinaryFormat::getCharCodeAndForwardPointer(root, &pos);
148 } else {
149 pos = BinaryFormat::skipOtherCharacters(root, pos);
150 }
151 pos = BinaryFormat::skipChildrenPosition(flags, pos);
152 pos = BinaryFormat::skipFrequency(flags, pos);
153 pos = BinaryFormat::skipShortcuts(root, flags, pos);
154 return pos;
155}
156
Jean Chalardf1634c82012-05-02 19:05:27 +0900157void BigramDictionary::fillBigramAddressToFrequencyMapAndFilter(const int32_t *prevWord,
158 const int prevWordLength, std::map<int, int> *map, uint8_t *filter) {
159 memset(filter, 0, BIGRAM_FILTER_BYTE_SIZE);
Jean Chalard1ff8dc42012-05-02 16:00:24 +0900160 const uint8_t* const root = DICT;
161 int pos = getBigramListPositionForWord(prevWord, prevWordLength);
162 if (0 == pos) return;
163
164 int bigramFlags;
165 do {
166 bigramFlags = BinaryFormat::getFlagsAndForwardPointer(root, &pos);
167 const int frequency = UnigramDictionary::MASK_ATTRIBUTE_FREQUENCY & bigramFlags;
168 const int bigramPos = BinaryFormat::getAttributeAddressAndForwardPointer(root, bigramFlags,
169 &pos);
170 (*map)[bigramPos] = frequency;
Jean Chalardf1634c82012-05-02 19:05:27 +0900171 setInFilter(filter, bigramPos);
Jean Chalard1ff8dc42012-05-02 16:00:24 +0900172 } while (0 != (UnigramDictionary::FLAG_ATTRIBUTE_HAS_NEXT & bigramFlags));
173}
174
satok18c28f42010-12-02 18:11:54 +0900175bool BigramDictionary::checkFirstCharacter(unsigned short *word) {
176 // Checks whether this word starts with same character or neighboring characters of
177 // what user typed.
178
179 int *inputCodes = mInputCodes;
180 int maxAlt = MAX_ALTERNATIVES;
Tom Ouyangaeda8a72012-03-24 15:31:27 +0900181 const unsigned short firstBaseChar = toBaseLowerCase(*word);
satok18c28f42010-12-02 18:11:54 +0900182 while (maxAlt > 0) {
Tom Ouyangaeda8a72012-03-24 15:31:27 +0900183 if (toBaseLowerCase(*inputCodes) == firstBaseChar) {
satok18c28f42010-12-02 18:11:54 +0900184 return true;
185 }
186 inputCodes++;
187 maxAlt--;
188 }
189 return false;
190}
191
satok30088252010-12-01 21:22:15 +0900192// TODO: Move functions related to bigram to here
193} // namespace latinime