NgramContext.java revision 11a3965f8c376db4d8fbdf3c6ea6ac54550ae6ed
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
21bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagiimport com.android.inputmethod.annotations.UsedForTesting;
229342484e8d573a40f470b6a593df31c602fa4076Ken Wakasaimport com.android.inputmethod.latin.common.Constants;
234beeb9253a06482299e0c67467531d30436a02fcJean Chalardimport com.android.inputmethod.latin.common.StringUtils;
24e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi
2586f36003fd4397143bd37938dda029e5707634afYohei Yukawaimport java.util.Arrays;
2686f36003fd4397143bd37938dda029e5707634afYohei Yukawa
27d3a4c5132422b189c8dbb94dbbe84a9b9761b0a8Tadashi G. Takaokaimport javax.annotation.Nonnull;
28d3a4c5132422b189c8dbb94dbbe84a9b9761b0a8Tadashi G. Takaoka
29a790c5b68324da41428aeb68594d43ca5632f66dKeisuke Kuroyanagi/**
30a790c5b68324da41428aeb68594d43ca5632f66dKeisuke Kuroyanagi * Class to represent information of previous words. This class is used to add n-gram entries
31a790c5b68324da41428aeb68594d43ca5632f66dKeisuke Kuroyanagi * into binary dictionaries, to get predictions, and to get suggestions.
32a790c5b68324da41428aeb68594d43ca5632f66dKeisuke Kuroyanagi */
33bb0eca57054758ef17b032d2654c1fc5f6b32101Keisuke Kuroyanagipublic class NgramContext {
34d3a4c5132422b189c8dbb94dbbe84a9b9761b0a8Tadashi G. Takaoka    @Nonnull
35bb0eca57054758ef17b032d2654c1fc5f6b32101Keisuke Kuroyanagi    public static final NgramContext EMPTY_PREV_WORDS_INFO =
36bb0eca57054758ef17b032d2654c1fc5f6b32101Keisuke Kuroyanagi            new NgramContext(WordInfo.EMPTY_WORD_INFO);
37d3a4c5132422b189c8dbb94dbbe84a9b9761b0a8Tadashi G. Takaoka    @Nonnull
38bb0eca57054758ef17b032d2654c1fc5f6b32101Keisuke Kuroyanagi    public static final NgramContext BEGINNING_OF_SENTENCE =
395f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka            new NgramContext(WordInfo.BEGINNING_OF_SENTENCE_WORD_INFO);
401adca93381d261a6070be2721dbf8b8abafbfe01Keisuke Kuroyanagi
41e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi    /**
42e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi     * Word information used to represent previous words information.
43e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi     */
44e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi    public static class WordInfo {
45d3a4c5132422b189c8dbb94dbbe84a9b9761b0a8Tadashi G. Takaoka        @Nonnull
46e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi        public static final WordInfo EMPTY_WORD_INFO = new WordInfo(null);
47d3a4c5132422b189c8dbb94dbbe84a9b9761b0a8Tadashi G. Takaoka        @Nonnull
485f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka        public static final WordInfo BEGINNING_OF_SENTENCE_WORD_INFO = new WordInfo();
49e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi
5086f36003fd4397143bd37938dda029e5707634afYohei Yukawa        // This is an empty char sequence when mIsBeginningOfSentence is true.
5186f36003fd4397143bd37938dda029e5707634afYohei Yukawa        public final CharSequence mWord;
52e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi        // TODO: Have sentence separator.
53e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi        // Whether the current context is beginning of sentence or not. This is true when composing
54e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi        // at the beginning of an input field or composing a word after a sentence separator.
55e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi        public final boolean mIsBeginningOfSentence;
56e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi
57e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi        // Beginning of sentence.
585f00fe09e9a611b647592188316e5999465df4d3Tadashi G. Takaoka        private WordInfo() {
59e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi            mWord = "";
60e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi            mIsBeginningOfSentence = true;
61e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi        }
62e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi
6386f36003fd4397143bd37938dda029e5707634afYohei Yukawa        public WordInfo(final CharSequence word) {
64e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi            mWord = word;
65e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi            mIsBeginningOfSentence = false;
66e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi        }
67e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi
68e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi        public boolean isValid() {
69e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi            return mWord != null;
70e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi        }
711c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi
721c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi        @Override
731c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi        public int hashCode() {
741c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi            return Arrays.hashCode(new Object[] { mWord, mIsBeginningOfSentence } );
751c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi        }
761c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi
771c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi        @Override
781c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi        public boolean equals(Object o) {
791c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi            if (this == o) return true;
801c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi            if (!(o instanceof WordInfo)) return false;
811c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi            final WordInfo wordInfo = (WordInfo)o;
821c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi            if (mWord == null || wordInfo.mWord == null) {
831c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi                return mWord == wordInfo.mWord
841c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi                        && mIsBeginningOfSentence == wordInfo.mIsBeginningOfSentence;
851c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi            }
8686f36003fd4397143bd37938dda029e5707634afYohei Yukawa            return TextUtils.equals(mWord, wordInfo.mWord)
871c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi                    && mIsBeginningOfSentence == wordInfo.mIsBeginningOfSentence;
881c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi        }
89e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi    }
9083c40a2301a0b5a42a75eecada48e7887a7c940eKeisuke Kuroyanagi
91e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi    // The words immediately before the considered word. EMPTY_WORD_INFO element means we don't
92e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi    // have any context for that previous word including the "beginning of sentence context" - we
93e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi    // just don't know what to predict using the information. An example of that is after a comma.
94e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi    // For simplicity of implementation, elements may also be EMPTY_WORD_INFO transiently after the
95e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi    // WordComposer was reset and before starting a new composing word, but we should never be
96e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi    // calling getSuggetions* in this situation.
97bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi    private final WordInfo[] mPrevWordsInfo;
98bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi    private final int mPrevWordsCount;
9917f326b7458c2bde2569e283a96e703755485328Keisuke Kuroyanagi
100e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi    // Construct from the previous word information.
101bb0eca57054758ef17b032d2654c1fc5f6b32101Keisuke Kuroyanagi    public NgramContext(final WordInfo... prevWordsInfo) {
102bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi        mPrevWordsInfo = prevWordsInfo;
103bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi        mPrevWordsCount = prevWordsInfo.length;
104e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi    }
105e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi
106e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi    // Create next prevWordsInfo using current prevWordsInfo.
107d3a4c5132422b189c8dbb94dbbe84a9b9761b0a8Tadashi G. Takaoka    @Nonnull
108bb0eca57054758ef17b032d2654c1fc5f6b32101Keisuke Kuroyanagi    public NgramContext getNextNgramContext(final WordInfo wordInfo) {
1094466464c24d6c6523f170f56b7e65e43ceb699e2Keisuke Kuroyanagi        final int nextPrevWordCount = Math.min(Constants.MAX_PREV_WORD_COUNT_FOR_N_GRAM,
110bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi                mPrevWordsCount + 1);
1114466464c24d6c6523f170f56b7e65e43ceb699e2Keisuke Kuroyanagi        final WordInfo[] prevWordsInfo = new WordInfo[nextPrevWordCount];
112e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi        prevWordsInfo[0] = wordInfo;
113bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi        System.arraycopy(mPrevWordsInfo, 0, prevWordsInfo, 1, nextPrevWordCount - 1);
114bb0eca57054758ef17b032d2654c1fc5f6b32101Keisuke Kuroyanagi        return new NgramContext(prevWordsInfo);
11583c40a2301a0b5a42a75eecada48e7887a7c940eKeisuke Kuroyanagi    }
1161adca93381d261a6070be2721dbf8b8abafbfe01Keisuke Kuroyanagi
1171adca93381d261a6070be2721dbf8b8abafbfe01Keisuke Kuroyanagi    public boolean isValid() {
118bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi        return mPrevWordsCount > 0 && mPrevWordsInfo[0].isValid();
119bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi    }
120bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi
121bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi    public boolean isBeginningOfSentenceContext() {
122bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi        return mPrevWordsCount > 0 && mPrevWordsInfo[0].mIsBeginningOfSentence;
123bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi    }
124bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi
125bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi    // n is 1-indexed.
126bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi    // TODO: Remove
127bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi    public CharSequence getNthPrevWord(final int n) {
128bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi        if (n <= 0 || n > mPrevWordsCount) {
129bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi            return null;
130bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi        }
131bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi        return mPrevWordsInfo[n - 1].mWord;
132bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi    }
133bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi
134bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi    // n is 1-indexed.
135bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi    @UsedForTesting
13611a3965f8c376db4d8fbdf3c6ea6ac54550ae6edAdrian Velicu    public boolean isNthPrevWordBeginningOfSentence(final int n) {
137bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi        if (n <= 0 || n > mPrevWordsCount) {
138bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi            return false;
139bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi        }
140bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi        return mPrevWordsInfo[n - 1].mIsBeginningOfSentence;
141e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi    }
142e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi
143e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi    public void outputToArray(final int[][] codePointArrays,
144e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi            final boolean[] isBeginningOfSentenceArray) {
145bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi        for (int i = 0; i < mPrevWordsCount; i++) {
146e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi            final WordInfo wordInfo = mPrevWordsInfo[i];
147e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi            if (wordInfo == null || !wordInfo.isValid()) {
148e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi                codePointArrays[i] = new int[0];
149e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi                isBeginningOfSentenceArray[i] = false;
150e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi                continue;
151e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi            }
152e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi            codePointArrays[i] = StringUtils.toCodePointArray(wordInfo.mWord);
153e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi            isBeginningOfSentenceArray[i] = wordInfo.mIsBeginningOfSentence;
154e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi        }
1551adca93381d261a6070be2721dbf8b8abafbfe01Keisuke Kuroyanagi    }
156dfca51726e9dc9a35f462dee39331823eafa07c9Keisuke Kuroyanagi
1574466464c24d6c6523f170f56b7e65e43ceb699e2Keisuke Kuroyanagi    public int getPrevWordCount() {
158bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi        return mPrevWordsCount;
1594466464c24d6c6523f170f56b7e65e43ceb699e2Keisuke Kuroyanagi    }
1604466464c24d6c6523f170f56b7e65e43ceb699e2Keisuke Kuroyanagi
161dfca51726e9dc9a35f462dee39331823eafa07c9Keisuke Kuroyanagi    @Override
1621c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi    public int hashCode() {
163c6a6f6a9905ab98516d944ac85933d016e4147fbKeisuke Kuroyanagi        int hashValue = 0;
164c6a6f6a9905ab98516d944ac85933d016e4147fbKeisuke Kuroyanagi        for (final WordInfo wordInfo : mPrevWordsInfo) {
165c6a6f6a9905ab98516d944ac85933d016e4147fbKeisuke Kuroyanagi            if (wordInfo == null || !WordInfo.EMPTY_WORD_INFO.equals(wordInfo)) {
166c6a6f6a9905ab98516d944ac85933d016e4147fbKeisuke Kuroyanagi                break;
167c6a6f6a9905ab98516d944ac85933d016e4147fbKeisuke Kuroyanagi            }
168c6a6f6a9905ab98516d944ac85933d016e4147fbKeisuke Kuroyanagi            hashValue ^= wordInfo.hashCode();
169c6a6f6a9905ab98516d944ac85933d016e4147fbKeisuke Kuroyanagi        }
170c6a6f6a9905ab98516d944ac85933d016e4147fbKeisuke Kuroyanagi        return hashValue;
1711c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi    }
1721c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi
1731c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi    @Override
1741c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi    public boolean equals(Object o) {
1751c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi        if (this == o) return true;
176bb0eca57054758ef17b032d2654c1fc5f6b32101Keisuke Kuroyanagi        if (!(o instanceof NgramContext)) return false;
177bb0eca57054758ef17b032d2654c1fc5f6b32101Keisuke Kuroyanagi        final NgramContext prevWordsInfo = (NgramContext)o;
178845c061970f0dcbe75eac028e142aa054f88e2a9Keisuke Kuroyanagi
179bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi        final int minLength = Math.min(mPrevWordsCount, prevWordsInfo.mPrevWordsCount);
180845c061970f0dcbe75eac028e142aa054f88e2a9Keisuke Kuroyanagi        for (int i = 0; i < minLength; i++) {
181845c061970f0dcbe75eac028e142aa054f88e2a9Keisuke Kuroyanagi            if (!mPrevWordsInfo[i].equals(prevWordsInfo.mPrevWordsInfo[i])) {
182845c061970f0dcbe75eac028e142aa054f88e2a9Keisuke Kuroyanagi                return false;
183845c061970f0dcbe75eac028e142aa054f88e2a9Keisuke Kuroyanagi            }
184845c061970f0dcbe75eac028e142aa054f88e2a9Keisuke Kuroyanagi        }
185bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi        final WordInfo[] longerWordsInfo;
186bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi        final int longerWordsInfoCount;
187bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi        if (mPrevWordsCount > prevWordsInfo.mPrevWordsCount) {
188bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi            longerWordsInfo = mPrevWordsInfo;
189bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi            longerWordsInfoCount = mPrevWordsCount;
190bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi        } else {
191bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi            longerWordsInfo = prevWordsInfo.mPrevWordsInfo;
192bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi            longerWordsInfoCount = prevWordsInfo.mPrevWordsCount;
193bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi        }
194bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi        for (int i = minLength; i < longerWordsInfoCount; i++) {
195845c061970f0dcbe75eac028e142aa054f88e2a9Keisuke Kuroyanagi            if (longerWordsInfo[i] != null
196845c061970f0dcbe75eac028e142aa054f88e2a9Keisuke Kuroyanagi                    && !WordInfo.EMPTY_WORD_INFO.equals(longerWordsInfo[i])) {
197845c061970f0dcbe75eac028e142aa054f88e2a9Keisuke Kuroyanagi                return false;
198845c061970f0dcbe75eac028e142aa054f88e2a9Keisuke Kuroyanagi            }
199845c061970f0dcbe75eac028e142aa054f88e2a9Keisuke Kuroyanagi        }
200845c061970f0dcbe75eac028e142aa054f88e2a9Keisuke Kuroyanagi        return true;
2011c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi    }
2021c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi
2031c2f1ada8305e36defa8572da687a4596bf083eaKeisuke Kuroyanagi    @Override
204dfca51726e9dc9a35f462dee39331823eafa07c9Keisuke Kuroyanagi    public String toString() {
205e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi        final StringBuffer builder = new StringBuffer();
206bbd6a26be025bc419e342e32d86629c4ebd68dd8Keisuke Kuroyanagi        for (int i = 0; i < mPrevWordsCount; i++) {
207e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi            final WordInfo wordInfo = mPrevWordsInfo[i];
208e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi            builder.append("PrevWord[");
209e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi            builder.append(i);
210e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi            builder.append("]: ");
211845c061970f0dcbe75eac028e142aa054f88e2a9Keisuke Kuroyanagi            if (wordInfo == null) {
212845c061970f0dcbe75eac028e142aa054f88e2a9Keisuke Kuroyanagi                builder.append("null. ");
213845c061970f0dcbe75eac028e142aa054f88e2a9Keisuke Kuroyanagi                continue;
214845c061970f0dcbe75eac028e142aa054f88e2a9Keisuke Kuroyanagi            }
215845c061970f0dcbe75eac028e142aa054f88e2a9Keisuke Kuroyanagi            if (!wordInfo.isValid()) {
216e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi                builder.append("Empty. ");
217e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi                continue;
218e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi            }
219e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi            builder.append(wordInfo.mWord);
220e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi            builder.append(", isBeginningOfSentence: ");
221e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi            builder.append(wordInfo.mIsBeginningOfSentence);
222e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi            builder.append(". ");
223e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi        }
224e708b1bc2e11285ad404133b8de21719ce08acb5Keisuke Kuroyanagi        return builder.toString();
225dfca51726e9dc9a35f462dee39331823eafa07c9Keisuke Kuroyanagi    }
22683c40a2301a0b5a42a75eecada48e7887a7c940eKeisuke Kuroyanagi}
227