1 /* 2 * Copyright (C) 2013 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_TYPING_TRAVERSAL_H 18 #define LATINIME_TYPING_TRAVERSAL_H 19 20 #include <cstdint> 21 22 #include "defines.h" 23 #include "suggest/core/dicnode/dic_node.h" 24 #include "suggest/core/dicnode/dic_node_vector.h" 25 #include "suggest/core/layout/proximity_info_state.h" 26 #include "suggest/core/layout/proximity_info_utils.h" 27 #include "suggest/core/policy/traversal.h" 28 #include "suggest/core/session/dic_traverse_session.h" 29 #include "suggest/core/suggest_options.h" 30 #include "suggest/policyimpl/typing/scoring_params.h" 31 #include "utils/char_utils.h" 32 33 namespace latinime { 34 class TypingTraversal : public Traversal { 35 public: 36 static const TypingTraversal *getInstance() { return &sInstance; } 37 38 AK_FORCE_INLINE int getMaxPointerCount() const { 39 return MAX_POINTER_COUNT; 40 } 41 42 AK_FORCE_INLINE bool allowsErrorCorrections(const DicNode *const dicNode) const { 43 return dicNode->getNormalizedSpatialDistance() 44 < ScoringParams::NORMALIZED_SPATIAL_DISTANCE_THRESHOLD_FOR_EDIT; 45 } 46 47 AK_FORCE_INLINE bool isOmission(const DicTraverseSession *const traverseSession, 48 const DicNode *const dicNode, const DicNode *const childDicNode, 49 const bool allowsErrorCorrections) const { 50 if (!CORRECT_OMISSION) { 51 return false; 52 } 53 // Note: Always consider intentional omissions (like apostrophes) since they are common. 54 const bool canConsiderOmission = 55 allowsErrorCorrections || childDicNode->canBeIntentionalOmission(); 56 if (!canConsiderOmission) { 57 return false; 58 } 59 const int inputSize = traverseSession->getInputSize(); 60 // TODO: Don't refer to isCompletion? 61 if (dicNode->isCompletion(inputSize)) { 62 return false; 63 } 64 if (dicNode->canBeIntentionalOmission()) { 65 return true; 66 } 67 const int point0Index = dicNode->getInputIndex(0); 68 const int currentBaseLowerCodePoint = 69 CharUtils::toBaseLowerCase(childDicNode->getNodeCodePoint()); 70 const int typedBaseLowerCodePoint = 71 CharUtils::toBaseLowerCase(traverseSession->getProximityInfoState(0) 72 ->getPrimaryCodePointAt(point0Index)); 73 return (currentBaseLowerCodePoint != typedBaseLowerCodePoint); 74 } 75 76 AK_FORCE_INLINE bool isSpaceSubstitutionTerminal( 77 const DicTraverseSession *const traverseSession, const DicNode *const dicNode) const { 78 if (!CORRECT_NEW_WORD_SPACE_SUBSTITUTION) { 79 return false; 80 } 81 if (traverseSession->getSuggestOptions()->weightForLocale() 82 < ScoringParams::LOCALE_WEIGHT_THRESHOLD_FOR_SPACE_SUBSTITUTION) { 83 // Space substitution is heavy, so we skip doing it if the weight for this language 84 // is low because we anticipate the suggestions out of this dictionary are not for 85 // the language the user intends to type in. 86 return false; 87 } 88 if (!canDoLookAheadCorrection(traverseSession, dicNode)) { 89 return false; 90 } 91 const int point0Index = dicNode->getInputIndex(0); 92 return dicNode->isTerminalDicNode() 93 && traverseSession->getProximityInfoState(0)-> 94 hasSpaceProximity(point0Index); 95 } 96 97 AK_FORCE_INLINE bool isSpaceOmissionTerminal( 98 const DicTraverseSession *const traverseSession, const DicNode *const dicNode) const { 99 if (!CORRECT_NEW_WORD_SPACE_OMISSION) { 100 return false; 101 } 102 if (traverseSession->getSuggestOptions()->weightForLocale() 103 < ScoringParams::LOCALE_WEIGHT_THRESHOLD_FOR_SPACE_OMISSION) { 104 // Space omission is heavy, so we skip doing it if the weight for this language 105 // is low because we anticipate the suggestions out of this dictionary are not for 106 // the language the user intends to type in. 107 return false; 108 } 109 const int inputSize = traverseSession->getInputSize(); 110 // TODO: Don't refer to isCompletion? 111 if (dicNode->isCompletion(inputSize)) { 112 return false; 113 } 114 if (!dicNode->isTerminalDicNode()) { 115 return false; 116 } 117 const int16_t pointIndex = dicNode->getInputIndex(0); 118 return pointIndex <= inputSize && !dicNode->isTotalInputSizeExceedingLimit() 119 && !dicNode->shouldBeFilteredBySafetyNetForBigram(); 120 } 121 122 AK_FORCE_INLINE bool shouldDepthLevelCache( 123 const DicTraverseSession *const traverseSession) const { 124 const int inputSize = traverseSession->getInputSize(); 125 return traverseSession->isCacheBorderForTyping(inputSize); 126 } 127 128 AK_FORCE_INLINE bool shouldNodeLevelCache( 129 const DicTraverseSession *const traverseSession, const DicNode *const dicNode) const { 130 return false; 131 } 132 133 AK_FORCE_INLINE bool canDoLookAheadCorrection( 134 const DicTraverseSession *const traverseSession, const DicNode *const dicNode) const { 135 const int inputSize = traverseSession->getInputSize(); 136 return dicNode->canDoLookAheadCorrection(inputSize); 137 } 138 139 AK_FORCE_INLINE ProximityType getProximityType( 140 const DicTraverseSession *const traverseSession, const DicNode *const dicNode, 141 const DicNode *const childDicNode) const { 142 return traverseSession->getProximityInfoState(0)->getProximityType( 143 dicNode->getInputIndex(0), childDicNode->getNodeCodePoint(), 144 true /* checkProximityChars */); 145 } 146 147 AK_FORCE_INLINE bool needsToTraverseAllUserInput() const { 148 return true; 149 } 150 151 AK_FORCE_INLINE float getMaxSpatialDistance() const { 152 return ScoringParams::MAX_SPATIAL_DISTANCE; 153 } 154 155 AK_FORCE_INLINE int getDefaultExpandDicNodeSize() const { 156 return DicNodeVector::DEFAULT_NODES_SIZE_FOR_OPTIMIZATION; 157 } 158 159 AK_FORCE_INLINE int getMaxCacheSize(const int inputSize, const float weightForLocale) const { 160 if (inputSize <= 1) { 161 return ScoringParams::MAX_CACHE_DIC_NODE_SIZE_FOR_SINGLE_POINT; 162 } 163 if (weightForLocale < ScoringParams::LOCALE_WEIGHT_THRESHOLD_FOR_SMALL_CACHE_SIZE) { 164 return ScoringParams::MAX_CACHE_DIC_NODE_SIZE_FOR_LOW_PROBABILITY_LOCALE; 165 } 166 return ScoringParams::MAX_CACHE_DIC_NODE_SIZE; 167 } 168 169 AK_FORCE_INLINE int getTerminalCacheSize() const { 170 return MAX_RESULTS; 171 } 172 173 AK_FORCE_INLINE bool isPossibleOmissionChildNode( 174 const DicTraverseSession *const traverseSession, const DicNode *const parentDicNode, 175 const DicNode *const dicNode) const { 176 const ProximityType proximityType = 177 getProximityType(traverseSession, parentDicNode, dicNode); 178 if (!ProximityInfoUtils::isMatchOrProximityChar(proximityType)) { 179 return false; 180 } 181 return true; 182 } 183 184 AK_FORCE_INLINE bool isGoodToTraverseNextWord(const DicNode *const dicNode, 185 const int probability) const { 186 if (probability < ScoringParams::THRESHOLD_NEXT_WORD_PROBABILITY) { 187 return false; 188 } 189 const bool shortCappedWord = dicNode->getNodeCodePointCount() 190 < ScoringParams::THRESHOLD_SHORT_WORD_LENGTH && dicNode->isFirstCharUppercase(); 191 return !shortCappedWord 192 || probability >= ScoringParams::THRESHOLD_NEXT_WORD_PROBABILITY_FOR_CAPPED; 193 } 194 195 private: 196 DISALLOW_COPY_AND_ASSIGN(TypingTraversal); 197 static const bool CORRECT_OMISSION; 198 static const bool CORRECT_NEW_WORD_SPACE_SUBSTITUTION; 199 static const bool CORRECT_NEW_WORD_SPACE_OMISSION; 200 static const TypingTraversal sInstance; 201 202 TypingTraversal() {} 203 ~TypingTraversal() {} 204 }; 205 } // namespace latinime 206 #endif // LATINIME_TYPING_TRAVERSAL_H 207