1 /*
2  * Copyright (C) 2012 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 #ifndef LATINIME_DIC_TRAVERSE_SESSION_H
18 #define LATINIME_DIC_TRAVERSE_SESSION_H
19 
20 #include <vector>
21 
22 #include "defines.h"
23 #include "dictionary/utils/multi_bigram_map.h"
24 #include "jni.h"
25 #include "suggest/core/dicnode/dic_nodes_cache.h"
26 #include "suggest/core/layout/proximity_info_state.h"
27 #include "utils/int_array_view.h"
28 
29 namespace latinime {
30 
31 class Dictionary;
32 class DictionaryStructureWithBufferPolicy;
33 class NgramContext;
34 class ProximityInfo;
35 class SuggestOptions;
36 
37 class DicTraverseSession {
38  public:
39 
40     // A factory method for DicTraverseSession
getSessionInstance(JNIEnv * env,jstring localeStr,jlong dictSize)41     static AK_FORCE_INLINE void *getSessionInstance(JNIEnv *env, jstring localeStr,
42             jlong dictSize) {
43         // To deal with the trade-off between accuracy and memory space, large cache is used for
44         // dictionaries larger that the threshold
45         return new DicTraverseSession(env, localeStr,
46                 dictSize >= DICTIONARY_SIZE_THRESHOLD_TO_USE_LARGE_CACHE_FOR_SUGGESTION);
47     }
48 
releaseSessionInstance(DicTraverseSession * traverseSession)49     static AK_FORCE_INLINE void releaseSessionInstance(DicTraverseSession *traverseSession) {
50         delete traverseSession;
51     }
52 
DicTraverseSession(JNIEnv * env,jstring localeStr,bool usesLargeCache)53     AK_FORCE_INLINE DicTraverseSession(JNIEnv *env, jstring localeStr, bool usesLargeCache)
54             : mPrevWordIdCount(0), mProximityInfo(nullptr), mDictionary(nullptr),
55               mSuggestOptions(nullptr), mDicNodesCache(usesLargeCache), mMultiBigramMap(),
56               mInputSize(0), mMaxPointerCount(1), mMultiWordCostMultiplier(1.0f) {
57         // NOTE: mProximityInfoStates is an array of instances.
58         // No need to initialize it explicitly here.
59     }
60 
61     // Non virtual inline destructor -- never inherit this class
~DicTraverseSession()62     AK_FORCE_INLINE ~DicTraverseSession() {}
63 
64     void init(const Dictionary *dictionary, const NgramContext *const ngramContext,
65             const SuggestOptions *const suggestOptions);
66     // TODO: Remove and merge into init
67     void setupForGetSuggestions(const ProximityInfo *pInfo, const int *inputCodePoints,
68             const int inputSize, const int *const inputXs, const int *const inputYs,
69             const int *const times, const int *const pointerIds, const float maxSpatialDistance,
70             const int maxPointerCount);
71     void resetCache(const int thresholdForNextActiveDicNodes, const int maxWords);
72 
73     const DictionaryStructureWithBufferPolicy *getDictionaryStructurePolicy() const;
74 
75     //--------------------
76     // getters and setters
77     //--------------------
getProximityInfo()78     const ProximityInfo *getProximityInfo() const { return mProximityInfo; }
getSuggestOptions()79     const SuggestOptions *getSuggestOptions() const { return mSuggestOptions; }
getPrevWordIds()80     const WordIdArrayView getPrevWordIds() const {
81         return WordIdArrayView::fromArray(mPrevWordIdArray).limit(mPrevWordIdCount);
82     }
getDicTraverseCache()83     DicNodesCache *getDicTraverseCache() { return &mDicNodesCache; }
getMultiBigramMap()84     MultiBigramMap *getMultiBigramMap() { return &mMultiBigramMap; }
getProximityInfoState(int id)85     const ProximityInfoState *getProximityInfoState(int id) const {
86         return &mProximityInfoStates[id];
87     }
getInputSize()88     int getInputSize() const { return mInputSize; }
89 
isOnlyOnePointerUsed(int * pointerId)90     bool isOnlyOnePointerUsed(int *pointerId) const {
91         // Not in the dictionary word
92         int usedPointerCount = 0;
93         int usedPointerId = 0;
94         for (int i = 0; i < mMaxPointerCount; ++i) {
95             if (mProximityInfoStates[i].isUsed()) {
96                 ++usedPointerCount;
97                 usedPointerId = i;
98             }
99         }
100         if (usedPointerCount != 1) {
101             return false;
102         }
103         if (pointerId) {
104             *pointerId = usedPointerId;
105         }
106         return true;
107     }
108 
getProximityTypeG(const DicNode * const dicNode,const int childCodePoint)109     ProximityType getProximityTypeG(const DicNode *const dicNode, const int childCodePoint) const {
110         ProximityType proximityType = UNRELATED_CHAR;
111         for (int i = 0; i < MAX_POINTER_COUNT_G; ++i) {
112             if (!mProximityInfoStates[i].isUsed()) {
113                 continue;
114             }
115             const int pointerId = dicNode->getInputIndex(i);
116             proximityType = mProximityInfoStates[i].getProximityTypeG(pointerId, childCodePoint);
117             ASSERT(proximityType == UNRELATED_CHAR || proximityType == MATCH_CHAR);
118             // TODO: Make this more generic
119             // Currently we assume there are only two types here -- UNRELATED_CHAR
120             // and MATCH_CHAR
121             if (proximityType != UNRELATED_CHAR) {
122                 return proximityType;
123             }
124         }
125         return proximityType;
126     }
127 
isCacheBorderForTyping(const int inputSize)128     AK_FORCE_INLINE bool isCacheBorderForTyping(const int inputSize) const {
129         return mDicNodesCache.isCacheBorderForTyping(inputSize);
130     }
131 
132     /**
133      * Returns whether or not it is possible to continue suggestion from the previous search.
134      */
135     // TODO: Remove. No need to check once the session is fully implemented.
isContinuousSuggestionPossible()136     bool isContinuousSuggestionPossible() const {
137         if (!mDicNodesCache.hasCachedDicNodesForContinuousSuggestion()) {
138             return false;
139         }
140         ASSERT(mMaxPointerCount <= MAX_POINTER_COUNT_G);
141         for (int i = 0; i < mMaxPointerCount; ++i) {
142             const ProximityInfoState *const pInfoState = getProximityInfoState(i);
143             // If a proximity info state is not continuous suggestion possible,
144             // do not continue searching.
145             if (pInfoState->isUsed() && !pInfoState->isContinuousSuggestionPossible()) {
146                 return false;
147             }
148         }
149         return true;
150     }
151 
isTouchPositionCorrectionEnabled()152     bool isTouchPositionCorrectionEnabled() const {
153         return mProximityInfoStates[0].touchPositionCorrectionEnabled();
154     }
155 
getMultiWordCostMultiplier()156     float getMultiWordCostMultiplier() const {
157         return mMultiWordCostMultiplier;
158     }
159 
160  private:
161     DISALLOW_IMPLICIT_CONSTRUCTORS(DicTraverseSession);
162     // threshold to start caching
163     static const int CACHE_START_INPUT_LENGTH_THRESHOLD;
164     static const int DICTIONARY_SIZE_THRESHOLD_TO_USE_LARGE_CACHE_FOR_SUGGESTION;
165     void initializeProximityInfoStates(const int *const inputCodePoints, const int *const inputXs,
166             const int *const inputYs, const int *const times, const int *const pointerIds,
167             const int inputSize, const float maxSpatialDistance, const int maxPointerCount);
168 
169     WordIdArray<MAX_PREV_WORD_COUNT_FOR_N_GRAM> mPrevWordIdArray;
170     size_t mPrevWordIdCount;
171     const ProximityInfo *mProximityInfo;
172     const Dictionary *mDictionary;
173     const SuggestOptions *mSuggestOptions;
174 
175     DicNodesCache mDicNodesCache;
176     // Temporary cache for bigram frequencies
177     MultiBigramMap mMultiBigramMap;
178     ProximityInfoState mProximityInfoStates[MAX_POINTER_COUNT_G];
179 
180     int mInputSize;
181     int mMaxPointerCount;
182 
183     /////////////////////////////////
184     // Configuration per dictionary
185     float mMultiWordCostMultiplier;
186 
187 };
188 } // namespace latinime
189 #endif // LATINIME_DIC_TRAVERSE_SESSION_H
190