From abdf97f65270c23cceea78af348b895e3b8ce0ab Mon Sep 17 00:00:00 2001 From: zonble Date: Wed, 12 Jan 2022 12:26:24 +0800 Subject: [PATCH] Adds McBopomofoLM as the facade of three language models. - main language model - user phrases - user excluded phrases --- McBopomofo.xcodeproj/project.pbxproj | 6 ++ Source/Engine/FastLM.cpp | 2 +- Source/Engine/FastLM.h | 2 +- .../Engine/Gramambular/BlockReadingBuilder.h | 38 +------- Source/Engine/Gramambular/LanguageModel.h | 2 +- Source/Engine/McBopomofoLM.cpp | 92 +++++++++++++++++++ Source/Engine/McBopomofoLM.h | 31 +++++++ Source/InputMethodController.h | 6 +- Source/InputMethodController.mm | 90 +++++------------- Source/LanguageModelManager.h | 8 +- Source/LanguageModelManager.mm | 71 +++----------- 11 files changed, 178 insertions(+), 170 deletions(-) create mode 100644 Source/Engine/McBopomofoLM.cpp create mode 100644 Source/Engine/McBopomofoLM.h diff --git a/McBopomofo.xcodeproj/project.pbxproj b/McBopomofo.xcodeproj/project.pbxproj index 502946a1..4d0bf37e 100644 --- a/McBopomofo.xcodeproj/project.pbxproj +++ b/McBopomofo.xcodeproj/project.pbxproj @@ -37,6 +37,7 @@ 6AE210B315FC63CC003659FE /* PlainBopomofo@2x.tiff in Resources */ = {isa = PBXBuildFile; fileRef = 6AE210B115FC63CC003659FE /* PlainBopomofo@2x.tiff */; }; 6AFF97F2253B299E007F1C49 /* NonModalAlertWindowController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 6AFF97F0253B299E007F1C49 /* NonModalAlertWindowController.xib */; }; D41355D8278D74B5005E5CBD /* LanguageModelManager.mm in Sources */ = {isa = PBXBuildFile; fileRef = D41355D7278D7409005E5CBD /* LanguageModelManager.mm */; }; + D41355DB278E6D17005E5CBD /* McBopomofoLM.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D41355D9278E6D17005E5CBD /* McBopomofoLM.cpp */; }; D427A9C125ED28CC005D43E0 /* OpenCCBridge.swift in Sources */ = {isa = PBXBuildFile; fileRef = D427A9C025ED28CC005D43E0 /* OpenCCBridge.swift */; }; D427F76A278C9E29004A2160 /* CandidateUI in Frameworks */ = {isa = PBXBuildFile; productRef = D427F769278C9E29004A2160 /* CandidateUI */; }; D427F76C278CA2B0004A2160 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D427F76B278CA1BA004A2160 /* AppDelegate.swift */; }; @@ -158,6 +159,8 @@ 6AFF97F0253B299E007F1C49 /* NonModalAlertWindowController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = NonModalAlertWindowController.xib; sourceTree = ""; }; D41355D6278D7409005E5CBD /* LanguageModelManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LanguageModelManager.h; sourceTree = ""; }; D41355D7278D7409005E5CBD /* LanguageModelManager.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = LanguageModelManager.mm; sourceTree = ""; }; + D41355D9278E6D17005E5CBD /* McBopomofoLM.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = McBopomofoLM.cpp; sourceTree = ""; }; + D41355DA278E6D17005E5CBD /* McBopomofoLM.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = McBopomofoLM.h; sourceTree = ""; }; D427A9BF25ED28CC005D43E0 /* McBopomofo-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "McBopomofo-Bridging-Header.h"; sourceTree = ""; }; D427A9C025ED28CC005D43E0 /* OpenCCBridge.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenCCBridge.swift; sourceTree = ""; }; D427F768278C9D0D004A2160 /* CandidateUI */ = {isa = PBXFileReference; lastKnownFileType = wrapper; name = CandidateUI; path = Packages/CandidateUI; sourceTree = ""; }; @@ -267,6 +270,8 @@ 6A0421A715FEF3F50061ED63 /* FastLM.h */, D47F7DD2278C1263002F9DD7 /* UserOverrideModel.cpp */, D47F7DD1278C1263002F9DD7 /* UserOverrideModel.h */, + D41355D9278E6D17005E5CBD /* McBopomofoLM.cpp */, + D41355DA278E6D17005E5CBD /* McBopomofoLM.h */, ); path = Engine; sourceTree = ""; @@ -553,6 +558,7 @@ D427A9C125ED28CC005D43E0 /* OpenCCBridge.swift in Sources */, D47F7DCE278BFB57002F9DD7 /* PreferencesWindowController.swift in Sources */, 6A0D4ED215FC0D6400ABF4B3 /* InputMethodController.mm in Sources */, + D41355DB278E6D17005E5CBD /* McBopomofoLM.cpp in Sources */, D47F7DD3278C1263002F9DD7 /* UserOverrideModel.cpp in Sources */, 6A0D4F4515FC0EB100ABF4B3 /* Mandarin.cpp in Sources */, 6A0421A815FEF3F50061ED63 /* FastLM.cpp in Sources */, diff --git a/Source/Engine/FastLM.cpp b/Source/Engine/FastLM.cpp index 48569c65..9808142f 100644 --- a/Source/Engine/FastLM.cpp +++ b/Source/Engine/FastLM.cpp @@ -285,7 +285,7 @@ const vector FastLM::bigramsForKeys(const string& preceedingKey, const s return vector(); } -const vector FastLM::unigramsForKeys(const string& key) +const vector FastLM::unigramsForKey(const string& key) { vector v; map >::const_iterator i = keyRowMap.find(key.c_str()); diff --git a/Source/Engine/FastLM.h b/Source/Engine/FastLM.h index 77aac397..69fb8bd9 100644 --- a/Source/Engine/FastLM.h +++ b/Source/Engine/FastLM.h @@ -50,7 +50,7 @@ namespace Formosa { void dump(); virtual const vector bigramsForKeys(const string& preceedingKey, const string& key); - virtual const vector unigramsForKeys(const string& key); + virtual const vector unigramsForKey(const string& key); virtual bool hasUnigramsForKey(const string& key); protected: diff --git a/Source/Engine/Gramambular/BlockReadingBuilder.h b/Source/Engine/Gramambular/BlockReadingBuilder.h index bd3dc2d0..145a0185 100644 --- a/Source/Engine/Gramambular/BlockReadingBuilder.h +++ b/Source/Engine/Gramambular/BlockReadingBuilder.h @@ -38,7 +38,7 @@ namespace Formosa { class BlockReadingBuilder { public: - BlockReadingBuilder(LanguageModel *inLM, LanguageModel *inUserPhraseLM, LanguageModel *inExcludedPhrasesLM); + BlockReadingBuilder(LanguageModel *inLM); void clear(); size_t length() const; @@ -75,17 +75,11 @@ namespace Formosa { Grid m_grid; LanguageModel *m_LM; - LanguageModel *m_userPhraseLM; - LanguageModel *m_excludedPhrasesLM; string m_joinSeparator; }; - inline BlockReadingBuilder::BlockReadingBuilder(LanguageModel *inLM, - LanguageModel *inUserPhraseLM, - LanguageModel *inExcludedPhrasesLM) + inline BlockReadingBuilder::BlockReadingBuilder(LanguageModel *inLM) : m_LM(inLM) - , m_userPhraseLM(inUserPhraseLM) - , m_excludedPhrasesLM(inExcludedPhrasesLM) , m_cursorIndex(0) , m_markerCursorIndex(SIZE_MAX) { @@ -238,33 +232,7 @@ namespace Formosa { for (size_t q = 1 ; q <= MaximumBuildSpanLength && p+q <= end ; q++) { string combinedReading = Join(m_readings.begin() + p, m_readings.begin() + p + q, m_joinSeparator); if (!m_grid.hasNodeAtLocationSpanningLengthMatchingKey(p, q, combinedReading)) { - vector unigrams; - vector userUnigrams; - - if (m_userPhraseLM != NULL && m_userPhraseLM->hasUnigramsForKey(combinedReading)) { - userUnigrams = m_userPhraseLM->unigramsForKeys(combinedReading); - } - - if (m_LM->hasUnigramsForKey(combinedReading)) { - vector globalUnigrams = m_LM->unigramsForKeys(combinedReading); - for (std::vector::iterator it=globalUnigrams.begin(); it!=globalUnigrams.end(); ++it) { - if (!checkIfUnigramExistInVector(*it, unigrams)) { - unigrams.push_back(*it); - } - } - } - unigrams.insert(unigrams.begin(), userUnigrams.begin(), userUnigrams.end()); - - if (m_excludedPhrasesLM != NULL && m_excludedPhrasesLM->hasUnigramsForKey(combinedReading)) { - vector excludedUnigrams = m_excludedPhrasesLM->unigramsForKeys(combinedReading); - vector newUnigram; - for (std::vector::iterator it=unigrams.begin(); it!=unigrams.end(); ++it) { - if (!checkIfUnigramExistInVector(*it, excludedUnigrams)) { - newUnigram.push_back(*it); - } - } - unigrams = newUnigram; - } + vector unigrams = m_LM->unigramsForKey(combinedReading); if (unigrams.size() > 0) { Node n(combinedReading, unigrams, vector()); diff --git a/Source/Engine/Gramambular/LanguageModel.h b/Source/Engine/Gramambular/LanguageModel.h index 46c2e1d4..65331b37 100644 --- a/Source/Engine/Gramambular/LanguageModel.h +++ b/Source/Engine/Gramambular/LanguageModel.h @@ -42,7 +42,7 @@ namespace Formosa { virtual ~LanguageModel() {} virtual const vector bigramsForKeys(const string &preceedingKey, const string& key) = 0; - virtual const vector unigramsForKeys(const string &key) = 0; + virtual const vector unigramsForKey(const string &key) = 0; virtual bool hasUnigramsForKey(const string& key) = 0; }; } diff --git a/Source/Engine/McBopomofoLM.cpp b/Source/Engine/McBopomofoLM.cpp new file mode 100644 index 00000000..e5bc741f --- /dev/null +++ b/Source/Engine/McBopomofoLM.cpp @@ -0,0 +1,92 @@ +#include "McBopomofoLM.h" +#include +#include +#include + +using namespace McBopomofo; + +McBopomofoLM::McBopomofoLM() +{ +} + +McBopomofoLM::~McBopomofoLM() +{ + m_languageModel.close(); + m_userPhrases.close(); + m_excluddePhrases.close(); +} + +void McBopomofoLM::loadLanguageModel(const char* languageModelDataPath) +{ + m_languageModel.close(); + m_languageModel.open(languageModelDataPath); +} + +void McBopomofoLM::loadUserPhrases(const char* userPhrasesDataPath, + const char* excludedPhrasesDataPath) +{ + m_userPhrases.close(); + m_userPhrases.open(userPhrasesDataPath); + m_excluddePhrases.close(); + m_excluddePhrases.open(excludedPhrasesDataPath); +} + +const vector McBopomofoLM::bigramsForKeys(const string& preceedingKey, const string& key) +{ + return vector(); +} + +const vector McBopomofoLM::unigramsForKey(const string& key) +{ + vector unigrams; + vector userUnigrams; + + // Use unordered_set so that you don't have to do O(n*m) + unordered_set excludedValues; + unordered_set userValues; + + if (m_excluddePhrases.hasUnigramsForKey(key)) { + vector excludedUnigrams = m_excluddePhrases.unigramsForKey(key); + transform(excludedUnigrams.begin(), excludedUnigrams.end(), + inserter(excludedValues, excludedValues.end()), + [](const Unigram &u) { return u.keyValue.value; }); + } + + if (m_userPhrases.hasUnigramsForKey(key)) { + vector rawUserUnigrams = m_userPhrases.unigramsForKey(key); + + for (auto&& unigram : rawUserUnigrams) { + if (excludedValues.find(unigram.keyValue.value) == excludedValues.end()) { + userUnigrams.push_back(unigram); + } + } + + transform(userUnigrams.begin(), userUnigrams.end(), + inserter(userValues, userValues.end()), + [](const Unigram &u) { return u.keyValue.value; }); + } + + if (m_languageModel.hasUnigramsForKey(key)) { + vector globalUnigrams = m_languageModel.unigramsForKey(key); + + for (auto&& unigram : globalUnigrams) { + if (excludedValues.find(unigram.keyValue.value) == excludedValues.end() && + userValues.find(unigram.keyValue.value) == userValues.end()) { + unigrams.push_back(unigram); + } + } + } + + unigrams.insert(unigrams.begin(), userUnigrams.begin(), userUnigrams.end()); + return unigrams; +} + +bool McBopomofoLM::hasUnigramsForKey(const string& key) +{ + if (!m_excluddePhrases.hasUnigramsForKey(key)) { + return m_userPhrases.hasUnigramsForKey(key) || + m_languageModel.hasUnigramsForKey(key); + } + + return unigramsForKey(key).size() > 0; +} diff --git a/Source/Engine/McBopomofoLM.h b/Source/Engine/McBopomofoLM.h new file mode 100644 index 00000000..19ad8246 --- /dev/null +++ b/Source/Engine/McBopomofoLM.h @@ -0,0 +1,31 @@ +#ifndef MCBOPOMOFOLM_H +#define MCBOPOMOFOLM_H + +#include +#include "FastLM.h" + +namespace McBopomofo { + +using namespace Formosa::Gramambular; + +class McBopomofoLM : public LanguageModel { +public: + McBopomofoLM(); + ~McBopomofoLM(); + + void loadLanguageModel(const char* languageModelDataPath); + void loadUserPhrases(const char* m_userPhrasesDataPath, + const char* m_excludedPhrasesDataPath); + + const vector bigramsForKeys(const string& preceedingKey, const string& key); + const vector unigramsForKey(const string& key); + bool hasUnigramsForKey(const string& key); + +protected: + FastLM m_languageModel; + FastLM m_userPhrases; + FastLM m_excluddePhrases; +}; +}; + +#endif diff --git a/Source/InputMethodController.h b/Source/InputMethodController.h index a99e248e..404c0ab4 100644 --- a/Source/InputMethodController.h +++ b/Source/InputMethodController.h @@ -36,7 +36,7 @@ #import #import "Mandarin.h" #import "Gramambular.h" -#import "FastLM.h" +#import "McBopomofoLM.h" #import "UserOverrideModel.h" @interface McBopomofoInputMethodController : IMKInputController @@ -46,9 +46,7 @@ Formosa::Mandarin::BopomofoReadingBuffer* _bpmfReadingBuffer; // language model - Formosa::Gramambular::FastLM *_languageModel; - Formosa::Gramambular::FastLM *_userPhrasesModel; - Formosa::Gramambular::FastLM *_excludedPhraseModel; + McBopomofo::McBopomofoLM *_languageModel; // user override model McBopomofo::UserOverrideModel *_userOverrideModel; diff --git a/Source/InputMethodController.mm b/Source/InputMethodController.mm index 32b71d8c..d17ad3e6 100644 --- a/Source/InputMethodController.mm +++ b/Source/InputMethodController.mm @@ -48,6 +48,7 @@ using namespace std; using namespace Formosa::Mandarin; using namespace Formosa::Gramambular; +using namespace McBopomofo; using namespace OpenVanilla; // default, min and max candidate list text size @@ -176,11 +177,9 @@ static double FindHighestScore(const vector& nodes, double epsilon) // create the lattice builder _languageModel = [LanguageModelManager languageModelMcBopomofo]; - _userPhrasesModel = [LanguageModelManager userPhraseLanguageModel]; _userOverrideModel = [LanguageModelManager userOverrideModel]; - _excludedPhraseModel = [LanguageModelManager excludedPhrasesLanguageModelMcBopomofo]; - _builder = new BlockReadingBuilder(_languageModel, _userPhrasesModel, _excludedPhraseModel); + _builder = new BlockReadingBuilder(_languageModel); // each Mandarin syllable is separated by a hyphen _builder->setJoinSeparator("-"); @@ -325,21 +324,15 @@ static double FindHighestScore(const vector& nodes, double epsilon) - (void)setValue:(id)value forTag:(long)tag client:(id)sender { NSString *newInputMode; - FastLM *newLanguageModel; - FastLM *newUserPhrasesModel; - FastLM *newExcludedPhraseModel; + McBopomofoLM *newLanguageModel; if ([value isKindOfClass:[NSString class]] && [value isEqual:kPlainBopomofoModeIdentifier]) { newInputMode = kPlainBopomofoModeIdentifier; newLanguageModel = [LanguageModelManager languageModelPlainBopomofo]; - newUserPhrasesModel = NULL; - newExcludedPhraseModel = [LanguageModelManager excludedPhrasesLanguageModelPlainBopomofo]; } else { newInputMode = kBopomofoModeIdentifier; newLanguageModel = [LanguageModelManager languageModelMcBopomofo]; - newUserPhrasesModel = [LanguageModelManager userPhraseLanguageModel]; - newExcludedPhraseModel = [LanguageModelManager excludedPhrasesLanguageModelMcBopomofo]; } // Only apply the changes if the value is changed @@ -355,8 +348,6 @@ static double FindHighestScore(const vector& nodes, double epsilon) _inputMode = newInputMode; _languageModel = newLanguageModel; - _userPhrasesModel = newUserPhrasesModel; - _excludedPhraseModel = newExcludedPhraseModel; if (!_bpmfReadingBuffer->isEmpty()) { _bpmfReadingBuffer->clear(); @@ -369,7 +360,7 @@ static double FindHighestScore(const vector& nodes, double epsilon) if (_builder) { delete _builder; - _builder = new BlockReadingBuilder(_languageModel, _userPhrasesModel, _excludedPhraseModel); + _builder = new BlockReadingBuilder(_languageModel); _builder->setJoinSeparator("-"); } } @@ -1096,65 +1087,30 @@ NS_INLINE size_t max(size_t a, size_t b) { return a > b ? a : b; } return NO; } -- (vector)_collectUnigrams:(string)string -{ - vector unigrams; - vector userUnigrams; - - if (_userPhrasesModel != NULL && _userPhrasesModel->hasUnigramsForKey(string)) { - userUnigrams = _userPhrasesModel->unigramsForKeys(string); - } - - if (_languageModel->hasUnigramsForKey(string)) { - vector globalUnigrams = _languageModel->unigramsForKeys(string); - for (std::vector::iterator it=globalUnigrams.begin(); it!=globalUnigrams.end(); ++it) { - if (!_builder->checkIfUnigramExistInVector(*it, unigrams)) { - unigrams.push_back(*it); - } - } - } - unigrams.insert(unigrams.begin(), userUnigrams.begin(), userUnigrams.end()); - - if (_excludedPhraseModel != NULL && _excludedPhraseModel->hasUnigramsForKey(string)) { - vector excludedUnigrams = _excludedPhraseModel->unigramsForKeys(string); - vector newUnigram; - for (std::vector::iterator it=unigrams.begin(); it!=unigrams.end(); ++it) { - if (!_builder->checkIfUnigramExistInVector(*it, excludedUnigrams)) { - newUnigram.push_back(*it); - } - } - unigrams = newUnigram; - } - return unigrams; -} - - - (BOOL)handlePunctuation:(string)customPunctuation usingVerticalMode:(BOOL)useVerticalMode client:(id)client { - vector collected = [self _collectUnigrams:customPunctuation]; - if (!collected.size()) { - return NO; - } - - if (_bpmfReadingBuffer->isEmpty()) { - _builder->insertReadingAtCursor(customPunctuation); - [self popOverflowComposingTextAndWalk:client]; - } - else { // If there is still unfinished bpmf reading, ignore the punctuation - [self beep]; - } - [self updateClientComposingBuffer:client]; - - if (_inputMode == kPlainBopomofoModeIdentifier && _bpmfReadingBuffer->isEmpty()) { - [self collectCandidates]; - if ([_candidates count] == 1) { - [self commitComposition:client]; + if (_languageModel->hasUnigramsForKey(customPunctuation)) { + if (_bpmfReadingBuffer->isEmpty()) { + _builder->insertReadingAtCursor(customPunctuation); + [self popOverflowComposingTextAndWalk:client]; } - else { - [self _showCandidateWindowUsingVerticalMode:useVerticalMode client:client]; + else { // If there is still unfinished bpmf reading, ignore the punctuation + [self beep]; } + [self updateClientComposingBuffer:client]; + + if (_inputMode == kPlainBopomofoModeIdentifier && _bpmfReadingBuffer->isEmpty()) { + [self collectCandidates]; + if ([_candidates count] == 1) { + [self commitComposition:client]; + } + else { + [self _showCandidateWindowUsingVerticalMode:useVerticalMode client:client]; + } + } + return YES; } - return YES; + return NO; } - (BOOL)handleCandidateEventWithInputText:(NSString *)inputText charCode:(UniChar)charCode keyCode:(NSUInteger)keyCode diff --git a/Source/LanguageModelManager.h b/Source/LanguageModelManager.h index 9ba88bb0..d819e067 100644 --- a/Source/LanguageModelManager.h +++ b/Source/LanguageModelManager.h @@ -1,6 +1,7 @@ #import #import "FastLM.h" #import "UserOverrideModel.h" +#import "McBopomofoLM.h" NS_ASSUME_NONNULL_BEGIN @@ -15,11 +16,8 @@ NS_ASSUME_NONNULL_BEGIN @property (class, readonly, nonatomic) NSString *userPhrasesDataPathMcBopomofo; @property (class, readonly, nonatomic) NSString *excludedPhrasesDataPathMcBopomofo; @property (class, readonly, nonatomic) NSString *excludedPhrasesDataPathPlainBopomofo; -@property (class, readonly, nonatomic) Formosa::Gramambular::FastLM *languageModelMcBopomofo; -@property (class, readonly, nonatomic) Formosa::Gramambular::FastLM *languageModelPlainBopomofo; -@property (class, readonly, nonatomic) Formosa::Gramambular::FastLM *userPhraseLanguageModel; -@property (class, readonly, nonatomic) Formosa::Gramambular::FastLM *excludedPhrasesLanguageModelMcBopomofo; -@property (class, readonly, nonatomic) Formosa::Gramambular::FastLM *excludedPhrasesLanguageModelPlainBopomofo; +@property (class, readonly, nonatomic) McBopomofo::McBopomofoLM *languageModelMcBopomofo; +@property (class, readonly, nonatomic) McBopomofo::McBopomofoLM *languageModelPlainBopomofo; @property (class, readonly, nonatomic) McBopomofo::UserOverrideModel *userOverrideModel; @end diff --git a/Source/LanguageModelManager.mm b/Source/LanguageModelManager.mm index 68924f54..ba632b67 100644 --- a/Source/LanguageModelManager.mm +++ b/Source/LanguageModelManager.mm @@ -7,61 +7,35 @@ using namespace std; using namespace Formosa::Gramambular; +using namespace McBopomofo; using namespace OpenVanilla; static const int kUserOverrideModelCapacity = 500; static const double kObservedOverrideHalflife = 5400.0; // 1.5 hr. -FastLM globalLanguageModel; -FastLM globalLanguageModelPlainBopomofo; -FastLM globalUserPhraseLanguageModel; -FastLM globalUserExcludedPhrasesMcBopomofo; -FastLM globalUserExcludedPhrasesPlainBopomofo; -McBopomofo::UserOverrideModel globalUserOverrideModel(kUserOverrideModelCapacity, kObservedOverrideHalflife); +McBopomofoLM gLanguageModelMcBopomofo; +McBopomofoLM gLanguageModelPlainBopomofo; +UserOverrideModel gUserOverrideModel(kUserOverrideModelCapacity, kObservedOverrideHalflife); @implementation LanguageModelManager -static bool LTLoadLanguageModelFile(NSString *filenameWithoutExtension, FastLM &lm) +static void LTLoadLanguageModelFile(NSString *filenameWithoutExtension, McBopomofoLM &lm) { Class cls = NSClassFromString(@"McBopomofoInputMethodController"); NSString *dataPath = [[NSBundle bundleForClass:cls] pathForResource:filenameWithoutExtension ofType:@"txt"]; - bool result = lm.open([dataPath UTF8String]); - return (BOOL)result; + lm.loadLanguageModel([dataPath UTF8String]); } + (void)loadDataModels { - bool dataOpenResult = LTLoadLanguageModelFile(@"data", globalLanguageModel); - if (!dataOpenResult) { - NSLog(@"Failed to open language model."); - } - bool plainBpmfOpenResult = LTLoadLanguageModelFile(@"data-plain-bpmf", globalLanguageModelPlainBopomofo); - if (!plainBpmfOpenResult) { - NSLog(@"Failed to open language model for plain bpmf."); - } + LTLoadLanguageModelFile(@"data", gLanguageModelMcBopomofo); + LTLoadLanguageModelFile(@"data-plain-bpmf", gLanguageModelPlainBopomofo); } + (void)loadUserPhrasesModel { - globalUserPhraseLanguageModel.close(); - globalUserExcludedPhrasesMcBopomofo.close(); - globalUserExcludedPhrasesPlainBopomofo.close(); - - bool result = false; - - result = globalUserPhraseLanguageModel.open([[self userPhrasesDataPathMcBopomofo] UTF8String]); - if (!result) { - NSLog(@"Failed to open user phrases. %@", [self userPhrasesDataPathMcBopomofo]); - } - result = globalUserExcludedPhrasesMcBopomofo.open([[self excludedPhrasesDataPathMcBopomofo] UTF8String]); - if (!result) { - NSLog(@"Failed to open excluded phrases McBopomofo. %@", [self excludedPhrasesDataPathMcBopomofo]); - } - - result = globalUserExcludedPhrasesPlainBopomofo.open([[self excludedPhrasesDataPathPlainBopomofo] UTF8String]); - if (!result) { - NSLog(@"Failed to open excluded phrases Plain Bopomofo. %@", [self excludedPhrasesDataPathPlainBopomofo]); - } + gLanguageModelMcBopomofo.loadUserPhrases([[self userPhrasesDataPathMcBopomofo] UTF8String], [[self excludedPhrasesDataPathMcBopomofo] UTF8String]); + gLanguageModelPlainBopomofo.loadUserPhrases("", [[self excludedPhrasesDataPathPlainBopomofo] UTF8String]); } + (BOOL)checkIfUserDataFolderExists @@ -163,34 +137,19 @@ static bool LTLoadLanguageModelFile(NSString *filenameWithoutExtension, FastLM & return [[self dataFolderPath] stringByAppendingPathComponent:@"exclude-phrases-plain-bpmf.txt"]; } - + (FastLM *)languageModelMcBopomofo + + (McBopomofoLM *)languageModelMcBopomofo { - return &globalLanguageModel; + return &gLanguageModelMcBopomofo; } -+ (FastLM *)languageModelPlainBopomofo ++ (McBopomofoLM *)languageModelPlainBopomofo { - return &globalLanguageModelPlainBopomofo; -} - -+ (FastLM *)userPhraseLanguageModel -{ - return &globalUserPhraseLanguageModel; -} - -+ (FastLM *)excludedPhrasesLanguageModelMcBopomofo -{ - return &globalUserExcludedPhrasesMcBopomofo; -} - -+ (FastLM *)excludedPhrasesLanguageModelPlainBopomofo -{ - return &globalUserExcludedPhrasesPlainBopomofo; + return &gLanguageModelPlainBopomofo; } + (McBopomofo::UserOverrideModel *)userOverrideModel { - return &globalUserOverrideModel; + return &gUserOverrideModel; } @end