Home | History | Annotate | Download | only in typing
      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