13e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka/*
23e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka * Copyright (C) 2012 The Android Open Source Project
33e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka *
43e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka * Licensed under the Apache License, Version 2.0 (the "License");
53e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka * you may not use this file except in compliance with the License.
63e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka * You may obtain a copy of the License at
73e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka *
83e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka *      http://www.apache.org/licenses/LICENSE-2.0
93e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka *
103e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka * Unless required by applicable law or agreed to in writing, software
113e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka * distributed under the License is distributed on an "AS IS" BASIS,
123e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
133e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka * See the License for the specific language governing permissions and
143e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka * limitations under the License.
153e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka */
163e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka
17f88f9dbbdec309c01feda06edc142470ba13cb2fKeisuke Kuroyanagi#define LOG_TAG "LatinIME: proximity_info_state.cpp"
18f88f9dbbdec309c01feda06edc142470ba13cb2fKeisuke Kuroyanagi
1929432f843a8cd6ffb2be286104964592e80d77c9Ken Wakasa#include "suggest/core/layout/proximity_info_state.h"
2029432f843a8cd6ffb2be286104964592e80d77c9Ken Wakasa
21865e6cf49764f3a411ee32861d927b15653ee398Keisuke Kuroyanagi#include <algorithm>
223e0777e726ce40b4c4b65174a21db41c19f04602Keisuke Kuroyanagi#include <cstring> // for memset() and memmove()
23806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi#include <sstream> // for debug prints
248ca9be17db2f1845c7c7a3b584507cf60c9ca53dKen Wakasa#include <unordered_map>
25e5cdd21102e4e49b18c696261a084783eb6d7e7aSatoshi Kataoka#include <vector>
263e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka
273e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka#include "defines.h"
2829432f843a8cd6ffb2be286104964592e80d77c9Ken Wakasa#include "suggest/core/layout/geometry_utils.h"
2929432f843a8cd6ffb2be286104964592e80d77c9Ken Wakasa#include "suggest/core/layout/proximity_info.h"
3029432f843a8cd6ffb2be286104964592e80d77c9Ken Wakasa#include "suggest/core/layout/proximity_info_state_utils.h"
31addea83bad5751308fef508d79c6989b8872f050Ken Wakasa#include "utils/char_utils.h"
323e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka
333e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataokanamespace latinime {
34764dd712032d7b8012797b1116b523bef7b907f3Ken Wakasa
352fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasaint ProximityInfoState::getPrimaryOriginalCodePointAt(const int index) const {
362fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    const int primaryCodePoint = getPrimaryCodePointAt(index);
372fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    const int keyIndex = mProximityInfo->getKeyIndexOf(primaryCodePoint);
382fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa    return mProximityInfo->getOriginalCodePointOf(keyIndex);
392fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa}
402fa3693c264a4c150ac307d9bb7f6f8f18cc4ffcKen Wakasa
41a1d84bcf8ffd031c135b6f3f8c94b6732071849bSatoshi Kataoka// TODO: Remove the dependency of "isGeometric"
42233aad5e5c7567a97af30f38f50a65365f729dfeSatoshi Kataokavoid ProximityInfoState::initInputParams(const int pointerId, const float maxPointToKeyLength,
431e61493c50082264caaef862df02b1ccc84dc396Ken Wakasa        const ProximityInfo *proximityInfo, const int *const inputCodes, const int inputSize,
44687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka        const int *const xCoordinates, const int *const yCoordinates, const int *const times,
45687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka        const int *const pointerIds, const bool isGeometric) {
469d18c6dd38c4d5632a5d5a5c26f567b9f6f7f969Satoshi Kataoka    ASSERT(isGeometric || (inputSize < MAX_WORD_LENGTH));
47f1233b58c2d81b575c92339f146cfe0f73a992faKeisuke Kuroyanagi    mIsContinuousSuggestionPossible = (mHasBeenUpdatedByGeometricInput != isGeometric) ?
48f1233b58c2d81b575c92339f146cfe0f73a992faKeisuke Kuroyanagi            false : ProximityInfoStateUtils::checkAndReturnIsContinuousSuggestionPossible(
49394b0bd345f33b1314613a433478fd0bb711e0f7Satoshi Kataoka                    inputSize, xCoordinates, yCoordinates, times, mSampledInputSize,
50394b0bd345f33b1314613a433478fd0bb711e0f7Satoshi Kataoka                    &mSampledInputXs, &mSampledInputYs, &mSampledTimes, &mSampledInputIndice);
51d1fff1adcc0693286ace156eaf467ccccbc0a719Satoshi Kataoka    if (DEBUG_DICT) {
52394b0bd345f33b1314613a433478fd0bb711e0f7Satoshi Kataoka        AKLOGI("isContinuousSuggestionPossible = %s",
53394b0bd345f33b1314613a433478fd0bb711e0f7Satoshi Kataoka                (mIsContinuousSuggestionPossible ? "true" : "false"));
54d1fff1adcc0693286ace156eaf467ccccbc0a719Satoshi Kataoka    }
55096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi
564a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka    mProximityInfo = proximityInfo;
574a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka    mHasTouchPositionCorrectionData = proximityInfo->hasTouchPositionCorrectionData();
584a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka    mMostCommonKeyWidthSquare = proximityInfo->getMostCommonKeyWidthSquare();
594a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka    mKeyCount = proximityInfo->getKeyCount();
604a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka    mCellHeight = proximityInfo->getCellHeight();
614a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka    mCellWidth = proximityInfo->getCellWidth();
624a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka    mGridHeight = proximityInfo->getGridWidth();
634a3db7057f77dc85311fb1f94934b5a004ab613eSatoshi Kataoka    mGridWidth = proximityInfo->getGridHeight();
643e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka
65bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka    memset(mInputProximities, 0, sizeof(mInputProximities));
663e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka
6708f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka    if (!isGeometric && pointerId == 0) {
68bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka        mProximityInfo->initializeProximities(inputCodes, xCoordinates, yCoordinates,
69bf78e1371c12d819020d60f0e585f5e6c26e6aa2Satoshi Kataoka                inputSize, mInputProximities);
703e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka    }
71687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka
72687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka    ///////////////////////
73687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka    // Setup touch points
74096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi    int pushTouchPointStartIndex = 0;
75096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi    int lastSavedInputSize = 0;
7608f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka    mMaxPointToKeyLength = maxPointToKeyLength;
7720b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka    mSampledInputSize = 0;
7820b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka    mMostProbableStringProbability = 0.0f;
7920b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka
80394b0bd345f33b1314613a433478fd0bb711e0f7Satoshi Kataoka    if (mIsContinuousSuggestionPossible && mSampledInputIndice.size() > 1) {
81096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi        // Just update difference.
8220b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka        // Previous two points are never skipped. Thus, we pop 2 input point data here.
8320b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka        pushTouchPointStartIndex = ProximityInfoStateUtils::trimLastTwoTouchPoints(
8420b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka                &mSampledInputXs, &mSampledInputYs, &mSampledTimes, &mSampledLengthCache,
8520b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka                &mSampledInputIndice);
86feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka        lastSavedInputSize = mSampledInputXs.size();
87096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi    } else {
88096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi        // Clear all data.
89feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka        mSampledInputXs.clear();
90feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka        mSampledInputYs.clear();
91d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka        mSampledTimes.clear();
92d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka        mSampledInputIndice.clear();
93d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka        mSampledLengthCache.clear();
94837f46dcb35a8f42a6bd5bc5fc6395d7386acb81Satoshi Kataoka        mSampledNormalizedSquaredLengthCache.clear();
95e5cdd21102e4e49b18c696261a084783eb6d7e7aSatoshi Kataoka        mSampledSearchKeySets.clear();
969af533538ea749d7c930bb3125fa4d3e4feb8478Satoshi Kataoka        mSpeedRates.clear();
976ae8dd4343445d2df4444388b605d2aa930fa2a0Satoshi Kataoka        mBeelineSpeedPercentiles.clear();
98806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi        mCharProbabilities.clear();
991e06a4d8e9e71188ed685282155ea52a48ddc050Keisuke Kuroyanagi        mDirections.clear();
100096f35ff4b5413906e2a339663baf16e5dabaf64Keisuke Kuroyanagi    }
10120b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka
1029182daf98c0d1db897e82b77c2196b7f9aad6f01Satoshi Kataoka    if (DEBUG_GEO_FULL) {
1039182daf98c0d1db897e82b77c2196b7f9aad6f01Satoshi Kataoka        AKLOGI("Init ProximityInfoState: reused points =  %d, last input size = %d",
1049182daf98c0d1db897e82b77c2196b7f9aad6f01Satoshi Kataoka                pushTouchPointStartIndex, lastSavedInputSize);
1059182daf98c0d1db897e82b77c2196b7f9aad6f01Satoshi Kataoka    }
106d9c10b19793b011f862e3dd31883f746044431d7Keisuke Kuroyanagi
107687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka    if (xCoordinates && yCoordinates) {
10828c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa        mSampledInputSize = ProximityInfoStateUtils::updateTouchPoints(mProximityInfo,
10928c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa                mMaxPointToKeyLength, mInputProximities, xCoordinates, yCoordinates, times,
1100052dbda762b1871c3214a6abeb5e89f11e091cdKeisuke Kuroynagi                pointerIds, inputSize, isGeometric, pointerId,
111a1d84bcf8ffd031c135b6f3f8c94b6732071849bSatoshi Kataoka                pushTouchPointStartIndex, &mSampledInputXs, &mSampledInputYs, &mSampledTimes,
112a1d84bcf8ffd031c135b6f3f8c94b6732071849bSatoshi Kataoka                &mSampledLengthCache, &mSampledInputIndice);
1133e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka    }
114687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka
115feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka    if (mSampledInputSize > 0 && isGeometric) {
11628c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa        mAverageSpeed = ProximityInfoStateUtils::refreshSpeedRates(inputSize, xCoordinates,
11728c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa                yCoordinates, times, lastSavedInputSize, mSampledInputSize, &mSampledInputXs,
11828c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa                &mSampledInputYs, &mSampledTimes, &mSampledLengthCache, &mSampledInputIndice,
11928c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa                &mSpeedRates, &mDirections);
12028c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa        ProximityInfoStateUtils::refreshBeelineSpeedRates(mProximityInfo->getMostCommonKeyWidth(),
12128c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa                mAverageSpeed, inputSize, xCoordinates, yCoordinates, times, mSampledInputSize,
12228c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa                &mSampledInputXs, &mSampledInputYs, &mSampledInputIndice,
12328c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa                &mBeelineSpeedPercentiles);
124ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    }
125ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi
126feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka    if (mSampledInputSize > 0) {
12728c008421cc5d97da8e470dbc934a2891daf9997Ken Wakasa        ProximityInfoStateUtils::initGeometricDistanceInfos(mProximityInfo, mSampledInputSize,
1280052dbda762b1871c3214a6abeb5e89f11e091cdKeisuke Kuroynagi                lastSavedInputSize, isGeometric, &mSampledInputXs, &mSampledInputYs,
129bc9500fb14622f8b185e30a10a7c0b4c5a29930aKeisuke Kuroyanagi                &mSampledNormalizedSquaredLengthCache);
130ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi        if (isGeometric) {
131ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi            // updates probabilities of skipping or mapping each key for all points.
132d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka            ProximityInfoStateUtils::updateAlignPointProbabilities(
133d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka                    mMaxPointToKeyLength, mProximityInfo->getMostCommonKeyWidth(),
134d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka                    mProximityInfo->getKeyCount(), lastSavedInputSize, mSampledInputSize,
135d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka                    &mSampledInputXs, &mSampledInputYs, &mSpeedRates, &mSampledLengthCache,
136bc9500fb14622f8b185e30a10a7c0b4c5a29930aKeisuke Kuroyanagi                    &mSampledNormalizedSquaredLengthCache, mProximityInfo, &mCharProbabilities);
137e5cdd21102e4e49b18c696261a084783eb6d7e7aSatoshi Kataoka            ProximityInfoStateUtils::updateSampledSearchKeySets(mProximityInfo,
138e5aad5646309e80e1cd71533fb47a6be43f3aa2fSatoshi Kataoka                    mSampledInputSize, lastSavedInputSize, &mSampledLengthCache,
139bc9500fb14622f8b185e30a10a7c0b4c5a29930aKeisuke Kuroyanagi                    &mCharProbabilities, &mSampledSearchKeySets,
140e5cdd21102e4e49b18c696261a084783eb6d7e7aSatoshi Kataoka                    &mSampledSearchKeyVectors);
14120b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka            mMostProbableStringProbability = ProximityInfoStateUtils::getMostProbableString(
14220b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka                    mProximityInfo, mSampledInputSize, &mCharProbabilities, mMostProbableString);
14320b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka
144687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka        }
145687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka    }
14608f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka
147806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi    if (DEBUG_SAMPLING_POINTS) {
148d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka        ProximityInfoStateUtils::dump(isGeometric, inputSize, xCoordinates, yCoordinates,
149e2912d17e4dab75b81f4c9e41a539e491ac059caSatoshi Kataoka                mSampledInputSize, &mSampledInputXs, &mSampledInputYs, &mSampledTimes, &mSpeedRates,
150d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka                &mBeelineSpeedPercentiles);
151806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi    }
152687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka    // end
153687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka    ///////////////////////
154687a244703a02323ebd64433cbaead5def499861Satoshi Kataoka
155feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka    mTouchPositionCorrectionEnabled = mSampledInputSize > 0 && mHasTouchPositionCorrectionData
1560edab9d2fcc30667c79aa9221dbb27f042d8b455Satoshi Kataoka            && xCoordinates && yCoordinates;
15708f00cf55f2e083c1ed254a32495b622c9ad9862Satoshi Kataoka    if (!isGeometric && pointerId == 0) {
158d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka        ProximityInfoStateUtils::initPrimaryInputWord(
159d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72eSatoshi Kataoka                inputSize, mInputProximities, mPrimaryInputWord);
1603e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka    }
161952ec4977d772607140773ae7d8868f86a7e0097Satoshi Kataoka    if (DEBUG_GEO_FULL) {
162feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka        AKLOGI("ProximityState init finished: %d points out of %d", mSampledInputSize, inputSize);
163feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka    }
164f1233b58c2d81b575c92339f146cfe0f73a992faKeisuke Kuroyanagi    mHasBeenUpdatedByGeometricInput = isGeometric;
165feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka}
166feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka
1670519fdd18ac4414b8298d3338db1c8ccce032170Satoshi Kataoka// This function basically converts from a length to an edit distance. Accordingly, it's obviously
1680519fdd18ac4414b8298d3338db1c8ccce032170Satoshi Kataoka// wrong to compare with mMaxPointToKeyLength.
1690519fdd18ac4414b8298d3338db1c8ccce032170Satoshi Kataokafloat ProximityInfoState::getPointToKeyLength(
1702192d08b9cca6a40d834d6a5001d19b5845ed8a0Tom Ouyang        const int inputIndex, const int codePoint) const {
171ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    const int keyId = mProximityInfo->getKeyIndexOf(codePoint);
172ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    if (keyId != NOT_AN_INDEX) {
173ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi        const int index = inputIndex * mProximityInfo->getKeyCount() + keyId;
174865e6cf49764f3a411ee32861d927b15653ee398Keisuke Kuroyanagi        return std::min(mSampledNormalizedSquaredLengthCache[index], mMaxPointToKeyLength);
175ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    }
176464d3ba43257da34ab165da8ba0af11e928aae5cKen Wakasa    if (CharUtils::isIntentionalOmissionCodePoint(codePoint)) {
177806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi        return 0.0f;
178806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi    }
179ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    // If the char is not a key on the keyboard then return the max length.
180830ba67498c6da53b38212dd9ac5ba318a00de11Satoshi Kataoka    return static_cast<float>(MAX_VALUE_FOR_WEIGHTING);
181806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi}
182806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi
1830519fdd18ac4414b8298d3338db1c8ccce032170Satoshi Kataokafloat ProximityInfoState::getPointToKeyByIdLength(
1842192d08b9cca6a40d834d6a5001d19b5845ed8a0Tom Ouyang        const int inputIndex, const int keyId) const {
185d4828d5053ac30476b884c177235be0cac982c92Satoshi Kataoka    return ProximityInfoStateUtils::getPointToKeyByIdLength(mMaxPointToKeyLength,
186837f46dcb35a8f42a6bd5bc5fc6395d7386acb81Satoshi Kataoka            &mSampledNormalizedSquaredLengthCache, mProximityInfo->getKeyCount(), inputIndex,
187837f46dcb35a8f42a6bd5bc5fc6395d7386acb81Satoshi Kataoka            keyId);
1880519fdd18ac4414b8298d3338db1c8ccce032170Satoshi Kataoka}
1890519fdd18ac4414b8298d3338db1c8ccce032170Satoshi Kataoka
1902c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa// In the following function, c is the current character of the dictionary word currently examined.
1912c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa// currentChars is an array containing the keys close to the character the user actually typed at
1922c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa// the same position. We want to see if c is in it: if so, then the word contains at that position
1932c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa// a character close to what the user typed.
1942c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa// What the user typed is actually the first character of the array.
195697a9d3541dd5b643664fc1af9b3265267370127Satoshi Kataoka// proximityIndex is a pointer to the variable where getProximityType returns the index of c
1962c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa// in the proximity chars of the input index.
1972c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa// Notice : accented characters do not have a proximity list, so they are alone in their list. The
1982c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa// non-accented version of the character should be considered "close", but not the other keys close
1992c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa// to the non-accented version.
200697a9d3541dd5b643664fc1af9b3265267370127Satoshi KataokaProximityType ProximityInfoState::getProximityType(const int index, const int codePoint,
2012c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa        const bool checkProximityChars, int *proximityIndex) const {
2022c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa    const int *currentCodePoints = getProximityCodePointsAt(index);
2032c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa    const int firstCodePoint = currentCodePoints[0];
204464d3ba43257da34ab165da8ba0af11e928aae5cKen Wakasa    const int baseLowerC = CharUtils::toBaseLowerCase(codePoint);
2052c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa
2062c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa    // The first char in the array is what user typed. If it matches right away, that means the
2072c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa    // user typed that same char for this pos.
208697a9d3541dd5b643664fc1af9b3265267370127Satoshi Kataoka    if (firstCodePoint == baseLowerC || firstCodePoint == codePoint) {
209f4425aaae971fe78d44530ebe01cf7a59b2e47aaSatoshi Kataoka        return MATCH_CHAR;
2102c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa    }
2112c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa
212f4425aaae971fe78d44530ebe01cf7a59b2e47aaSatoshi Kataoka    if (!checkProximityChars) return SUBSTITUTION_CHAR;
2132c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa
2142c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa    // If the non-accented, lowercased version of that first character matches c, then we have a
2152c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa    // non-accented version of the accented character the user typed. Treat it as a close char.
216464d3ba43257da34ab165da8ba0af11e928aae5cKen Wakasa    if (CharUtils::toBaseLowerCase(firstCodePoint) == baseLowerC) {
217f4425aaae971fe78d44530ebe01cf7a59b2e47aaSatoshi Kataoka        return PROXIMITY_CHAR;
2182c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa    }
2192c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa
2202c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa    // Not an exact nor an accent-alike match: search the list of close keys
2212c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa    int j = 1;
2226c22439bf80da08576e86c1282afc5cfa431e235Ken Wakasa    while (j < MAX_PROXIMITY_CHARS_SIZE
2232c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa            && currentCodePoints[j] > ADDITIONAL_PROXIMITY_CHAR_DELIMITER_CODE) {
224697a9d3541dd5b643664fc1af9b3265267370127Satoshi Kataoka        const bool matched = (currentCodePoints[j] == baseLowerC
225697a9d3541dd5b643664fc1af9b3265267370127Satoshi Kataoka                || currentCodePoints[j] == codePoint);
2262c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa        if (matched) {
2272c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa            if (proximityIndex) {
2282c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa                *proximityIndex = j;
2292c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa            }
230f4425aaae971fe78d44530ebe01cf7a59b2e47aaSatoshi Kataoka            return PROXIMITY_CHAR;
2312c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa        }
2322c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa        ++j;
2332c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa    }
2346c22439bf80da08576e86c1282afc5cfa431e235Ken Wakasa    if (j < MAX_PROXIMITY_CHARS_SIZE
2352c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa            && currentCodePoints[j] == ADDITIONAL_PROXIMITY_CHAR_DELIMITER_CODE) {
2362c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa        ++j;
2376c22439bf80da08576e86c1282afc5cfa431e235Ken Wakasa        while (j < MAX_PROXIMITY_CHARS_SIZE
2382c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa                && currentCodePoints[j] > ADDITIONAL_PROXIMITY_CHAR_DELIMITER_CODE) {
239697a9d3541dd5b643664fc1af9b3265267370127Satoshi Kataoka            const bool matched = (currentCodePoints[j] == baseLowerC
240697a9d3541dd5b643664fc1af9b3265267370127Satoshi Kataoka                    || currentCodePoints[j] == codePoint);
2412c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa            if (matched) {
2422c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa                if (proximityIndex) {
2432c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa                    *proximityIndex = j;
2442c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa                }
2452c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa                return ADDITIONAL_PROXIMITY_CHAR;
2462c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa            }
2472c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa            ++j;
2482c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa        }
2492c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa    }
250f4425aaae971fe78d44530ebe01cf7a59b2e47aaSatoshi Kataoka    // Was not included, signal this as a substitution character.
251f4425aaae971fe78d44530ebe01cf7a59b2e47aaSatoshi Kataoka    return SUBSTITUTION_CHAR;
2522c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa}
2532c2f3a90d8115777adbe9ffd597f344aede84276Ken Wakasa
254697a9d3541dd5b643664fc1af9b3265267370127Satoshi KataokaProximityType ProximityInfoState::getProximityTypeG(const int index, const int codePoint) const {
255697a9d3541dd5b643664fc1af9b3265267370127Satoshi Kataoka    if (!isUsed()) {
256f4425aaae971fe78d44530ebe01cf7a59b2e47aaSatoshi Kataoka        return UNRELATED_CHAR;
257697a9d3541dd5b643664fc1af9b3265267370127Satoshi Kataoka    }
25884c52a3c813669d70305e584763549c989d9305dKeisuke Kuroyanagi    const int sampledSearchKeyVectorsSize = static_cast<int>(mSampledSearchKeyVectors.size());
25984c52a3c813669d70305e584763549c989d9305dKeisuke Kuroyanagi    if (index < 0 || index >= sampledSearchKeyVectorsSize) {
26084c52a3c813669d70305e584763549c989d9305dKeisuke Kuroyanagi        AKLOGE("getProximityTypeG() is called with an invalid index(%d). "
26184c52a3c813669d70305e584763549c989d9305dKeisuke Kuroyanagi                "mSampledSearchKeyVectors.size() = %d, codePoint = %x.", index,
26284c52a3c813669d70305e584763549c989d9305dKeisuke Kuroyanagi                sampledSearchKeyVectorsSize, codePoint);
26384c52a3c813669d70305e584763549c989d9305dKeisuke Kuroyanagi        ASSERT(false);
26484c52a3c813669d70305e584763549c989d9305dKeisuke Kuroyanagi        return UNRELATED_CHAR;
26584c52a3c813669d70305e584763549c989d9305dKeisuke Kuroyanagi    }
266464d3ba43257da34ab165da8ba0af11e928aae5cKen Wakasa    const int lowerCodePoint = CharUtils::toLowerCase(codePoint);
267464d3ba43257da34ab165da8ba0af11e928aae5cKen Wakasa    const int baseLowerCodePoint = CharUtils::toBaseCodePoint(lowerCodePoint);
268697a9d3541dd5b643664fc1af9b3265267370127Satoshi Kataoka    for (int i = 0; i < static_cast<int>(mSampledSearchKeyVectors[index].size()); ++i) {
269697a9d3541dd5b643664fc1af9b3265267370127Satoshi Kataoka        if (mSampledSearchKeyVectors[index][i] == lowerCodePoint
270697a9d3541dd5b643664fc1af9b3265267370127Satoshi Kataoka                || mSampledSearchKeyVectors[index][i] == baseLowerCodePoint) {
271f4425aaae971fe78d44530ebe01cf7a59b2e47aaSatoshi Kataoka            return MATCH_CHAR;
272697a9d3541dd5b643664fc1af9b3265267370127Satoshi Kataoka        }
273697a9d3541dd5b643664fc1af9b3265267370127Satoshi Kataoka    }
274f4425aaae971fe78d44530ebe01cf7a59b2e47aaSatoshi Kataoka    return UNRELATED_CHAR;
275697a9d3541dd5b643664fc1af9b3265267370127Satoshi Kataoka}
276697a9d3541dd5b643664fc1af9b3265267370127Satoshi Kataoka
277ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagibool ProximityInfoState::isKeyInSerchKeysAfterIndex(const int index, const int keyId) const {
27820b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka    ASSERT(keyId >= 0 && index >= 0 && index < mSampledInputSize);
279e5cdd21102e4e49b18c696261a084783eb6d7e7aSatoshi Kataoka    return mSampledSearchKeySets[index].test(keyId);
280ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi}
281ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi
282ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagifloat ProximityInfoState::getDirection(const int index0, const int index1) const {
283ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka    return ProximityInfoStateUtils::getDirection(
284ee62b78c9675bddaf2437e0cf521f6115e1d9febSatoshi Kataoka            &mSampledInputXs, &mSampledInputYs, index0, index1);
285ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi}
286ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi
287e0349619acdba79223390c9925d81f7e88c7f8adSatoshi Kataokafloat ProximityInfoState::getMostProbableString(int *const codePointBuf) const {
2883e0777e726ce40b4c4b65174a21db41c19f04602Keisuke Kuroyanagi    memmove(codePointBuf, mMostProbableString, sizeof(mMostProbableString));
28920b6775acc957896bdb038dfd99794d6cd7cea5aSatoshi Kataoka    return mMostProbableStringProbability;
290ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi}
291ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi
292f32869c6b6296a8bf594abdf0b18281d9312e54fSatoshi Kataokabool ProximityInfoState::hasSpaceProximity(const int index) const {
293f32869c6b6296a8bf594abdf0b18281d9312e54fSatoshi Kataoka    ASSERT(0 <= index && index < mSampledInputSize);
294f32869c6b6296a8bf594abdf0b18281d9312e54fSatoshi Kataoka    return mProximityInfo->hasSpaceProximity(getInputX(index), getInputY(index));
295f32869c6b6296a8bf594abdf0b18281d9312e54fSatoshi Kataoka}
296f32869c6b6296a8bf594abdf0b18281d9312e54fSatoshi Kataoka
297ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi// Returns a probability of mapping index to keyIndex.
298ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagifloat ProximityInfoState::getProbability(const int index, const int keyIndex) const {
299feec20a692c9ffdecf7855a45531a12f129086caSatoshi Kataoka    ASSERT(0 <= index && index < mSampledInputSize);
3008ca9be17db2f1845c7c7a3b584507cf60c9ca53dKen Wakasa    std::unordered_map<int, float>::const_iterator it = mCharProbabilities[index].find(keyIndex);
301ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    if (it != mCharProbabilities[index].end()) {
302ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi        return it->second;
303ff74cc3e5e75fc0c6b9ffaa5e68d879775dc6115Keisuke Kuroyanagi    }
304830ba67498c6da53b38212dd9ac5ba318a00de11Satoshi Kataoka    return static_cast<float>(MAX_VALUE_FOR_WEIGHTING);
305806eba452423e5e5971ef096dfae3fed180db665Keisuke Kuroyanagi}
3063e8c58f68d53e6cc9dbf59201c7bdfb8ad04a1cdSatoshi Kataoka} // namespace latinime
307