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 <stdint.h> 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/policyimpl/typing/scoring_params.h" 30 #include "utils/char_utils.h" 31 32 namespace latinime { 33 class TypingTraversal : public Traversal { 34 public: 35 static const TypingTraversal *getInstance() { return &sInstance; } 36 37 AK_FORCE_INLINE int getMaxPointerCount() const { 38 return MAX_POINTER_COUNT; 39 } 40 41 AK_FORCE_INLINE bool allowsErrorCorrections(const DicNode *const dicNode) const { 42 return dicNode->getNormalizedSpatialDistance() 43 < ScoringParams::NORMALIZED_SPATIAL_DISTANCE_THRESHOLD_FOR_EDIT; 44 } 45 46 AK_FORCE_INLINE bool isOmission(const DicTraverseSession *const traverseSession, 47 const DicNode *const dicNode, const DicNode *const childDicNode, 48 const bool allowsErrorCorrections) const { 49 if (!CORRECT_OMISSION) { 50 return false; 51 } 52 // Note: Always consider intentional omissions (like apostrophes) since they are common. 53 const bool canConsiderOmission = 54 allowsErrorCorrections || childDicNode->canBeIntentionalOmission(); 55 if (!canConsiderOmission) { 56 return false; 57 } 58 const int inputSize = traverseSession->getInputSize(); 59 // TODO: Don't refer to isCompletion? 60 if (dicNode->isCompletion(inputSize)) { 61 return false; 62 } 63 if (dicNode->canBeIntentionalOmission()) { 64 return true; 65 } 66 const int point0Index = dicNode->getInputIndex(0); 67 const int currentBaseLowerCodePoint = 68 CharUtils::toBaseLowerCase(childDicNode->getNodeCodePoint()); 69 const int typedBaseLowerCodePoint = 70 CharUtils::toBaseLowerCase(traverseSession->getProximityInfoState(0) 71 ->getPrimaryCodePointAt(point0Index)); 72 return (currentBaseLowerCodePoint != typedBaseLowerCodePoint); 73 } 74 75 AK_FORCE_INLINE bool isSpaceSubstitutionTerminal( 76 const DicTraverseSession *const traverseSession, const DicNode *const dicNode) const { 77 if (!CORRECT_NEW_WORD_SPACE_SUBSTITUTION) { 78 return false; 79 } 80 if (!canDoLookAheadCorrection(traverseSession, dicNode)) { 81 return false; 82 } 83 const int point0Index = dicNode->getInputIndex(0); 84 return dicNode->isTerminalWordNode() 85 && traverseSession->getProximityInfoState(0)-> 86 hasSpaceProximity(point0Index); 87 } 88 89 AK_FORCE_INLINE bool isSpaceOmissionTerminal( 90 const DicTraverseSession *const traverseSession, const DicNode *const dicNode) const { 91 if (!CORRECT_NEW_WORD_SPACE_OMISSION) { 92 return false; 93 } 94 const int inputSize = traverseSession->getInputSize(); 95 // TODO: Don't refer to isCompletion? 96 if (dicNode->isCompletion(inputSize)) { 97 return false; 98 } 99 if (!dicNode->isTerminalWordNode()) { 100 return false; 101 } 102 const int16_t pointIndex = dicNode->getInputIndex(0); 103 return pointIndex <= inputSize && !dicNode->isTotalInputSizeExceedingLimit() 104 && !dicNode->shouldBeFilteredBySafetyNetForBigram(); 105 } 106 107 AK_FORCE_INLINE bool shouldDepthLevelCache( 108 const DicTraverseSession *const traverseSession) const { 109 const int inputSize = traverseSession->getInputSize(); 110 return traverseSession->isCacheBorderForTyping(inputSize); 111 } 112 113 AK_FORCE_INLINE bool shouldNodeLevelCache( 114 const DicTraverseSession *const traverseSession, const DicNode *const dicNode) const { 115 return false; 116 } 117 118 AK_FORCE_INLINE bool canDoLookAheadCorrection( 119 const DicTraverseSession *const traverseSession, const DicNode *const dicNode) const { 120 const int inputSize = traverseSession->getInputSize(); 121 return dicNode->canDoLookAheadCorrection(inputSize); 122 } 123 124 AK_FORCE_INLINE ProximityType getProximityType( 125 const DicTraverseSession *const traverseSession, const DicNode *const dicNode, 126 const DicNode *const childDicNode) const { 127 return traverseSession->getProximityInfoState(0)->getProximityType( 128 dicNode->getInputIndex(0), childDicNode->getNodeCodePoint(), 129 true /* checkProximityChars */); 130 } 131 132 AK_FORCE_INLINE bool needsToTraverseAllUserInput() const { 133 return true; 134 } 135 136 AK_FORCE_INLINE float getMaxSpatialDistance() const { 137 return ScoringParams::MAX_SPATIAL_DISTANCE; 138 } 139 140 AK_FORCE_INLINE bool autoCorrectsToMultiWordSuggestionIfTop() const { 141 return true; 142 } 143 144 AK_FORCE_INLINE int getDefaultExpandDicNodeSize() const { 145 return DicNodeVector::DEFAULT_NODES_SIZE_FOR_OPTIMIZATION; 146 } 147 148 AK_FORCE_INLINE bool sameAsTyped( 149 const DicTraverseSession *const traverseSession, const DicNode *const dicNode) const { 150 return traverseSession->getProximityInfoState(0)->sameAsTyped( 151 dicNode->getOutputWordBuf(), dicNode->getNodeCodePointCount()); 152 } 153 154 AK_FORCE_INLINE int getMaxCacheSize(const int inputSize) const { 155 return (inputSize <= 1) ? ScoringParams::MAX_CACHE_DIC_NODE_SIZE_FOR_SINGLE_POINT 156 : ScoringParams::MAX_CACHE_DIC_NODE_SIZE; 157 } 158 159 AK_FORCE_INLINE bool isPossibleOmissionChildNode( 160 const DicTraverseSession *const traverseSession, const DicNode *const parentDicNode, 161 const DicNode *const dicNode) const { 162 const ProximityType proximityType = 163 getProximityType(traverseSession, parentDicNode, dicNode); 164 if (!ProximityInfoUtils::isMatchOrProximityChar(proximityType)) { 165 return false; 166 } 167 return true; 168 } 169 170 AK_FORCE_INLINE bool isGoodToTraverseNextWord(const DicNode *const dicNode) const { 171 const int probability = dicNode->getProbability(); 172 if (probability < ScoringParams::THRESHOLD_NEXT_WORD_PROBABILITY) { 173 return false; 174 } 175 const int c = dicNode->getOutputWordBuf()[0]; 176 const bool shortCappedWord = dicNode->getNodeCodePointCount() 177 < ScoringParams::THRESHOLD_SHORT_WORD_LENGTH && CharUtils::isAsciiUpper(c); 178 return !shortCappedWord 179 || probability >= ScoringParams::THRESHOLD_NEXT_WORD_PROBABILITY_FOR_CAPPED; 180 } 181 182 private: 183 DISALLOW_COPY_AND_ASSIGN(TypingTraversal); 184 static const bool CORRECT_OMISSION; 185 static const bool CORRECT_NEW_WORD_SPACE_SUBSTITUTION; 186 static const bool CORRECT_NEW_WORD_SPACE_OMISSION; 187 static const TypingTraversal sInstance; 188 189 TypingTraversal() {} 190 ~TypingTraversal() {} 191 }; 192 } // namespace latinime 193 #endif // LATINIME_TYPING_TRAVERSAL_H 194