diff options
Diffstat (limited to 'native/src/correction.cpp')
-rw-r--r-- | native/src/correction.cpp | 113 |
1 files changed, 57 insertions, 56 deletions
diff --git a/native/src/correction.cpp b/native/src/correction.cpp index a08a21bd2..31493ee7d 100644 --- a/native/src/correction.cpp +++ b/native/src/correction.cpp @@ -118,7 +118,6 @@ bool Correction::initProcessState(const int outputIndex) { mInputIndex = mCorrectionStates[outputIndex].mInputIndex; mNeedsToTraverseAllNodes = mCorrectionStates[outputIndex].mNeedsToTraverseAllNodes; - mSumOfDistance = mCorrectionStates[outputIndex].mSumOfDistance; mEquivalentCharCount = mCorrectionStates[outputIndex].mEquivalentCharCount; mProximityCount = mCorrectionStates[outputIndex].mProximityCount; mTransposedCount = mCorrectionStates[outputIndex].mTransposedCount; @@ -174,7 +173,6 @@ void Correction::incrementOutputIndex() { mCorrectionStates[mOutputIndex].mInputIndex = mInputIndex; mCorrectionStates[mOutputIndex].mNeedsToTraverseAllNodes = mNeedsToTraverseAllNodes; - mCorrectionStates[mOutputIndex].mSumOfDistance = mSumOfDistance; mCorrectionStates[mOutputIndex].mEquivalentCharCount = mEquivalentCharCount; mCorrectionStates[mOutputIndex].mProximityCount = mProximityCount; mCorrectionStates[mOutputIndex].mTransposedCount = mTransposedCount; @@ -227,20 +225,26 @@ Correction::CorrectionType Correction::processCharAndCalcState( // TODO: Change the limit if we'll allow two or more corrections const bool noCorrectionsHappenedSoFar = correctionCount == 0; const bool canTryCorrection = noCorrectionsHappenedSoFar; + int proximityIndex = 0; + mDistances[mOutputIndex] = NOT_A_DISTANCE; if (mNeedsToTraverseAllNodes || isQuote(c)) { bool incremented = false; if (mLastCharExceeded && mInputIndex == mInputLength - 1) { // TODO: Do not check the proximity if EditDistance exceeds the threshold const ProximityInfo::ProximityType matchId = - mProximityInfo->getMatchedProximityId(mInputIndex, c, true); + mProximityInfo->getMatchedProximityId(mInputIndex, c, true, &proximityIndex); if (isEquivalentChar(matchId)) { mLastCharExceeded = false; --mExcessiveCount; + mDistances[mOutputIndex] = + mProximityInfo->getNormalizedSquaredDistance(mInputIndex, 0); } else if (matchId == ProximityInfo::NEAR_PROXIMITY_CHAR) { mLastCharExceeded = false; --mExcessiveCount; ++mProximityCount; + mDistances[mOutputIndex] = + mProximityInfo->getNormalizedSquaredDistance(mInputIndex, proximityIndex); } incrementInputIndex(); incremented = true; @@ -301,7 +305,8 @@ Correction::CorrectionType Correction::processCharAndCalcState( const bool checkProximityChars = noCorrectionsHappenedSoFar || mProximityCount == 0; ProximityInfo::ProximityType matchedProximityCharId = secondTransposing ? ProximityInfo::EQUIVALENT_CHAR - : mProximityInfo->getMatchedProximityId(mInputIndex, c, checkProximityChars); + : mProximityInfo->getMatchedProximityId( + mInputIndex, c, checkProximityChars, &proximityIndex); if (ProximityInfo::UNRELATED_CHAR == matchedProximityCharId) { if (canTryCorrection && mOutputIndex > 0 @@ -323,8 +328,8 @@ Correction::CorrectionType Correction::processCharAndCalcState( // Here, we are doing something equivalent to matchedProximityCharId, // but we already know that "excessive char correction" just happened // so that we just need to check "mProximityCount == 0". - matchedProximityCharId = - mProximityInfo->getMatchedProximityId(mInputIndex, c, mProximityCount == 0); + matchedProximityCharId = mProximityInfo->getMatchedProximityId( + mInputIndex, c, mProximityCount == 0, &proximityIndex); } } @@ -399,17 +404,12 @@ Correction::CorrectionType Correction::processCharAndCalcState( } else if (isEquivalentChar(matchedProximityCharId)) { mMatching = true; ++mEquivalentCharCount; - if (mSumOfDistance != NOT_A_DISTANCE) { - const int distance = mProximityInfo->getNormalizedSquaredDistance(mInputIndex); - if (distance != NOT_A_DISTANCE) { - mSumOfDistance += distance; - } else { - mSumOfDistance = NOT_A_DISTANCE; - } - } + mDistances[mOutputIndex] = mProximityInfo->getNormalizedSquaredDistance(mInputIndex, 0); } else if (ProximityInfo::NEAR_PROXIMITY_CHAR == matchedProximityCharId) { mProximityMatching = true; ++mProximityCount; + mDistances[mOutputIndex] = + mProximityInfo->getNormalizedSquaredDistance(mInputIndex, proximityIndex); } mWord[mOutputIndex] = c; @@ -583,8 +583,6 @@ int Correction::RankingAlgorithm::calculateFinalFreq(const int inputIndex, const const int transposedCount = correction->mTransposedCount / 2; const int excessiveCount = correction->mExcessiveCount + correction->mTransposedCount % 2; const int proximityMatchedCount = correction->mProximityCount; - const int mSumOfDistance = correction->mSumOfDistance; - const int mEquivalentCharCount = correction->mEquivalentCharCount; const bool lastCharExceeded = correction->mLastCharExceeded; const bool useFullEditDistance = correction->mUseFullEditDistance; const int outputLength = outputIndex + 1; @@ -684,47 +682,50 @@ int Correction::RankingAlgorithm::calculateFinalFreq(const int inputIndex, const } } - // Promotion for a word with proximity characters - for (int i = 0; i < adjustedProximityMatchedCount; ++i) { - // A word with proximity corrections - if (DEBUG_DICT_FULL) { - LOGI("Found a proximity correction."); + // Score calibration by touch coordinates is being done only for pure-fat finger typing error + // cases. + // TODO: Remove this constraint. + if (CALIBRATE_SCORE_BY_TOUCH_COORDINATES && proximityInfo->touchPositionCorrectionEnabled() + && skippedCount == 0 && excessiveCount == 0 && transposedCount == 0) { + for (int i = 0; i < outputLength; ++i) { + const int squaredDistance = correction->mDistances[i]; + if (i < adjustedProximityMatchedCount) { + multiplyIntCapped(typedLetterMultiplier, &finalFreq); + } + if (squaredDistance >= 0) { + // Promote or demote the score according to the distance from the sweet spot + static const float A = ZERO_DISTANCE_PROMOTION_RATE / 100.0f; + static const float B = 1.0f; + static const float C = 0.5f; + static const float R1 = NEUTRAL_SCORE_SQUARED_RADIUS; + static const float R2 = HALF_SCORE_SQUARED_RADIUS; + const float x = (float)squaredDistance + / ProximityInfo::NORMALIZED_SQUARED_DISTANCE_SCALING_FACTOR; + const float factor = (x < R1) + ? (A * (R1 - x) + B * x) / R1 + : (B * (R2 - x) + C * (x - R1)) / (R2 - R1); + // factor is piecewise linear function like: + // A -_ . + // ^-_ . + // B \ . + // \ . + // C \ . + // 0 R1 R2 + multiplyRate((int)(factor * 100), &finalFreq); + } else if (squaredDistance == PROXIMITY_CHAR_WITHOUT_DISTANCE_INFO) { + multiplyRate(WORDS_WITH_PROXIMITY_CHARACTER_DEMOTION_RATE, &finalFreq); + } + } + } else { + // Promotion for a word with proximity characters + for (int i = 0; i < adjustedProximityMatchedCount; ++i) { + // A word with proximity corrections + if (DEBUG_DICT_FULL) { + LOGI("Found a proximity correction."); + } + multiplyIntCapped(typedLetterMultiplier, &finalFreq); + multiplyRate(WORDS_WITH_PROXIMITY_CHARACTER_DEMOTION_RATE, &finalFreq); } - multiplyIntCapped(typedLetterMultiplier, &finalFreq); - multiplyRate(WORDS_WITH_PROXIMITY_CHARACTER_DEMOTION_RATE, &finalFreq); - } - - if (CALIBRATE_SCORE_BY_TOUCH_COORDINATES - && mEquivalentCharCount > 0 && mSumOfDistance != NOT_A_DISTANCE) { - // Let (x, y) be the coordinate of a user's touch, and let c be a key. - // Assuming users' touch distribution is gauss distribution, the conditional probability of - // the user touching (x, y) given he or she intends to hit c is: - // p(x, y | c) = exp(-(x - m_x) / (2 * s^2)) / (sqrt(2 * pi) * s) - // * exp(-(y - m_y) / (2 * s^2)) / (sqrt(2 * pi) * s) - // where (m_x, m_y) is a mean of touches of c, and s is a variance of touches of c. - // If user touches c1, c2, .., cn, the joint distribution is - // p(x1, y1 | c1) * p(x2, y2 | c2) * ... * p(xn, yn | cn) - // We consider the logarithm of this value, that is - // sum_i log p(x_i, y_i | c_i) + const - // = sum_i ((x_i - m_x)^2 + (y_i - m_y)^2) / (2 * s^2) + const - // Thus, we use the sum of squared distance as a score of the word. - static const int UPPER = WORDS_WITH_EQUIVALENT_CHAR_STRONGEST_PROMOTION_RATE; - static const int LOWER = WORDS_WITH_EQUIVALENT_CHAR_WEAKEST_DEMOTION_RATE; - static const int MIDDLE = 100; - static const int SHIFT = ProximityInfo::NORMALIZED_SQUARED_DISTANCE_SCALING_FACTOR_LOG_2; - const int expected = mEquivalentCharCount << SHIFT; - // factor is a function as described below: - // U\ . - // \ . - // M \ . - // \ . - // L \------- . - // 0 e - // (x-axis is mSumOfDistance, y-axis is rate, - // and e, U, M, L are expected, UPPER, MIDDLE, LOWER respectively. - const int factor = - max((UPPER * expected - (UPPER - MIDDLE) * mSumOfDistance) / expected, LOWER); - multiplyRate(factor, &finalFreq); } const int errorCount = adjustedProximityMatchedCount > 0 |