Home | History | Annotate | Download | only in latin
      1 /*
      2  * Copyright (C) 2014 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.inputmethod.latin;
     18 
     19 import android.text.TextUtils;
     20 
     21 import com.android.inputmethod.latin.utils.StringUtils;
     22 
     23 import java.util.Arrays;
     24 
     25 /**
     26  * Class to represent information of previous words. This class is used to add n-gram entries
     27  * into binary dictionaries, to get predictions, and to get suggestions.
     28  */
     29 public class PrevWordsInfo {
     30     public static final PrevWordsInfo EMPTY_PREV_WORDS_INFO =
     31             new PrevWordsInfo(WordInfo.EMPTY_WORD_INFO);
     32     public static final PrevWordsInfo BEGINNING_OF_SENTENCE =
     33             new PrevWordsInfo(WordInfo.BEGINNING_OF_SENTENCE);
     34 
     35     /**
     36      * Word information used to represent previous words information.
     37      */
     38     public static class WordInfo {
     39         public static final WordInfo EMPTY_WORD_INFO = new WordInfo(null);
     40         public static final WordInfo BEGINNING_OF_SENTENCE = new WordInfo();
     41 
     42         // This is an empty char sequence when mIsBeginningOfSentence is true.
     43         public final CharSequence mWord;
     44         // TODO: Have sentence separator.
     45         // Whether the current context is beginning of sentence or not. This is true when composing
     46         // at the beginning of an input field or composing a word after a sentence separator.
     47         public final boolean mIsBeginningOfSentence;
     48 
     49         // Beginning of sentence.
     50         public WordInfo() {
     51             mWord = "";
     52             mIsBeginningOfSentence = true;
     53         }
     54 
     55         public WordInfo(final CharSequence word) {
     56             mWord = word;
     57             mIsBeginningOfSentence = false;
     58         }
     59 
     60         public boolean isValid() {
     61             return mWord != null;
     62         }
     63 
     64         @Override
     65         public int hashCode() {
     66             return Arrays.hashCode(new Object[] { mWord, mIsBeginningOfSentence } );
     67         }
     68 
     69         @Override
     70         public boolean equals(Object o) {
     71             if (this == o) return true;
     72             if (!(o instanceof WordInfo)) return false;
     73             final WordInfo wordInfo = (WordInfo)o;
     74             if (mWord == null || wordInfo.mWord == null) {
     75                 return mWord == wordInfo.mWord
     76                         && mIsBeginningOfSentence == wordInfo.mIsBeginningOfSentence;
     77             }
     78             return TextUtils.equals(mWord, wordInfo.mWord)
     79                     && mIsBeginningOfSentence == wordInfo.mIsBeginningOfSentence;
     80         }
     81     }
     82 
     83     // The words immediately before the considered word. EMPTY_WORD_INFO element means we don't
     84     // have any context for that previous word including the "beginning of sentence context" - we
     85     // just don't know what to predict using the information. An example of that is after a comma.
     86     // For simplicity of implementation, elements may also be EMPTY_WORD_INFO transiently after the
     87     // WordComposer was reset and before starting a new composing word, but we should never be
     88     // calling getSuggetions* in this situation.
     89     public WordInfo[] mPrevWordsInfo = new WordInfo[Constants.MAX_PREV_WORD_COUNT_FOR_N_GRAM];
     90 
     91     // Construct from the previous word information.
     92     public PrevWordsInfo(final WordInfo prevWordInfo) {
     93         mPrevWordsInfo[0] = prevWordInfo;
     94     }
     95 
     96     // Construct from WordInfo array. n-th element represents (n+1)-th previous word's information.
     97     public PrevWordsInfo(final WordInfo[] prevWordsInfo) {
     98         for (int i = 0; i < Constants.MAX_PREV_WORD_COUNT_FOR_N_GRAM; i++) {
     99             mPrevWordsInfo[i] =
    100                     (prevWordsInfo.length > i) ? prevWordsInfo[i] : WordInfo.EMPTY_WORD_INFO;
    101         }
    102     }
    103 
    104     // Create next prevWordsInfo using current prevWordsInfo.
    105     public PrevWordsInfo getNextPrevWordsInfo(final WordInfo wordInfo) {
    106         final WordInfo[] prevWordsInfo = new WordInfo[Constants.MAX_PREV_WORD_COUNT_FOR_N_GRAM];
    107         prevWordsInfo[0] = wordInfo;
    108         for (int i = 1; i < prevWordsInfo.length; i++) {
    109             prevWordsInfo[i] = mPrevWordsInfo[i - 1];
    110         }
    111         return new PrevWordsInfo(prevWordsInfo);
    112     }
    113 
    114     public boolean isValid() {
    115         return mPrevWordsInfo[0].isValid();
    116     }
    117 
    118     public void outputToArray(final int[][] codePointArrays,
    119             final boolean[] isBeginningOfSentenceArray) {
    120         for (int i = 0; i < mPrevWordsInfo.length; i++) {
    121             final WordInfo wordInfo = mPrevWordsInfo[i];
    122             if (wordInfo == null || !wordInfo.isValid()) {
    123                 codePointArrays[i] = new int[0];
    124                 isBeginningOfSentenceArray[i] = false;
    125                 continue;
    126             }
    127             codePointArrays[i] = StringUtils.toCodePointArray(wordInfo.mWord);
    128             isBeginningOfSentenceArray[i] = wordInfo.mIsBeginningOfSentence;
    129         }
    130     }
    131 
    132     @Override
    133     public int hashCode() {
    134         return Arrays.hashCode(mPrevWordsInfo);
    135     }
    136 
    137     @Override
    138     public boolean equals(Object o) {
    139         if (this == o) return true;
    140         if (!(o instanceof PrevWordsInfo)) return false;
    141         final PrevWordsInfo prevWordsInfo = (PrevWordsInfo)o;
    142         return Arrays.equals(mPrevWordsInfo, prevWordsInfo.mPrevWordsInfo);
    143     }
    144 
    145     @Override
    146     public String toString() {
    147         final StringBuffer builder = new StringBuffer();
    148         for (int i = 0; i < mPrevWordsInfo.length; i++) {
    149             final WordInfo wordInfo = mPrevWordsInfo[i];
    150             builder.append("PrevWord[");
    151             builder.append(i);
    152             builder.append("]: ");
    153             if (wordInfo == null || !wordInfo.isValid()) {
    154                 builder.append("Empty. ");
    155                 continue;
    156             }
    157             builder.append(wordInfo.mWord);
    158             builder.append(", isBeginningOfSentence: ");
    159             builder.append(wordInfo.mIsBeginningOfSentence);
    160             builder.append(". ");
    161         }
    162         return builder.toString();
    163     }
    164 }
    165