From d7a8fbf6a9ec8828d4b6d1c615a6c605bbe5b72e Mon Sep 17 00:00:00 2001
From: Satoshi Kataoka <satok@google.com>
Date: Tue, 22 Jan 2013 17:00:43 +0900
Subject: [PATCH] refactor proximity info state

Change-Id: Iaf0c0fb7858358209fa12145777f158e0285bc27
---
 native/jni/src/proximity_info_params.cpp      |   4 +
 native/jni/src/proximity_info_params.h        |   3 +
 native/jni/src/proximity_info_state.cpp       | 169 ++++--------------
 native/jni/src/proximity_info_state.h         |  22 ++-
 native/jni/src/proximity_info_state_utils.cpp | 154 +++++++++++++++-
 native/jni/src/proximity_info_state_utils.h   |  31 +++-
 native/jni/src/suggest_utils.h                |   3 +-
 7 files changed, 234 insertions(+), 152 deletions(-)

diff --git a/native/jni/src/proximity_info_params.cpp b/native/jni/src/proximity_info_params.cpp
index 45f8fb5291..d62e090b08 100644
--- a/native/jni/src/proximity_info_params.cpp
+++ b/native/jni/src/proximity_info_params.cpp
@@ -21,4 +21,8 @@ const int ProximityInfoParams::LOOKUP_RADIUS_PERCENTILE = 50;
 const int ProximityInfoParams::FIRST_POINT_TIME_OFFSET_MILLIS = 150;
 const int ProximityInfoParams::STRONG_DOUBLE_LETTER_TIME_MILLIS = 600;
 const int ProximityInfoParams::MIN_DOUBLE_LETTER_BEELINE_SPEED_PERCENTILE = 5;
+const int ProximityInfoParams::NORMALIZED_SQUARED_DISTANCE_SCALING_FACTOR_LOG_2 = 10;
+const int ProximityInfoParams::NORMALIZED_SQUARED_DISTANCE_SCALING_FACTOR =
+        1 << NORMALIZED_SQUARED_DISTANCE_SCALING_FACTOR_LOG_2;
+const float ProximityInfoParams::NOT_A_DISTANCE_FLOAT = -1.0f;
 } // namespace latinime
diff --git a/native/jni/src/proximity_info_params.h b/native/jni/src/proximity_info_params.h
index e54945e6c8..171e6b4dec 100644
--- a/native/jni/src/proximity_info_params.h
+++ b/native/jni/src/proximity_info_params.h
@@ -27,8 +27,11 @@ class ProximityInfoParams {
     static const int FIRST_POINT_TIME_OFFSET_MILLIS;
     static const int STRONG_DOUBLE_LETTER_TIME_MILLIS;
     static const int MIN_DOUBLE_LETTER_BEELINE_SPEED_PERCENTILE;
+    static const int NORMALIZED_SQUARED_DISTANCE_SCALING_FACTOR;
+    static const float NOT_A_DISTANCE_FLOAT;
  private:
     DISALLOW_IMPLICIT_CONSTRUCTORS(ProximityInfoParams);
+    static const int NORMALIZED_SQUARED_DISTANCE_SCALING_FACTOR_LOG_2;
 };
 } // namespace latinime
 #endif // LATINIME_PROXIMITY_INFO_PARAMS_H
