1bc5688506229bd5cd5e6f4dcdc73c21dc6b80ecbSatoshi Kataoka/*
2bc5688506229bd5cd5e6f4dcdc73c21dc6b80ecbSatoshi Kataoka * Copyright (C) 2012 The Android Open Source Project
3bc5688506229bd5cd5e6f4dcdc73c21dc6b80ecbSatoshi Kataoka *
4bc5688506229bd5cd5e6f4dcdc73c21dc6b80ecbSatoshi Kataoka * Licensed under the Apache License, Version 2.0 (the "License");
5bc5688506229bd5cd5e6f4dcdc73c21dc6b80ecbSatoshi Kataoka * you may not use this file except in compliance with the License.
6bc5688506229bd5cd5e6f4dcdc73c21dc6b80ecbSatoshi Kataoka * You may obtain a copy of the License at
7bc5688506229bd5cd5e6f4dcdc73c21dc6b80ecbSatoshi Kataoka *
8bc5688506229bd5cd5e6f4dcdc73c21dc6b80ecbSatoshi Kataoka *      http://www.apache.org/licenses/LICENSE-2.0
9bc5688506229bd5cd5e6f4dcdc73c21dc6b80ecbSatoshi Kataoka *
10bc5688506229bd5cd5e6f4dcdc73c21dc6b80ecbSatoshi Kataoka * Unless required by applicable law or agreed to in writing, software
11bc5688506229bd5cd5e6f4dcdc73c21dc6b80ecbSatoshi Kataoka * distributed under the License is distributed on an "AS IS" BASIS,
12bc5688506229bd5cd5e6f4dcdc73c21dc6b80ecbSatoshi Kataoka * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13bc5688506229bd5cd5e6f4dcdc73c21dc6b80ecbSatoshi Kataoka * See the License for the specific language governing permissions and
14bc5688506229bd5cd5e6f4dcdc73c21dc6b80ecbSatoshi Kataoka * limitations under the License.
15bc5688506229bd5cd5e6f4dcdc73c21dc6b80ecbSatoshi Kataoka */
16bc5688506229bd5cd5e6f4dcdc73c21dc6b80ecbSatoshi Kataoka
17ffcbbaf12788a9fc9398607a548e552d7d2bf05eSatoshi Kataokapackage com.android.inputmethod.latin.personalization;
18bc5688506229bd5cd5e6f4dcdc73c21dc6b80ecbSatoshi Kataoka
19bc5688506229bd5cd5e6f4dcdc73c21dc6b80ecbSatoshi Kataokaimport android.util.Log;
20bc5688506229bd5cd5e6f4dcdc73c21dc6b80ecbSatoshi Kataoka
21b6ca354431367b625daf9fff5fbe4b1f5ef996abKen Wakasaimport com.android.inputmethod.annotations.UsedForTesting;
22e28eba5074664d5716b8e58b8d0a235746b261ebKen Wakasaimport com.android.inputmethod.latin.utils.CollectionUtils;
23b6ca354431367b625daf9fff5fbe4b1f5ef996abKen Wakasa
24bc5688506229bd5cd5e6f4dcdc73c21dc6b80ecbSatoshi Kataokaimport java.util.HashMap;
25bc5688506229bd5cd5e6f4dcdc73c21dc6b80ecbSatoshi Kataokaimport java.util.Set;
26bc5688506229bd5cd5e6f4dcdc73c21dc6b80ecbSatoshi Kataoka
27bc5688506229bd5cd5e6f4dcdc73c21dc6b80ecbSatoshi Kataoka/**
28bc5688506229bd5cd5e6f4dcdc73c21dc6b80ecbSatoshi Kataoka * A store of bigrams which will be updated when the user history dictionary is closed
29bc5688506229bd5cd5e6f4dcdc73c21dc6b80ecbSatoshi Kataoka * All bigrams including stale ones in SQL DB should be stored in this class to avoid adding stale
30bc5688506229bd5cd5e6f4dcdc73c21dc6b80ecbSatoshi Kataoka * bigrams when we write to the SQL DB.
31bc5688506229bd5cd5e6f4dcdc73c21dc6b80ecbSatoshi Kataoka */
32b6ca354431367b625daf9fff5fbe4b1f5ef996abKen Wakasa@UsedForTesting
33a28a05e971cc242b338331a3b78276fa95188d19Tadashi G. Takaokapublic final class UserHistoryDictionaryBigramList {
34a8c13e7942ed88f58b534f2f853dafb804a72894Satoshi Kataoka    public static final byte FORGETTING_CURVE_INITIAL_VALUE = 0;
35bc5688506229bd5cd5e6f4dcdc73c21dc6b80ecbSatoshi Kataoka    private static final String TAG = UserHistoryDictionaryBigramList.class.getSimpleName();
365f282ea9e4a4590fcbab6e27d5fca7dacbb40a6aTadashi G. Takaoka    private static final HashMap<String, Byte> EMPTY_BIGRAM_MAP = CollectionUtils.newHashMap();
375f282ea9e4a4590fcbab6e27d5fca7dacbb40a6aTadashi G. Takaoka    private final HashMap<String, HashMap<String, Byte>> mBigramMap = CollectionUtils.newHashMap();
38bc5688506229bd5cd5e6f4dcdc73c21dc6b80ecbSatoshi Kataoka    private int mSize = 0;
39bc5688506229bd5cd5e6f4dcdc73c21dc6b80ecbSatoshi Kataoka
40bc5688506229bd5cd5e6f4dcdc73c21dc6b80ecbSatoshi Kataoka    public void evictAll() {
41bc5688506229bd5cd5e6f4dcdc73c21dc6b80ecbSatoshi Kataoka        mSize = 0;
42bc5688506229bd5cd5e6f4dcdc73c21dc6b80ecbSatoshi Kataoka        mBigramMap.clear();
43bc5688506229bd5cd5e6f4dcdc73c21dc6b80ecbSatoshi Kataoka    }
44bc5688506229bd5cd5e6f4dcdc73c21dc6b80ecbSatoshi Kataoka
45a836808f8b6b4cf3d5ff2cf93f079763fca86abbSatoshi Kataoka    /**
46a836808f8b6b4cf3d5ff2cf93f079763fca86abbSatoshi Kataoka     * Called when the user typed a word.
47a836808f8b6b4cf3d5ff2cf93f079763fca86abbSatoshi Kataoka     */
486e04d6593239e841f5dac0d3f32d613967c11e22Keisuke Kuroyanagi    @UsedForTesting
49bc5688506229bd5cd5e6f4dcdc73c21dc6b80ecbSatoshi Kataoka    public void addBigram(String word1, String word2) {
50a8c13e7942ed88f58b534f2f853dafb804a72894Satoshi Kataoka        addBigram(word1, word2, FORGETTING_CURVE_INITIAL_VALUE);
51a8c13e7942ed88f58b534f2f853dafb804a72894Satoshi Kataoka    }
52a8c13e7942ed88f58b534f2f853dafb804a72894Satoshi Kataoka
53a836808f8b6b4cf3d5ff2cf93f079763fca86abbSatoshi Kataoka    /**
54a836808f8b6b4cf3d5ff2cf93f079763fca86abbSatoshi Kataoka     * Called when loaded from the SQL DB.
55a836808f8b6b4cf3d5ff2cf93f079763fca86abbSatoshi Kataoka     */
56a8c13e7942ed88f58b534f2f853dafb804a72894Satoshi Kataoka    public void addBigram(String word1, String word2, byte fcValue) {
575ef6209656c51df0f0542d2a75c2df93c8d0f027Keisuke Kuroyanagi        if (DecayingExpandableBinaryDictionaryBase.DBG_SAVE_RESTORE) {
58a836808f8b6b4cf3d5ff2cf93f079763fca86abbSatoshi Kataoka            Log.d(TAG, "--- add bigram: " + word1 + ", " + word2 + ", " + fcValue);
59bc5688506229bd5cd5e6f4dcdc73c21dc6b80ecbSatoshi Kataoka        }
60a8c13e7942ed88f58b534f2f853dafb804a72894Satoshi Kataoka        final HashMap<String, Byte> map;
61bc5688506229bd5cd5e6f4dcdc73c21dc6b80ecbSatoshi Kataoka        if (mBigramMap.containsKey(word1)) {
62a8c13e7942ed88f58b534f2f853dafb804a72894Satoshi Kataoka            map = mBigramMap.get(word1);
63bc5688506229bd5cd5e6f4dcdc73c21dc6b80ecbSatoshi Kataoka        } else {
645f282ea9e4a4590fcbab6e27d5fca7dacbb40a6aTadashi G. Takaoka            map = CollectionUtils.newHashMap();
65a8c13e7942ed88f58b534f2f853dafb804a72894Satoshi Kataoka            mBigramMap.put(word1, map);
66bc5688506229bd5cd5e6f4dcdc73c21dc6b80ecbSatoshi Kataoka        }
67a8c13e7942ed88f58b534f2f853dafb804a72894Satoshi Kataoka        if (!map.containsKey(word2)) {
68bc5688506229bd5cd5e6f4dcdc73c21dc6b80ecbSatoshi Kataoka            ++mSize;
69a8c13e7942ed88f58b534f2f853dafb804a72894Satoshi Kataoka            map.put(word2, fcValue);
70bc5688506229bd5cd5e6f4dcdc73c21dc6b80ecbSatoshi Kataoka        }
71bc5688506229bd5cd5e6f4dcdc73c21dc6b80ecbSatoshi Kataoka    }
72bc5688506229bd5cd5e6f4dcdc73c21dc6b80ecbSatoshi Kataoka
73a836808f8b6b4cf3d5ff2cf93f079763fca86abbSatoshi Kataoka    /**
74a836808f8b6b4cf3d5ff2cf93f079763fca86abbSatoshi Kataoka     * Called when inserted to the SQL DB.
75a836808f8b6b4cf3d5ff2cf93f079763fca86abbSatoshi Kataoka     */
76a836808f8b6b4cf3d5ff2cf93f079763fca86abbSatoshi Kataoka    public void updateBigram(String word1, String word2, byte fcValue) {
775ef6209656c51df0f0542d2a75c2df93c8d0f027Keisuke Kuroyanagi        if (DecayingExpandableBinaryDictionaryBase.DBG_SAVE_RESTORE) {
78a836808f8b6b4cf3d5ff2cf93f079763fca86abbSatoshi Kataoka            Log.d(TAG, "--- update bigram: " + word1 + ", " + word2 + ", " + fcValue);
79a836808f8b6b4cf3d5ff2cf93f079763fca86abbSatoshi Kataoka        }
80a836808f8b6b4cf3d5ff2cf93f079763fca86abbSatoshi Kataoka        final HashMap<String, Byte> map;
81a836808f8b6b4cf3d5ff2cf93f079763fca86abbSatoshi Kataoka        if (mBigramMap.containsKey(word1)) {
82a836808f8b6b4cf3d5ff2cf93f079763fca86abbSatoshi Kataoka            map = mBigramMap.get(word1);
83a836808f8b6b4cf3d5ff2cf93f079763fca86abbSatoshi Kataoka        } else {
84a836808f8b6b4cf3d5ff2cf93f079763fca86abbSatoshi Kataoka            return;
85a836808f8b6b4cf3d5ff2cf93f079763fca86abbSatoshi Kataoka        }
86a836808f8b6b4cf3d5ff2cf93f079763fca86abbSatoshi Kataoka        if (!map.containsKey(word2)) {
87a836808f8b6b4cf3d5ff2cf93f079763fca86abbSatoshi Kataoka            return;
88a836808f8b6b4cf3d5ff2cf93f079763fca86abbSatoshi Kataoka        }
89a836808f8b6b4cf3d5ff2cf93f079763fca86abbSatoshi Kataoka        map.put(word2, fcValue);
90a836808f8b6b4cf3d5ff2cf93f079763fca86abbSatoshi Kataoka    }
91a836808f8b6b4cf3d5ff2cf93f079763fca86abbSatoshi Kataoka
92bc5688506229bd5cd5e6f4dcdc73c21dc6b80ecbSatoshi Kataoka    public int size() {
93bc5688506229bd5cd5e6f4dcdc73c21dc6b80ecbSatoshi Kataoka        return mSize;
94bc5688506229bd5cd5e6f4dcdc73c21dc6b80ecbSatoshi Kataoka    }
95bc5688506229bd5cd5e6f4dcdc73c21dc6b80ecbSatoshi Kataoka
96bc5688506229bd5cd5e6f4dcdc73c21dc6b80ecbSatoshi Kataoka    public boolean isEmpty() {
97bc5688506229bd5cd5e6f4dcdc73c21dc6b80ecbSatoshi Kataoka        return mBigramMap.isEmpty();
98bc5688506229bd5cd5e6f4dcdc73c21dc6b80ecbSatoshi Kataoka    }
99bc5688506229bd5cd5e6f4dcdc73c21dc6b80ecbSatoshi Kataoka
100e5a35711b854aedeeea2f45105b941b9deee49bcSatoshi Kataoka    public boolean containsKey(String word) {
101e5a35711b854aedeeea2f45105b941b9deee49bcSatoshi Kataoka        return mBigramMap.containsKey(word);
102e5a35711b854aedeeea2f45105b941b9deee49bcSatoshi Kataoka    }
103e5a35711b854aedeeea2f45105b941b9deee49bcSatoshi Kataoka
104bc5688506229bd5cd5e6f4dcdc73c21dc6b80ecbSatoshi Kataoka    public Set<String> keySet() {
105bc5688506229bd5cd5e6f4dcdc73c21dc6b80ecbSatoshi Kataoka        return mBigramMap.keySet();
106bc5688506229bd5cd5e6f4dcdc73c21dc6b80ecbSatoshi Kataoka    }
107bc5688506229bd5cd5e6f4dcdc73c21dc6b80ecbSatoshi Kataoka
108a8c13e7942ed88f58b534f2f853dafb804a72894Satoshi Kataoka    public HashMap<String, Byte> getBigrams(String word1) {
109e9a86e2cdb58dd8d5601138294521e966d164520Jean Chalard        if (mBigramMap.containsKey(word1)) return mBigramMap.get(word1);
110e9a86e2cdb58dd8d5601138294521e966d164520Jean Chalard        // TODO: lower case according to locale
111e9a86e2cdb58dd8d5601138294521e966d164520Jean Chalard        final String lowerWord1 = word1.toLowerCase();
112e9a86e2cdb58dd8d5601138294521e966d164520Jean Chalard        if (mBigramMap.containsKey(lowerWord1)) return mBigramMap.get(lowerWord1);
113e9a86e2cdb58dd8d5601138294521e966d164520Jean Chalard        return EMPTY_BIGRAM_MAP;
114bc5688506229bd5cd5e6f4dcdc73c21dc6b80ecbSatoshi Kataoka    }
115bc5688506229bd5cd5e6f4dcdc73c21dc6b80ecbSatoshi Kataoka
116bc5688506229bd5cd5e6f4dcdc73c21dc6b80ecbSatoshi Kataoka    public boolean removeBigram(String word1, String word2) {
117a8c13e7942ed88f58b534f2f853dafb804a72894Satoshi Kataoka        final HashMap<String, Byte> set = getBigrams(word1);
118bc5688506229bd5cd5e6f4dcdc73c21dc6b80ecbSatoshi Kataoka        if (set.isEmpty()) {
119bc5688506229bd5cd5e6f4dcdc73c21dc6b80ecbSatoshi Kataoka            return false;
120bc5688506229bd5cd5e6f4dcdc73c21dc6b80ecbSatoshi Kataoka        }
121a8c13e7942ed88f58b534f2f853dafb804a72894Satoshi Kataoka        if (set.containsKey(word2)) {
122bc5688506229bd5cd5e6f4dcdc73c21dc6b80ecbSatoshi Kataoka            set.remove(word2);
123bc5688506229bd5cd5e6f4dcdc73c21dc6b80ecbSatoshi Kataoka            --mSize;
124bc5688506229bd5cd5e6f4dcdc73c21dc6b80ecbSatoshi Kataoka            return true;
125bc5688506229bd5cd5e6f4dcdc73c21dc6b80ecbSatoshi Kataoka        }
126bc5688506229bd5cd5e6f4dcdc73c21dc6b80ecbSatoshi Kataoka        return false;
127bc5688506229bd5cd5e6f4dcdc73c21dc6b80ecbSatoshi Kataoka    }
128bc5688506229bd5cd5e6f4dcdc73c21dc6b80ecbSatoshi Kataoka}
129