UserHistoryForgettingCurveUtils.java revision 607a9244861ee22c25aaea6ffdfa19fccf497b0b
1/* 2 * Copyright (C) 2012 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 17package com.android.inputmethod.latin; 18 19public class UserHistoryForgettingCurveUtils { 20 private static final int FC_FREQ_MAX = 127; 21 /* package */ static final int COUNT_MAX = 3; 22 private static final int FC_LEVEL_MAX = 3; 23 /* package */ static final int ELAPSED_TIME_MAX = 15; 24 private static final int ELAPSED_TIME_INTERVAL_HOURS = 6; 25 private static final int HALF_LIFE_HOURS = 48; 26 27 /* package */ static int fcToElapsedTime(byte fc) { 28 return fc & 0x0F; 29 } 30 31 /* package */ static int fcToCount(byte fc) { 32 return (fc >> 4) & 0x03; 33 } 34 35 /* package */ static int fcToLevel(byte fc) { 36 return (fc >> 6) & 0x03; 37 } 38 39 private static int calcFreq(int elapsedTime, int count, int level) { 40 if (level <= 0) { 41 // Reserved words, just return 0 42 return 0; 43 } 44 if (count == COUNT_MAX) { 45 // Temporary promote because it's frequently typed recently 46 ++level; 47 } 48 final int et = Math.min(FC_FREQ_MAX, Math.max(0, elapsedTime)); 49 final int l = Math.min(FC_LEVEL_MAX, Math.max(0, level)); 50 return MathUtils.SCORE_TABLE[l - 1][et]; 51 } 52 53 /* pakcage */ static byte calcFc(int elapsedTime, int count, int level) { 54 final int et = Math.min(FC_FREQ_MAX, Math.max(0, elapsedTime)); 55 final int c = Math.min(COUNT_MAX, Math.max(0, count)); 56 final int l = Math.min(FC_LEVEL_MAX, Math.max(0, level)); 57 return (byte)(et | (c << 4) | (l << 6)); 58 } 59 60 public static int fcToFreq(byte fc) { 61 final int elapsedTime = fcToElapsedTime(fc); 62 final int count = fcToCount(fc); 63 final int level = fcToLevel(fc); 64 return calcFreq(elapsedTime, count, level); 65 } 66 67 public static byte pushElapsedTime(byte fc) { 68 int elapsedTime = fcToElapsedTime(fc); 69 int count = fcToCount(fc); 70 int level = fcToLevel(fc); 71 if (elapsedTime >= ELAPSED_TIME_MAX) { 72 // Downgrade level 73 elapsedTime = 0; 74 count = COUNT_MAX; 75 --level; 76 } else { 77 ++elapsedTime; 78 } 79 return calcFc(elapsedTime, count, level); 80 } 81 82 public static byte pushCount(byte fc, boolean isValid) { 83 final int elapsedTime = fcToElapsedTime(fc); 84 int count = fcToCount(fc); 85 int level = fcToLevel(fc); 86 if ((elapsedTime == 0 && count >= COUNT_MAX) || (isValid && level == 0)) { 87 // Upgrade level 88 ++level; 89 count = 0; 90 } else { 91 ++count; 92 } 93 return calcFc(0, count, level); 94 } 95 96 private static class MathUtils { 97 public static final int[][] SCORE_TABLE = new int[FC_LEVEL_MAX][ELAPSED_TIME_MAX + 1]; 98 static { 99 for (int i = 0; i < FC_LEVEL_MAX; ++i) { 100 final double initialFreq; 101 if (i >= 2) { 102 initialFreq = (double)FC_FREQ_MAX; 103 } else if (i == 1) { 104 initialFreq = (double)FC_FREQ_MAX / 2; 105 } else if (i == 0) { 106 initialFreq = (double)FC_FREQ_MAX / 4; 107 } else { 108 continue; 109 } 110 for (int j = 0; j < ELAPSED_TIME_MAX; ++j) { 111 final double elapsedHour = j * ELAPSED_TIME_INTERVAL_HOURS; 112 final double freq = 113 initialFreq * Math.pow(initialFreq, elapsedHour / HALF_LIFE_HOURS); 114 final int intFreq = Math.min(FC_FREQ_MAX, Math.max(0, (int)freq)); 115 SCORE_TABLE[i][j] = intFreq; 116 } 117 } 118 } 119 } 120} 121