diff --git a/native/jni/src/proximity_info_state.cpp b/native/jni/src/proximity_info_state.cpp
index 45b72eb21a..86fe7e10af 100644
--- a/native/jni/src/proximity_info_state.cpp
+++ b/native/jni/src/proximity_info_state.cpp
@@ -27,10 +27,6 @@
 
 namespace latinime {
 
-const int ProximityInfoState::NORMALIZED_SQUARED_DISTANCE_SCALING_FACTOR_LOG_2 = 10;
-const int ProximityInfoState::NORMALIZED_SQUARED_DISTANCE_SCALING_FACTOR =
-        1 << NORMALIZED_SQUARED_DISTANCE_SCALING_FACTOR_LOG_2;
-const float ProximityInfoState::NOT_A_DISTANCE_FLOAT = -1.0f;
 const int ProximityInfoState::NOT_A_CODE = -1;
 
 void ProximityInfoState::initInputParams(const int pointerId, const float maxPointToKeyLength,
@@ -61,10 +57,10 @@ void ProximityInfoState::initInputParams(const int pointerId, const float maxPoi
     int pushTouchPointStartIndex = 0;
     int lastSavedInputSize = 0;
     mMaxPointToKeyLength = maxPointToKeyLength;
-    if (mIsContinuationPossible && mInputIndice.size() > 1) {
+    if (mIsContinuationPossible && mSampledInputIndice.size() > 1) {
         // Just update difference.
         // Two points prior is never skipped. Thus, we pop 2 input point data here.
-        pushTouchPointStartIndex = mInputIndice[mInputIndice.size() - 2];
+        pushTouchPointStartIndex = mSampledInputIndice[mSampledInputIndice.size() - 2];
         popInputData();
         popInputData();
         lastSavedInputSize = mSampledInputXs.size();
@@ -72,9 +68,9 @@ void ProximityInfoState::initInputParams(const int pointerId, const float maxPoi
         // Clear all data.
         mSampledInputXs.clear();
         mSampledInputYs.clear();
-        mTimes.clear();
-        mInputIndice.clear();
-        mLengthCache.clear();
+        mSampledTimes.clear();
+        mSampledInputIndice.clear();
+        mSampledLengthCache.clear();
         mDistanceCache_G.clear();
         mNearKeysVector.clear();
         mSearchKeysVector.clear();
@@ -93,56 +89,33 @@ void ProximityInfoState::initInputParams(const int pointerId, const float maxPoi
         mSampledInputSize = ProximityInfoStateUtils::updateTouchPoints(
                 mProximityInfo->getMostCommonKeyWidth(), mProximityInfo, mMaxPointToKeyLength,
                 mInputProximities, xCoordinates, yCoordinates, times, pointerIds, inputSize,
-                isGeometric, pointerId, pushTouchPointStartIndex,
-                &mSampledInputXs, &mSampledInputYs, &mTimes, &mLengthCache, &mInputIndice);
+                isGeometric, pointerId, pushTouchPointStartIndex, &mSampledInputXs,
+                &mSampledInputYs, &mSampledTimes, &mSampledLengthCache, &mSampledInputIndice);
     }
 
     if (mSampledInputSize > 0 && isGeometric) {
         mAverageSpeed = ProximityInfoStateUtils::refreshSpeedRates(
                 inputSize, xCoordinates, yCoordinates, times, lastSavedInputSize,
-                mSampledInputSize, &mSampledInputXs, &mSampledInputYs, &mTimes, &mLengthCache,
-                &mInputIndice, &mSpeedRates, &mDirections);
+                mSampledInputSize, &mSampledInputXs, &mSampledInputYs, &mSampledTimes,
+                &mSampledLengthCache, &mSampledInputIndice, &mSpeedRates, &mDirections);
         ProximityInfoStateUtils::refreshBeelineSpeedRates(
                 mProximityInfo->getMostCommonKeyWidth(), mAverageSpeed, inputSize,
                 xCoordinates, yCoordinates, times, mSampledInputSize, &mSampledInputXs,
-                &mSampledInputYs, &mInputIndice, &mBeelineSpeedPercentiles);
-    }
-
-    if (DEBUG_GEO_FULL) {
-        for (int i = 0; i < mSampledInputSize; ++i) {
-            AKLOGI("Sampled(%d): x = %d, y = %d, time = %d", i, mSampledInputXs[i],
-                    mSampledInputYs[i], mTimes[i]);
-        }
+                &mSampledInputYs, &mSampledInputIndice, &mBeelineSpeedPercentiles);
     }
 
     if (mSampledInputSize > 0) {
-        const int keyCount = mProximityInfo->getKeyCount();
-        mNearKeysVector.resize(mSampledInputSize);
-        mSearchKeysVector.resize(mSampledInputSize);
-        mDistanceCache_G.resize(mSampledInputSize * keyCount);
-        for (int i = lastSavedInputSize; i < mSampledInputSize; ++i) {
-            mNearKeysVector[i].reset();
-            mSearchKeysVector[i].reset();
-            static const float NEAR_KEY_NORMALIZED_SQUARED_THRESHOLD = 4.0f;
-            for (int k = 0; k < keyCount; ++k) {
-                const int index = i * keyCount + k;
-                const int x = mSampledInputXs[i];
-                const int y = mSampledInputYs[i];
-                const float normalizedSquaredDistance =
-                        mProximityInfo->getNormalizedSquaredDistanceFromCenterFloatG(k, x, y);
-                mDistanceCache_G[index] = normalizedSquaredDistance;
-                if (normalizedSquaredDistance < NEAR_KEY_NORMALIZED_SQUARED_THRESHOLD) {
-                    mNearKeysVector[i][k] = true;
-                }
-            }
-        }
+        ProximityInfoStateUtils::initGeometricDistanceInfos(
+                mProximityInfo, mProximityInfo->getKeyCount(),
+                mSampledInputSize, lastSavedInputSize, &mSampledInputXs, &mSampledInputYs,
+                &mNearKeysVector, &mSearchKeysVector, &mDistanceCache_G);
         if (isGeometric) {
             // updates probabilities of skipping or mapping each key for all points.
             ProximityInfoStateUtils::updateAlignPointProbabilities(
                     mMaxPointToKeyLength, mProximityInfo->getMostCommonKeyWidth(),
-                    keyCount, lastSavedInputSize, mSampledInputSize, &mSampledInputXs,
-                    &mSampledInputYs, &mSpeedRates, &mLengthCache, &mDistanceCache_G,
-                    &mNearKeysVector, &mCharProbabilities);
+                    mProximityInfo->getKeyCount(), lastSavedInputSize, mSampledInputSize,
+                    &mSampledInputXs, &mSampledInputYs, &mSpeedRates, &mSampledLengthCache,
+                    &mDistanceCache_G, &mNearKeysVector, &mCharProbabilities);
 
             static const float READ_FORWORD_LENGTH_SCALE = 0.95f;
             const int readForwordLength = static_cast<int>(
@@ -153,7 +126,7 @@ void ProximityInfoState::initInputParams(const int pointerId, const float maxPoi
                     mSearchKeysVector[i].reset();
                 }
                 for (int j = max(i, lastSavedInputSize); j < mSampledInputSize; ++j) {
-                    if (mLengthCache[j] - mLengthCache[i] >= readForwordLength) {
+                    if (mSampledLengthCache[j] - mSampledLengthCache[i] >= readForwordLength) {
                         break;
                     }
                     mSearchKeysVector[i] |= mNearKeysVector[j];
@@ -163,32 +136,9 @@ void ProximityInfoState::initInputParams(const int pointerId, const float maxPoi
     }
 
     if (DEBUG_SAMPLING_POINTS) {
-        std::stringstream originalX, originalY, sampledX, sampledY;
-        for (int i = 0; i < inputSize; ++i) {
-            originalX << xCoordinates[i];
-            originalY << yCoordinates[i];
-            if (i != inputSize - 1) {
-                originalX << ";";
-                originalY << ";";
-            }
-        }
-        AKLOGI("===== sampled points =====");
-        for (int i = 0; i < mSampledInputSize; ++i) {
-            if (isGeometric) {
-                AKLOGI("%d: x = %d, y = %d, time = %d, relative speed = %.4f, beeline speed = %d",
-                        i, mSampledInputXs[i], mSampledInputYs[i], mTimes[i], mSpeedRates[i],
-                        getBeelineSpeedPercentile(i));
-            }
-            sampledX << mSampledInputXs[i];
-            sampledY << mSampledInputYs[i];
-            if (i != mSampledInputSize - 1) {
-                sampledX << ";";
-                sampledY << ";";
-            }
-        }
-        AKLOGI("original points:\n%s, %s,\nsampled points:\n%s, %s,\n",
-                originalX.str().c_str(), originalY.str().c_str(), sampledX.str().c_str(),
-                sampledY.str().c_str());
+        ProximityInfoStateUtils::dump(isGeometric, inputSize, xCoordinates, yCoordinates,
+                mSampledInputSize, &mSampledInputXs, &mSampledInputYs, &mSpeedRates,
+                &mBeelineSpeedPercentiles);
     }
     // end
     ///////////////////////
@@ -198,42 +148,15 @@ void ProximityInfoState::initInputParams(const int pointerId, const float maxPoi
     mTouchPositionCorrectionEnabled = mSampledInputSize > 0 && mHasTouchPositionCorrectionData
             && xCoordinates && yCoordinates;
     if (!isGeometric && pointerId == 0) {
-        for (int i = 0; i < inputSize; ++i) {
-            mPrimaryInputWord[i] = getPrimaryCodePointAt(i);
-        }
-
-        for (int i = 0; i < mSampledInputSize && mTouchPositionCorrectionEnabled; ++i) {
-            const int *proximityCodePoints = getProximityCodePointsAt(i);
-            const int primaryKey = proximityCodePoints[0];
-            const int x = xCoordinates[i];
-            const int y = yCoordinates[i];
-            if (DEBUG_PROXIMITY_CHARS) {
-                int a = x + y + primaryKey;
-                a += 0;
-                AKLOGI("--- Primary = %c, x = %d, y = %d", primaryKey, x, y);
-            }
-            for (int j = 0; j < MAX_PROXIMITY_CHARS_SIZE && proximityCodePoints[j] > 0;
-                    ++j) {
-                const int currentCodePoint = proximityCodePoints[j];
-                const float squaredDistance =
-                        hasInputCoordinates() ? calculateNormalizedSquaredDistance(
-                                mProximityInfo->getKeyIndexOf(currentCodePoint), i) :
-                                NOT_A_DISTANCE_FLOAT;
-                if (squaredDistance >= 0.0f) {
-                    mNormalizedSquaredDistances[i * MAX_PROXIMITY_CHARS_SIZE + j] =
-                            (int) (squaredDistance * NORMALIZED_SQUARED_DISTANCE_SCALING_FACTOR);
-                } else {
-                    mNormalizedSquaredDistances[i * MAX_PROXIMITY_CHARS_SIZE + j] =
-                            (j == 0) ? EQUIVALENT_CHAR_WITHOUT_DISTANCE_INFO :
-                                    PROXIMITY_CHAR_WITHOUT_DISTANCE_INFO;
-                }
-                if (DEBUG_PROXIMITY_CHARS) {
-                    AKLOGI("--- Proximity (%d) = %c", j, currentCodePoint);
-                }
-            }
+        ProximityInfoStateUtils::initPrimaryInputWord(
+                inputSize, mInputProximities, mPrimaryInputWord);
+        if (mTouchPositionCorrectionEnabled) {
+            ProximityInfoStateUtils::initNormalizedSquaredDistances(
+                    mProximityInfo, inputSize, xCoordinates, yCoordinates, mInputProximities,
+                    hasInputCoordinates(), &mSampledInputXs, &mSampledInputYs,
+                    mNormalizedSquaredDistances);
         }
     }
-
     if (DEBUG_GEO_FULL) {
         AKLOGI("ProximityState init finished: %d points out of %d", mSampledInputSize, inputSize);
     }
@@ -244,9 +167,9 @@ bool ProximityInfoState::checkAndReturnIsContinuationPossible(const int inputSiz
         const bool isGeometric) const {
     if (isGeometric) {
         for (int i = 0; i < mSampledInputSize; ++i) {
-            const int index = mInputIndice[i];
+            const int index = mSampledInputIndice[i];
             if (index > inputSize || xCoordinates[index] != mSampledInputXs[i] ||
-                    yCoordinates[index] != mSampledInputYs[i] || times[index] != mTimes[i]) {
+                    yCoordinates[index] != mSampledInputYs[i] || times[index] != mSampledTimes[i]) {
                 return false;
             }
         }
@@ -265,26 +188,9 @@ bool ProximityInfoState::checkAndReturnIsContinuationPossible(const int inputSiz
     return true;
 }
 
-float ProximityInfoState::calculateNormalizedSquaredDistance(
-        const int keyIndex, const int inputIndex) const {
-    if (keyIndex == NOT_AN_INDEX) {
-        return NOT_A_DISTANCE_FLOAT;
-    }
-    if (!mProximityInfo->hasSweetSpotData(keyIndex)) {
-        return NOT_A_DISTANCE_FLOAT;
-    }
-    if (NOT_A_COORDINATE == mSampledInputXs[inputIndex]) {
-        return NOT_A_DISTANCE_FLOAT;
-    }
-    const float squaredDistance = calculateSquaredDistanceFromSweetSpotCenter(
-            keyIndex, inputIndex);
-    const float squaredRadius = square(mProximityInfo->getSweetSpotRadiiAt(keyIndex));
-    return squaredDistance / squaredRadius;
-}
-
 int ProximityInfoState::getDuration(const int index) const {
     if (index >= 0 && index < mSampledInputSize - 1) {
-        return mTimes[index + 1] - mTimes[index];
+        return mSampledTimes[index + 1] - mSampledTimes[index];
     }
     return 0;
 }
@@ -388,15 +294,6 @@ int ProximityInfoState::getSpaceY() const {
     return mProximityInfo->getKeyCenterYOfKeyIdG(keyId);
 }
 
-float ProximityInfoState::calculateSquaredDistanceFromSweetSpotCenter(
-        const int keyIndex, const int inputIndex) const {
-    const float sweetSpotCenterX = mProximityInfo->getSweetSpotCenterXAt(keyIndex);
-    const float sweetSpotCenterY = mProximityInfo->getSweetSpotCenterYAt(keyIndex);
-    const float inputX = static_cast<float>(mSampledInputXs[inputIndex]);
-    const float inputY = static_cast<float>(mSampledInputYs[inputIndex]);
-    return square(inputX - sweetSpotCenterX) + square(inputY - sweetSpotCenterY);
-}
-
 // Puts possible characters into filter and returns new filter size.
 int ProximityInfoState::getAllPossibleChars(
         const size_t index, int *const filter, const int filterSize) const {
@@ -431,8 +328,8 @@ bool ProximityInfoState::isKeyInSerchKeysAfterIndex(const int index, const int k
 }
 
 void ProximityInfoState::popInputData() {
-    ProximityInfoStateUtils::popInputData(&mSampledInputXs, &mSampledInputYs, &mTimes,
-            &mLengthCache, &mInputIndice);
+    ProximityInfoStateUtils::popInputData(&mSampledInputXs, &mSampledInputYs, &mSampledTimes,
+            &mSampledLengthCache, &mSampledInputIndice);
 }
 
 float ProximityInfoState::getDirection(const int index0, const int index1) const {
diff --git a/native/jni/src/proximity_info_state.h b/native/jni/src/proximity_info_state.h
index f2149e774d..8bada277ed 100644
--- a/native/jni/src/proximity_info_state.h
+++ b/native/jni/src/proximity_info_state.h
@@ -32,9 +32,7 @@ class ProximityInfo;
 
 class ProximityInfoState {
  public:
-    static const int NORMALIZED_SQUARED_DISTANCE_SCALING_FACTOR_LOG_2;
-    static const int NORMALIZED_SQUARED_DISTANCE_SCALING_FACTOR;
-    static const float NOT_A_DISTANCE_FLOAT;
+
     static const int NOT_A_CODE;
 
     /////////////////////////////////////////
@@ -52,10 +50,11 @@ class ProximityInfoState {
             : mProximityInfo(0), mMaxPointToKeyLength(0.0f), mAverageSpeed(0.0f),
               mHasTouchPositionCorrectionData(false), mMostCommonKeyWidthSquare(0),
               mKeyCount(0), mCellHeight(0), mCellWidth(0), mGridHeight(0), mGridWidth(0),
-              mIsContinuationPossible(false), mSampledInputXs(), mSampledInputYs(), mTimes(),
-              mInputIndice(), mLengthCache(), mBeelineSpeedPercentiles(), mDistanceCache_G(),
-              mSpeedRates(), mDirections(), mCharProbabilities(), mNearKeysVector(),
-              mSearchKeysVector(), mTouchPositionCorrectionEnabled(false), mSampledInputSize(0) {
+              mIsContinuationPossible(false), mSampledInputXs(), mSampledInputYs(), mSampledTimes(),
+              mSampledInputIndice(), mSampledLengthCache(), mBeelineSpeedPercentiles(),
+              mDistanceCache_G(), mSpeedRates(), mDirections(), mCharProbabilities(),
+              mNearKeysVector(), mSearchKeysVector(), mTouchPositionCorrectionEnabled(false),
+              mSampledInputSize(0) {
         memset(mInputProximities, 0, sizeof(mInputProximities));
         memset(mNormalizedSquaredDistances, 0, sizeof(mNormalizedSquaredDistances));
         memset(mPrimaryInputWord, 0, sizeof(mPrimaryInputWord));
@@ -144,7 +143,7 @@ class ProximityInfoState {
     bool hasSpaceProximity(const int index) const;
 
     int getLengthCache(const int index) const {
-        return mLengthCache[index];
+        return mSampledLengthCache[index];
     }
 
     bool isContinuationPossible() const {
@@ -210,7 +209,6 @@ class ProximityInfoState {
     /////////////////////////////////////////
     // Defined here                        //
     /////////////////////////////////////////
-    inline float square(const float x) const { return x * x; }
 
     bool hasInputCoordinates() const {
         return mSampledInputXs.size() > 0 && mSampledInputYs.size() > 0;
@@ -238,9 +236,9 @@ class ProximityInfoState {
 
     std::vector<int> mSampledInputXs;
     std::vector<int> mSampledInputYs;
-    std::vector<int> mTimes;
-    std::vector<int> mInputIndice;
-    std::vector<int> mLengthCache;
+    std::vector<int> mSampledTimes;
+    std::vector<int> mSampledInputIndice;
+    std::vector<int> mSampledLengthCache;
     std::vector<int> mBeelineSpeedPercentiles;
     std::vector<float> mDistanceCache_G;
     std::vector<float> mSpeedRates;
diff --git a/native/jni/src/proximity_info_state_utils.cpp b/native/jni/src/proximity_info_state_utils.cpp
index e5567f7a76..9dd3f0b9a7 100644
--- a/native/jni/src/proximity_info_state_utils.cpp
+++ b/native/jni/src/proximity_info_state_utils.cpp
@@ -24,6 +24,7 @@
 #include "proximity_info_state_utils.h"
 
 namespace latinime {
+
 /* static */ int ProximityInfoStateUtils::updateTouchPoints(const int mostCommonKeyWidth,
         const ProximityInfo *const proximityInfo, const int maxPointToKeyLength,
         const int *const inputProximities, const int *const inputXCoordinates,
@@ -126,6 +127,114 @@ namespace latinime {
     return getProximityCodePointsAt(inputProximities, index)[0];
 }
 
+/* static */ void ProximityInfoStateUtils::initPrimaryInputWord(
+        const int inputSize, const int *const inputProximities, int *primaryInputWord) {
+    for (int i = 0; i < inputSize; ++i) {
+        primaryInputWord[i] = getPrimaryCodePointAt(inputProximities, i);
+    }
+}
+
+/* static */ float ProximityInfoStateUtils::calculateSquaredDistanceFromSweetSpotCenter(
+        const ProximityInfo *const proximityInfo, const std::vector<int> *const sampledInputXs,
+        const std::vector<int> *const sampledInputYs, const int keyIndex,
+        const int inputIndex) {
+    const float sweetSpotCenterX = proximityInfo->getSweetSpotCenterXAt(keyIndex);
+    const float sweetSpotCenterY = proximityInfo->getSweetSpotCenterYAt(keyIndex);
+    const float inputX = static_cast<float>((*sampledInputXs)[inputIndex]);
+    const float inputY = static_cast<float>((*sampledInputYs)[inputIndex]);
+    return SQUARE_FLOAT(inputX - sweetSpotCenterX) + SQUARE_FLOAT(inputY - sweetSpotCenterY);
+}
+
+/* static */ float ProximityInfoStateUtils::calculateNormalizedSquaredDistance(
+        const ProximityInfo *const proximityInfo, const std::vector<int> *const sampledInputXs,
+        const std::vector<int> *const sampledInputYs,
+        const int keyIndex, const int inputIndex) {
+    if (keyIndex == NOT_AN_INDEX) {
+        return ProximityInfoParams::NOT_A_DISTANCE_FLOAT;
+    }
+    if (!proximityInfo->hasSweetSpotData(keyIndex)) {
+        return ProximityInfoParams::NOT_A_DISTANCE_FLOAT;
+    }
+    if (NOT_A_COORDINATE == (*sampledInputXs)[inputIndex]) {
+        return ProximityInfoParams::NOT_A_DISTANCE_FLOAT;
+    }
+    const float squaredDistance = calculateSquaredDistanceFromSweetSpotCenter(proximityInfo,
+            sampledInputXs, sampledInputYs, keyIndex, inputIndex);
+    const float squaredRadius = SQUARE_FLOAT(proximityInfo->getSweetSpotRadiiAt(keyIndex));
+    return squaredDistance / squaredRadius;
+}
+
+/* static */ void ProximityInfoStateUtils::initNormalizedSquaredDistances(
+        const ProximityInfo *const proximityInfo, const int inputSize,
+        const int *inputXCoordinates, const int *inputYCoordinates,
+        const int *const inputProximities, const bool hasInputCoordinates,
+        const std::vector<int> *const sampledInputXs,
+        const std::vector<int> *const sampledInputYs,
+        int *normalizedSquaredDistances) {
+    for (int i = 0; i < inputSize; ++i) {
+        const int *proximityCodePoints = getProximityCodePointsAt(inputProximities, i);
+        const int primaryKey = proximityCodePoints[0];
+        const int x = inputXCoordinates[i];
+        const int y = inputYCoordinates[i];
+        if (DEBUG_PROXIMITY_CHARS) {
+            int a = x + y + primaryKey;
+            a += 0;
+            AKLOGI("--- Primary = %c, x = %d, y = %d", primaryKey, x, y);
+        }
+        for (int j = 0; j < MAX_PROXIMITY_CHARS_SIZE && proximityCodePoints[j] > 0;
+                ++j) {
+            const int currentCodePoint = proximityCodePoints[j];
+            const float squaredDistance =
+                    hasInputCoordinates ? calculateNormalizedSquaredDistance(
+                            proximityInfo, sampledInputXs, sampledInputYs,
+                            proximityInfo->getKeyIndexOf(currentCodePoint), i) :
+                            ProximityInfoParams::NOT_A_DISTANCE_FLOAT;
+            if (squaredDistance >= 0.0f) {
+                normalizedSquaredDistances[i * MAX_PROXIMITY_CHARS_SIZE + j] =
+                        (int) (squaredDistance
+                                * ProximityInfoParams::NORMALIZED_SQUARED_DISTANCE_SCALING_FACTOR);
+            } else {
+                normalizedSquaredDistances[i * MAX_PROXIMITY_CHARS_SIZE + j] =
+                        (j == 0) ? EQUIVALENT_CHAR_WITHOUT_DISTANCE_INFO :
+                                PROXIMITY_CHAR_WITHOUT_DISTANCE_INFO;
+            }
+            if (DEBUG_PROXIMITY_CHARS) {
+                AKLOGI("--- Proximity (%d) = %c", j, currentCodePoint);
+            }
+        }
+    }
+
+}
+
+/* static */ void ProximityInfoStateUtils::initGeometricDistanceInfos(
+        const ProximityInfo *const proximityInfo, const int keyCount,
+        const int sampledInputSize, const int lastSavedInputSize,
+        const std::vector<int> *const sampledInputXs,
+        const std::vector<int> *const sampledInputYs,
+        std::vector<NearKeycodesSet> *nearKeysVector,
+        std::vector<NearKeycodesSet> *searchKeysVector,
+        std::vector<float> *distanceCache_G) {
+    nearKeysVector->resize(sampledInputSize);
+    searchKeysVector->resize(sampledInputSize);
+    distanceCache_G->resize(sampledInputSize * keyCount);
+    for (int i = lastSavedInputSize; i < sampledInputSize; ++i) {
+        (*nearKeysVector)[i].reset();
+        (*searchKeysVector)[i].reset();
+        static const float NEAR_KEY_NORMALIZED_SQUARED_THRESHOLD = 4.0f;
+        for (int k = 0; k < keyCount; ++k) {
+            const int index = i * keyCount + k;
+            const int x = (*sampledInputXs)[i];
+            const int y = (*sampledInputYs)[i];
+            const float normalizedSquaredDistance =
+                    proximityInfo->getNormalizedSquaredDistanceFromCenterFloatG(k, x, y);
+            (*distanceCache_G)[index] = normalizedSquaredDistance;
+            if (normalizedSquaredDistance < NEAR_KEY_NORMALIZED_SQUARED_THRESHOLD) {
+                (*nearKeysVector)[i][k] = true;
+            }
+        }
+    }
+}
+
 /* static */ void ProximityInfoStateUtils::popInputData(std::vector<int> *sampledInputXs,
         std::vector<int> *sampledInputYs, std::vector<int> *sampledInputTimes,
         std::vector<int> *sampledLengthCache, std::vector<int> *sampledInputIndice) {
@@ -171,7 +280,7 @@ namespace latinime {
             if (i > 0 && j < (*sampledInputIndice)[i - 1]) {
                 break;
             }
-            // TODO: use mLengthCache instead?
+            // TODO: use mSampledLengthCache instead?
             length += getDistanceInt(xCoordinates[j], yCoordinates[j],
                     xCoordinates[j + 1], yCoordinates[j + 1]);
             duration += times[j + 1] - times[j];
@@ -473,7 +582,7 @@ namespace latinime {
     if (DEBUG_DOUBLE_LETTER) {
         AKLOGI("--- (%d, %d) double letter: start = %d, end = %d, dist = %d, time = %d,"
                 " speed = %f, ave = %f, val = %f, start time = %d, end time = %d",
-                id, mInputIndice[id], start, end, beelineDistance, time,
+                id, mSampledInputIndice[id], start, end, beelineDistance, time,
                 (static_cast<float>(beelineDistance) / static_cast<float>(time)), mAverageSpeed,
                 ((static_cast<float>(beelineDistance) / static_cast<float>(time))
                         / mAverageSpeed), adjustedStartTime, adjustedEndTime);
@@ -849,4 +958,45 @@ namespace latinime {
     }
     return true;
 }
+
+/* static */ void ProximityInfoStateUtils::dump(const bool isGeometric, const int inputSize,
+        const int *const inputXCoordinates, const int *const inputYCoordinates,
+        const int sampledInputSize, const std::vector<int> *const sampledInputXs,
+        const std::vector<int> *const sampledInputYs,
+        const std::vector<float> *const sampledSpeedRates,
+        const std::vector<int> *const sampledBeelineSpeedPercentiles) {
+    if (DEBUG_GEO_FULL) {
+        for (int i = 0; i < sampledInputSize; ++i) {
+            AKLOGI("Sampled(%d): x = %d, y = %d, time = %d", i, mSampledInputXs[i],
+                    mSampledInputYs[i], mSampledTimes ? mSampledTimes[i], -1);
+        }
+    }
+
+    std::stringstream originalX, originalY, sampledX, sampledY;
+    for (int i = 0; i < inputSize; ++i) {
+        originalX << inputXCoordinates[i];
+        originalY << inputYCoordinates[i];
+        if (i != inputSize - 1) {
+            originalX << ";";
+            originalY << ";";
+        }
+    }
+    AKLOGI("===== sampled points =====");
+    for (int i = 0; i < sampledInputSize; ++i) {
+        if (isGeometric) {
+            AKLOGI("%d: x = %d, y = %d, time = %d, relative speed = %.4f, beeline speed = %d",
+                    i, mSampledInputXs[i], mSampledInputYs[i], mSampledTimes[i], mSpeedRates[i],
+                    getBeelineSpeedPercentile(i));
+        }
+        sampledX << (*sampledInputXs)[i];
+        sampledY << (*sampledInputYs)[i];
+        if (i != sampledInputSize - 1) {
+            sampledX << ";";
+            sampledY << ";";
+        }
+    }
+    AKLOGI("original points:\n%s, %s,\nsampled points:\n%s, %s,\n",
+            originalX.str().c_str(), originalY.str().c_str(), sampledX.str().c_str(),
+            sampledY.str().c_str());
+}
 } // namespace latinime
diff --git a/native/jni/src/proximity_info_state_utils.h b/native/jni/src/proximity_info_state_utils.h
index 8241eaf892..b67f82cd63 100644
--- a/native/jni/src/proximity_info_state_utils.h
+++ b/native/jni/src/proximity_info_state_utils.h
@@ -78,7 +78,29 @@ class ProximityInfoStateUtils {
     static float getPointToKeyByIdLength(const float maxPointToKeyLength,
             const std::vector<float> *const distanceCache_G, const int keyCount,
             const int inputIndex, const int keyId);
-
+    static void initGeometricDistanceInfos(
+            const ProximityInfo *const proximityInfo, const int keyCount,
+            const int sampledInputSize, const int lastSavedInputSize,
+            const std::vector<int> *const sampledInputXs,
+            const std::vector<int> *const sampledInputYs,
+            std::vector<NearKeycodesSet> *nearKeysVector,
+            std::vector<NearKeycodesSet> *searchKeysVector,
+            std::vector<float> *distanceCache_G);
+    static void initPrimaryInputWord(
+            const int inputSize, const int *const inputProximities, int *primaryInputWord);
+    static void initNormalizedSquaredDistances(
+            const ProximityInfo *const proximityInfo, const int inputSize,
+            const int *inputXCoordinates, const int *inputYCoordinates,
+            const int *const inputProximities, const bool hasInputCoordinates,
+            const std::vector<int> *const sampledInputXs,
+            const std::vector<int> *const sampledInputYs,
+            int *normalizedSquaredDistances);
+    static void dump(const bool isGeometric, const int inputSize,
+            const int *const inputXCoordinates, const int *const inputYCoordinates,
+            const int sampledInputSize, const std::vector<int> *const sampledInputXs,
+            const std::vector<int> *const sampledInputYs,
+            const std::vector<float> *const sampledSpeedRates,
+            const std::vector<int> *const sampledBeelineSpeedPercentiles);
  private:
     DISALLOW_IMPLICIT_CONSTRUCTORS(ProximityInfoStateUtils);
 
@@ -121,6 +143,13 @@ class ProximityInfoStateUtils {
             const int sampledInputSize, const std::vector<int> *const lengthCache,
             const int index0, const int index1,
             std::vector<hash_map_compat<int, float> > *charProbabilities);
+    static float calculateSquaredDistanceFromSweetSpotCenter(
+            const ProximityInfo *const proximityInfo, const std::vector<int> *const sampledInputXs,
+            const std::vector<int> *const sampledInputYs, const int keyIndex,
+            const int inputIndex);
+     static float calculateNormalizedSquaredDistance(
+            const ProximityInfo *const proximityInfo, const std::vector<int> *const sampledInputXs,
+            const std::vector<int> *const sampledInputYs, const int keyIndex, const int inputIndex);
 };
 } // namespace latinime
 #endif // LATINIME_PROXIMITY_INFO_STATE_UTILS_H
diff --git a/native/jni/src/suggest_utils.h b/native/jni/src/suggest_utils.h
index 42cc5dea03..7d49cde7ea 100644
--- a/native/jni/src/suggest_utils.h
+++ b/native/jni/src/suggest_utils.h
@@ -18,6 +18,7 @@
 #define LATINIME_SUGGEST_UTILS_H
 
 #include "defines.h"
+#include "proximity_info_params.h"
 #include "proximity_info_state.h"
 
 namespace latinime {
@@ -35,7 +36,7 @@ class SuggestUtils {
         static const float R1 = NEUTRAL_SCORE_SQUARED_RADIUS;
         static const float R2 = HALF_SCORE_SQUARED_RADIUS;
         const float x = normalizedSquaredDistance / static_cast<float>(
-                ProximityInfoState::NORMALIZED_SQUARED_DISTANCE_SCALING_FACTOR);
+                ProximityInfoParams::NORMALIZED_SQUARED_DISTANCE_SCALING_FACTOR);
         const float factor = max((x < R1)
                 ? (A * (R1 - x) + B * x) / R1
                 : (B * (R2 - x) + C * (x - R1)) / (R2 - R1), MIN);
-- 
GitLab