NgramContext.java revision 86f36003fd4397143bd37938dda029e5707634af
183c40a2301a0b5a42a75eecada48e7887a7c940eKeisuke Kuroyanagi/*
283c40a2301a0b5a42a75eecada48e7887a7c940eKeisuke Kuroyanagi * Copyright (C) 2014 The Android Open Source Project
383c40a2301a0b5a42a75eecada48e7887a7c940eKeisuke Kuroyanagi *
483c40a2301a0b5a42a75eecada48e7887a7c940eKeisuke Kuroyanagi * Licensed under the Apache License, Version 2.0 (the "License");
583c40a2301a0b5a42a75eecada48e7887a7c940eKeisuke Kuroyanagi * you may not use this file except in compliance with the License.
683c40a2301a0b5a42a75eecada48e7887a7c940eKeisuke Kuroyanagi * You may obtain a copy of the License at
783c40a2301a0b5a42a75eecada48e7887a7c940eKeisuke Kuroyanagi *
883c40a2301a0b5a42a75eecada48e7887a7c940eKeisuke Kuroyanagi *      http://www.apache.org/licenses/LICENSE-2.0
983c40a2301a0b5a42a75eecada48e7887a7c940eKeisuke Kuroyanagi *
1083c40a2301a0b5a42a75eecada48e7887a7c940eKeisuke Kuroyanagi * Unless required by applicable law or agreed to in writing, software
1183c40a2301a0b5a42a75eecada48e7887a7c940eKeisuke Kuroyanagi * distributed under the License is distributed on an "AS IS" BASIS,
1283c40a2301a0b5a42a75eecada48e7887a7c940eKeisuke Kuroyanagi * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1383c40a2301a0b5a42a75eecada48e7887a7c940eKeisuke Kuroyanagi * See the License for the specific language governing permissions and
1483c40a2301a0b5a42a75eecada48e7887a7c940eKeisuke Kuroyanagi * limitations under the License.
1583c40a2301a0b5a42a75eecada48e7887a7c940eKeisuke Kuroyanagi */
1683c40a2301a0b5a42a75eecada48e7887a7c940eKeisuke Kuroyanagi
1783c40a2301a0b5a42a75eecada48e7887a7c940eKeisuke Kuroyanagipackage com.android.inputmethod.latin;
1883c40a2301a0b5a42a75eecada48e7887a7c940eKeisuke Kuroyanagi
1986f36003fd4397143bd37938dda029e5707634afYohei Yukawaimport android.text.TextUtils;
20e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi
21e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagiimport com.android.inputmethod.latin.utils.StringUtils;
22e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi
2386f36003fd4397143bd37938dda029e5707634afYohei Yukawaimport java.util.Arrays;
2486f36003fd4397143bd37938dda029e5707634afYohei Yukawa
25a790c5b68324da41428aeb68594d43ca5632f66dKeisuke Kuroyanagi/**
26a790c5b68324da41428aeb68594d43ca5632f66dKeisuke Kuroyanagi * Class to represent information of previous words. This class is used to add n-gram entries
27a790c5b68324da41428aeb68594d43ca5632f66dKeisuke Kuroyanagi * into binary dictionaries, to get predictions, and to get suggestions.
28a790c5b68324da41428aeb68594d43ca5632f66dKeisuke Kuroyanagi */
2983c40a2301a0b5a42a75eecada48e7887a7c940eKeisuke Kuroyanagipublic class PrevWordsInfo {
30e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi    public static final PrevWordsInfo EMPTY_PREV_WORDS_INFO =
31e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi            new PrevWordsInfo(WordInfo.EMPTY_WORD_INFO);
321c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi    public static final PrevWordsInfo BEGINNING_OF_SENTENCE =
331c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi            new PrevWordsInfo(WordInfo.BEGINNING_OF_SENTENCE);
341adca93381d261a6070be2721dbf8b8abafbfe01Keisuke Kuroyanagi
35e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi    /**
36e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi     * Word information used to represent previous words information.
37e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi     */
38e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi    public static class WordInfo {
39e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi        public static final WordInfo EMPTY_WORD_INFO = new WordInfo(null);
40e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi        public static final WordInfo BEGINNING_OF_SENTENCE = new WordInfo();
41e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi
4286f36003fd4397143bd37938dda029e5707634afYohei Yukawa        // This is an empty char sequence when mIsBeginningOfSentence is true.
4386f36003fd4397143bd37938dda029e5707634afYohei Yukawa        public final CharSequence mWord;
44e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi        // TODO: Have sentence separator.
45e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi        // Whether the current context is beginning of sentence or not. This is true when composing
46e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi        // at the beginning of an input field or composing a word after a sentence separator.
47e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi        public final boolean mIsBeginningOfSentence;
48e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi
49e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi        // Beginning of sentence.
50e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi        public WordInfo() {
51e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi            mWord = "";
52e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi            mIsBeginningOfSentence = true;
53e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi        }
54e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi
5586f36003fd4397143bd37938dda029e5707634afYohei Yukawa        public WordInfo(final CharSequence word) {
56e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi            mWord = word;
57e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi            mIsBeginningOfSentence = false;
58e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi        }
59e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi
60e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi        public boolean isValid() {
61e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi            return mWord != null;
62e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi        }
631c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi
641c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi        @Override
651c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi        public int hashCode() {
661c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi            return Arrays.hashCode(new Object[] { mWord, mIsBeginningOfSentence } );
671c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi        }
681c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi
691c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi        @Override
701c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi        public boolean equals(Object o) {
711c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi            if (this == o) return true;
721c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi            if (!(o instanceof WordInfo)) return false;
731c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi            final WordInfo wordInfo = (WordInfo)o;
741c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi            if (mWord == null || wordInfo.mWord == null) {
751c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi                return mWord == wordInfo.mWord
761c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi                        && mIsBeginningOfSentence == wordInfo.mIsBeginningOfSentence;
771c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi            }
7886f36003fd4397143bd37938dda029e5707634afYohei Yukawa            return TextUtils.equals(mWord, wordInfo.mWord)
791c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi                    && mIsBeginningOfSentence == wordInfo.mIsBeginningOfSentence;
801c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi        }
81e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi    }
8283c40a2301a0b5a42a75eecada48e7887a7c940eKeisuke Kuroyanagi
83e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi    // The words immediately before the considered word. EMPTY_WORD_INFO element means we don't
84e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi    // have any context for that previous word including the "beginning of sentence context" - we
85e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi    // just don't know what to predict using the information. An example of that is after a comma.
86e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi    // For simplicity of implementation, elements may also be EMPTY_WORD_INFO transiently after the
87e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi    // WordComposer was reset and before starting a new composing word, but we should never be
88e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi    // calling getSuggetions* in this situation.
89e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi    public WordInfo[] mPrevWordsInfo = new WordInfo[Constants.MAX_PREV_WORD_COUNT_FOR_N_GRAM];
9017f326b7458c2bde2569e283a96e703755485328Keisuke Kuroyanagi
91e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi    // Construct from the previous word information.
92e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi    public PrevWordsInfo(final WordInfo prevWordInfo) {
93e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi        mPrevWordsInfo[0] = prevWordInfo;
94e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi    }
95e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi
96e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi    // Construct from WordInfo array. n-th element represents (n+1)-th previous word's information.
97e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi    public PrevWordsInfo(final WordInfo[] prevWordsInfo) {
98e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi        for (int i = 0; i < Constants.MAX_PREV_WORD_COUNT_FOR_N_GRAM; i++) {
99e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi            mPrevWordsInfo[i] =
100e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi                    (prevWordsInfo.length > i) ? prevWordsInfo[i] : WordInfo.EMPTY_WORD_INFO;
101e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi        }
102e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi    }
103e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi
104e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi    // Create next prevWordsInfo using current prevWordsInfo.
105e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi    public PrevWordsInfo getNextPrevWordsInfo(final WordInfo wordInfo) {
106e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi        final WordInfo[] prevWordsInfo = new WordInfo[Constants.MAX_PREV_WORD_COUNT_FOR_N_GRAM];
107e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi        prevWordsInfo[0] = wordInfo;
108e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi        for (int i = 1; i < prevWordsInfo.length; i++) {
109e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi            prevWordsInfo[i] = mPrevWordsInfo[i - 1];
110e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi        }
111e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi        return new PrevWordsInfo(prevWordsInfo);
11283c40a2301a0b5a42a75eecada48e7887a7c940eKeisuke Kuroyanagi    }
1131adca93381d261a6070be2721dbf8b8abafbfe01Keisuke Kuroyanagi
1141adca93381d261a6070be2721dbf8b8abafbfe01Keisuke Kuroyanagi    public boolean isValid() {
115e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi        return mPrevWordsInfo[0].isValid();
116e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi    }
117e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi
118e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi    public void outputToArray(final int[][] codePointArrays,
119e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi            final boolean[] isBeginningOfSentenceArray) {
120e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi        for (int i = 0; i < mPrevWordsInfo.length; i++) {
121e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi            final WordInfo wordInfo = mPrevWordsInfo[i];
122e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi            if (wordInfo == null || !wordInfo.isValid()) {
123e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi                codePointArrays[i] = new int[0];
124e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi                isBeginningOfSentenceArray[i] = false;
125e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi                continue;
126e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi            }
127e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi            codePointArrays[i] = StringUtils.toCodePointArray(wordInfo.mWord);
128e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi            isBeginningOfSentenceArray[i] = wordInfo.mIsBeginningOfSentence;
129e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi        }
1301adca93381d261a6070be2721dbf8b8abafbfe01Keisuke Kuroyanagi    }
131dfca51726e9dc9a35f462dee39331823eafa07c9Keisuke Kuroyanagi
132dfca51726e9dc9a35f462dee39331823eafa07c9Keisuke Kuroyanagi    @Override
1331c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi    public int hashCode() {
1341c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi        return Arrays.hashCode(mPrevWordsInfo);
1351c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi    }
1361c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi
1371c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi    @Override
1381c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi    public boolean equals(Object o) {
1391c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi        if (this == o) return true;
1401c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi        if (!(o instanceof PrevWordsInfo)) return false;
1411c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi        final PrevWordsInfo prevWordsInfo = (PrevWordsInfo)o;
1421c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi        return Arrays.equals(mPrevWordsInfo, prevWordsInfo.mPrevWordsInfo);
1431c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi    }
1441c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi
1451c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi    @Override
146dfca51726e9dc9a35f462dee39331823eafa07c9Keisuke Kuroyanagi    public String toString() {
147e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi        final StringBuffer builder = new StringBuffer();
148e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi        for (int i = 0; i < mPrevWordsInfo.length; i++) {
149e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi            final WordInfo wordInfo = mPrevWordsInfo[i];
150e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi            builder.append("PrevWord[");
151e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi            builder.append(i);
152e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi            builder.append("]: ");
1531c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi            if (wordInfo == null || !wordInfo.isValid()) {
154e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi                builder.append("Empty. ");
155e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi                continue;
156e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi            }
157e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi            builder.append(wordInfo.mWord);
158e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi            builder.append(", isBeginningOfSentence: ");
159e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi            builder.append(wordInfo.mIsBeginningOfSentence);
160e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi            builder.append(". ");
161e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi        }
162e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi        return builder.toString();
163dfca51726e9dc9a35f462dee39331823eafa07c9Keisuke Kuroyanagi    }
16483c40a2301a0b5a42a75eecada48e7887a7c940eKeisuke Kuroyanagi}
165