/* * Copyright (C) 2013 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "utils/autocorrection_threshold_utils.h" #include #include #include "defines.h" #include "suggest/policyimpl/utils/edit_distance.h" #include "suggest/policyimpl/utils/damerau_levenshtein_edit_distance_policy.h" namespace latinime { const int AutocorrectionThresholdUtils::MAX_INITIAL_SCORE = 255; const int AutocorrectionThresholdUtils::TYPED_LETTER_MULTIPLIER = 2; const int AutocorrectionThresholdUtils::FULL_WORD_MULTIPLIER = 2; /* static */ int AutocorrectionThresholdUtils::editDistance(const int *before, const int beforeLength, const int *after, const int afterLength) { const DamerauLevenshteinEditDistancePolicy daemaruLevenshtein( before, beforeLength, after, afterLength); return static_cast(EditDistance::getEditDistance(&daemaruLevenshtein)); } // In dictionary.cpp, getSuggestion() method, // When USE_SUGGEST_INTERFACE_FOR_TYPING is true: // // // TODO: Revise the following logic thoroughly by referring to the logic // // marked as "Otherwise" below. // SUGGEST_INTERFACE_OUTPUT_SCALE was multiplied to the original suggestion scores to convert // them to integers. // score = (int)((original score) * SUGGEST_INTERFACE_OUTPUT_SCALE) // Undo the scaling here to recover the original score. // normalizedScore = ((float)score) / SUGGEST_INTERFACE_OUTPUT_SCALE // // Otherwise: suggestion scores are computed using the below formula. // original score // := powf(mTypedLetterMultiplier (this is defined 2), // (the number of matched characters between typed word and suggested word)) // * (individual word's score which defined in the unigram dictionary, // and this score is defined in range [0, 255].) // Then, the following processing is applied. // - If the dictionary word is matched up to the point of the user entry // (full match up to min(before.length(), after.length()) // => Then multiply by FULL_MATCHED_WORDS_PROMOTION_RATE (this is defined 1.2) // - If the word is a true full match except for differences in accents or // capitalization, then treat it as if the score was 255. // - If before.length() == after.length() // => multiply by mFullWordMultiplier (this is defined 2)) // So, maximum original score is powf(2, min(before.length(), after.length())) * 255 * 2 * 1.2 // For historical reasons we ignore the 1.2 modifier (because the measure for a good // autocorrection threshold was done at a time when it didn't exist). This doesn't change // the result. // So, we can normalize original score by dividing powf(2, min(b.l(),a.l())) * 255 * 2. /* static */ float AutocorrectionThresholdUtils::calcNormalizedScore(const int *before, const int beforeLength, const int *after, const int afterLength, const int score) { if (0 == beforeLength || 0 == afterLength) { return 0.0f; } const int distance = editDistance(before, beforeLength, after, afterLength); int spaceCount = 0; for (int i = 0; i < afterLength; ++i) { if (after[i] == KEYCODE_SPACE) { ++spaceCount; } } if (spaceCount == afterLength) { return 0.0f; } if (score <= 0 || distance >= afterLength) { // normalizedScore must be 0.0f (the minimum value) if the score is less than or equal to 0, // or if the edit distance is larger than or equal to afterLength. return 0.0f; } // add a weight based on edit distance. const float weight = 1.0f - static_cast(distance) / static_cast(afterLength); // TODO: Revise the following logic thoroughly by referring to... if (true /* USE_SUGGEST_INTERFACE_FOR_TYPING */) { return (static_cast(score) / SUGGEST_INTERFACE_OUTPUT_SCALE) * weight; } // ...this logic. const float maxScore = score >= S_INT_MAX ? static_cast(S_INT_MAX) : static_cast(MAX_INITIAL_SCORE) * powf(static_cast(TYPED_LETTER_MULTIPLIER), static_cast(std::min(beforeLength, afterLength - spaceCount))) * static_cast(FULL_WORD_MULTIPLIER); return (static_cast(score) / maxScore) * weight; } } // namespace latinime