~ubuntu-branches/ubuntu/raring/sunpinyin/raring

« back to all changes in this revision

Viewing changes to src/ime-core/imi_context.cpp

  • Committer: Package Import Robot
  • Author(s): YunQiang Su
  • Date: 2012-03-30 15:31:55 UTC
  • mfrom: (1.1.3) (1.2.7 sid)
  • Revision ID: package-import@ubuntu.com-20120330153155-qgls77sogzgtg9zp
Tags: 2.0.3+git20120222-1
* Team upload: git snapshot 20120222.
   - fix breaks if LDFLAGS in environment contains
       multiple words (Closese #646001).
   - rm patches merged to upstream:
       append-os-environ-toenv.patch
       fix-ftbfs-on-sh.patch
       remove-10-candidate-words-limitation.patch
   - refresh disable-lm-dict-compile.patch.
* Bump stardard version to 3.9.3: no modify needed.
* add libsunpinyin3-dbg and python-sunpinyin packages.
* debian/compat to 9, multiarch it.
* rewrite debian/rules with dh 7 format.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 
 * 
 
3
 *
4
4
 * Copyright (c) 2007 Sun Microsystems, Inc. All Rights Reserved.
5
 
 * 
 
5
 *
6
6
 * The contents of this file are subject to the terms of either the GNU Lesser
7
7
 * General Public License Version 2.1 only ("LGPL") or the Common Development and
8
8
 * Distribution License ("CDDL")(collectively, the "License"). You may not use this
9
9
 * file except in compliance with the License. You can obtain a copy of the CDDL at
10
10
 * http://www.opensource.org/licenses/cddl1.php and a copy of the LGPLv2.1 at
11
 
 * http://www.opensource.org/licenses/lgpl-license.php. See the License for the 
 
11
 * http://www.opensource.org/licenses/lgpl-license.php. See the License for the
12
12
 * specific language governing permissions and limitations under the License. When
13
13
 * distributing the software, include this License Header Notice in each file and
14
14
 * include the full text of the License in the License file as well as the
15
15
 * following notice:
16
 
 * 
 
16
 *
17
17
 * NOTICE PURSUANT TO SECTION 9 OF THE COMMON DEVELOPMENT AND DISTRIBUTION LICENSE
18
18
 * (CDDL)
19
19
 * For Covered Software in this distribution, this License shall be governed by the
21
21
 * Any litigation relating to this License shall be subject to the jurisdiction of
22
22
 * the Federal Courts of the Northern District of California and the state courts
23
23
 * of the State of California, with venue lying in Santa Clara County, California.
24
 
 * 
 
24
 *
25
25
 * Contributor(s):
26
 
 * 
 
26
 *
27
27
 * If you wish your version of this file to be governed by only the CDDL or only
28
28
 * the LGPL Version 2.1, indicate your decision by adding "[Contributor]" elects to
29
29
 * include this software in this distribution under the [CDDL or LGPL Version 2.1]
32
32
 * Version 2.1, or to extend the choice of license to its licensees as provided
33
33
 * above. However, if you add LGPL Version 2.1 code and therefore, elected the LGPL
34
34
 * Version 2 license, then the option applies only if the new code is made subject
35
 
 * to such option by the copyright holder. 
 
35
 * to such option by the copyright holder.
36
36
 */
37
37
 
38
38
#ifdef HAVE_CONFIG_H
39
39
#include <config.h>
40
40
#endif
41
41
 
 
42
#include <assert.h>
42
43
#include <algorithm>
43
44
#include "imi_defines.h"
44
45
#include "imi_context.h"
46
47
TCandiRank::TCandiRank(bool user, bool best, unsigned len,
47
48
                       bool fromLattice, TSentenceScore score)
48
49
{
49
 
    anony.m_user = (user)?0:1;
50
 
    anony.m_best = (best)?0:1;
51
 
    anony.m_len = (len > 31)?(0):(31-len);
52
 
    anony.m_lattice = (fromLattice)?0:1;
 
50
    anony.m_user = (user) ? 0 : 1;
 
51
    anony.m_best = (best) ? 0 : 1;
 
52
    anony.m_len = (len > 31) ? (0) : (31 - len);
 
53
    anony.m_lattice = (fromLattice) ? 0 : 1;
53
54
 
54
55
    double ds = -score.log2();
55
56
 
58
59
        ds = 32767.0;
59
60
    else if (ds < -32768.0)
60
61
        ds = -32768.0;
61
 
    unsigned cost = unsigned((ds+32768.0)*256.0);
 
62
    unsigned cost = unsigned((ds + 32768.0) * 256.0);
62
63
    anony.m_cost = cost;
63
64
}
64
65
 
65
66
TCandiRank::TCandiRank(bool user, bool best, unsigned len,
66
67
                       bool fromLattice, unsigned rank)
67
68
{
68
 
    anony.m_user = (user)?0:1;
69
 
    anony.m_best = (best)?0:1;
70
 
    anony.m_len = (len > 31)?(0):(31-len);
71
 
    anony.m_lattice = (fromLattice)?0:1;
 
69
    anony.m_user = (user) ? 0 : 1;
 
70
    anony.m_best = (best) ? 0 : 1;
 
71
    anony.m_len = (len > 31) ? (0) : (31 - len);
 
72
    anony.m_lattice = (fromLattice) ? 0 : 1;
72
73
    anony.m_cost = rank;
73
74
}
74
75
 
75
 
void CLatticeFrame::print (std::string prefix)
 
76
void
 
77
CLatticeFrame::print(std::string prefix)
76
78
{
77
 
    if (m_bwType & BESTWORD) printf ("B");
78
 
    if (m_bwType & USER_SELECTED) printf ("U");
79
 
    printf ("\n");
 
79
    if (m_bwType & BESTWORD) printf("B");
 
80
    if (m_bwType & USER_SELECTED) printf("U");
 
81
    printf("\n");
80
82
 
81
83
    prefix += "    ";
82
 
    printf ("  Lexicon States:\n");
83
 
    for_each (m_lexiconStates.begin (), m_lexiconStates.end (), 
84
 
              bind2nd (mem_fun_ref (&TLexiconState::print), prefix));
 
84
    printf("  Lexicon States:\n");
 
85
    for_each(m_lexiconStates.begin(), m_lexiconStates.end(),
 
86
             bind2nd(mem_fun_ref(&TLexiconState::print), prefix));
85
87
 
86
 
    printf ("  Lattice States:\n");
87
 
    for_each (m_latticeStates.begin (), m_latticeStates.end (), 
88
 
              bind2nd (mem_fun_ref (&TLatticeState::print), prefix));
89
 
    printf ("\n");
 
88
    printf("  Lattice States:\n");
 
89
    for_each(m_latticeStates.begin(), m_latticeStates.end(),
 
90
             bind2nd(mem_fun_ref(&TLatticeState::print), prefix));
 
91
    printf("\n");
90
92
}
91
93
 
92
 
void CIMIContext::printLattice ()
 
94
void
 
95
CIMIContext::printLattice()
93
96
{
94
97
    std::string prefix;
95
98
 
96
 
    for (int i=0; i<=m_tailIdx; ++i) {
 
99
    for (size_t i = 0; i <= m_tailIdx; ++i) {
97
100
        if (m_lattice[i].m_type == CLatticeFrame::UNUSED)
98
101
            continue;
99
102
 
100
 
        printf ("Lattice Frame [%d]:", i);
101
 
        m_lattice[i].print (prefix);
 
103
        printf("Lattice Frame [%lu]:", i);
 
104
        m_lattice[i].print(prefix);
102
105
    }
103
106
}
104
107
 
105
 
CIMIContext::CIMIContext () 
106
 
    : m_tailIdx(1), m_pModel(NULL), m_pPinyinTrie(NULL), m_pUserDict(NULL), m_pHistory(NULL), 
107
 
      m_historyPower(5), m_bFullSymbolForwarding(false), m_pGetFullSymbolOp(NULL),
108
 
      m_bFullPunctForwarding(true), m_pGetFullPunctOp(NULL), m_bDynaCandiOrder(true),
109
 
      m_candiStarts(0), m_candiEnds(0), m_csLevel(0), m_bNonCompleteSyllable(true),
110
 
      m_pPySegmentor(0), m_bOmitPunct(false)
 
108
CIMIContext::CIMIContext()
 
109
    : m_tailIdx(1), m_nBest(0), m_maxBest(1), m_maxTailCandidateNum(0),
 
110
      m_pModel(NULL), m_pPinyinTrie(NULL), m_pUserDict(NULL), m_pHistory(NULL),
 
111
      m_historyPower(5), m_csLevel(0), m_bFullSymbolForwarding(false),
 
112
      m_bOmitPunct(false), m_pGetFullSymbolOp(NULL),
 
113
      m_bFullPunctForwarding(true), m_pGetFullPunctOp(NULL),
 
114
      m_pPySegmentor(NULL), m_bNonCompleteSyllable(true),
 
115
      m_bDynaCandiOrder(true), m_candiStarts(0), m_candiEnds(0)
111
116
{
112
 
    m_lattice.resize (MAX_LATTICE_LENGTH);
113
 
    m_lattice[0].m_latticeStates.push_back (TLatticeState (-1.0, 0));
 
117
    m_lattice.resize(MAX_LATTICE_LENGTH);
 
118
    m_lattice[0].m_latticeStates.add(TLatticeState(-1.0, 0));
 
119
    setMaxBest(m_maxBest);
114
120
}
115
121
 
116
 
void CIMIContext::setCoreData (CIMIData *pCoreData)
 
122
void
 
123
CIMIContext::setCoreData(CIMIData *pCoreData)
117
124
{
118
125
    m_pModel = pCoreData->getSlm();
119
126
    m_pPinyinTrie = pCoreData->getPinyinTrie();
120
127
}
121
128
 
122
 
void CIMIContext::clear ()
 
129
void
 
130
CIMIContext::clear()
123
131
{
124
 
    _clearFrom (1);
125
 
    _clearBestPaths ();
 
132
    _clearFrom(1);
 
133
    _clearPaths();
126
134
    m_tailIdx = 1;
127
135
    m_candiStarts = m_candiEnds = 0;
128
136
}
129
137
 
130
 
void CIMIContext::_clearFrom (unsigned idx)
 
138
void
 
139
CIMIContext::_clearFrom(unsigned idx)
131
140
{
132
 
    for (int i=idx; i<m_tailIdx+1; ++i)
 
141
    for (size_t i = idx; i < m_tailIdx + 1; i++)
133
142
        m_lattice[i].clear();
134
143
}
135
144
 
136
 
bool CIMIContext::buildLattice (IPySegmentor *segmentor, bool doSearch)
 
145
bool
 
146
CIMIContext::buildLattice(IPySegmentor *segmentor, bool doSearch)
137
147
{
138
148
    m_pPySegmentor = segmentor;
139
 
    return _buildLattice (segmentor->getSegments(), segmentor->updatedFrom()+1, doSearch);
 
149
    return _buildLattice(segmentor->getSegments(),
 
150
                         segmentor->updatedFrom() + 1, doSearch);
140
151
}
141
152
 
142
 
bool CIMIContext::_buildLattice (IPySegmentor::TSegmentVec &segments, unsigned rebuildFrom, bool doSearch)
 
153
bool
 
154
CIMIContext::_buildLattice(IPySegmentor::TSegmentVec &segments,
 
155
                           unsigned rebuildFrom,
 
156
                           bool doSearch)
143
157
{
144
 
    _clearFrom (rebuildFrom);
145
 
 
146
 
    IPySegmentor::TSegmentVec::const_iterator it  = segments.begin ();
147
 
    IPySegmentor::TSegmentVec::const_iterator ite = segments.end ();
148
 
   
149
 
    unsigned i, j=0; 
 
158
    _clearFrom(rebuildFrom);
 
159
 
 
160
    IPySegmentor::TSegmentVec::const_iterator it = segments.begin();
 
161
    IPySegmentor::TSegmentVec::const_iterator ite = segments.end();
 
162
 
 
163
    unsigned i, j = 0;
150
164
    for (; it != ite; ++it) {
151
165
        i = it->m_start;
152
166
        j = i + it->m_len;
153
167
 
154
 
        if (i < rebuildFrom-1)
 
168
        if (i < rebuildFrom - 1)
155
169
            continue;
156
170
 
157
 
        if (j >= m_lattice.capacity()-1)
 
171
        if (j >= m_lattice.capacity() - 1)
158
172
            break;
159
173
 
160
174
        if (it->m_type == IPySegmentor::SYLLABLE)
161
 
            _forwardSyllables (i, j, *it);
 
175
            _forwardSyllables(i, j, *it);
162
176
        else if (it->m_type == IPySegmentor::SYLLABLE_SEP)
163
 
            _forwardSyllableSep (i, j);
 
177
            _forwardSyllableSep(i, j);
164
178
        else
165
 
            _forwardString (i, j, it->m_syllables);
 
179
            _forwardString(i, j, it->m_syllables);
166
180
        m_bOmitPunct = false;
167
181
    }
168
182
 
169
 
    _forwardTail (j, j+1);
170
 
    m_tailIdx = j+1;
 
183
    _forwardTail(j, j + 1);
 
184
    m_tailIdx = j + 1;
171
185
 
172
 
    return doSearch && searchFrom (rebuildFrom);
 
186
    return doSearch && searchFrom(rebuildFrom);
173
187
}
174
188
 
175
 
void CIMIContext::_forwardSyllables (unsigned i, unsigned j, const IPySegmentor::TSegment& seg)
 
189
void
 
190
CIMIContext::_forwardSyllables(unsigned i,
 
191
                               unsigned j,
 
192
                               const IPySegmentor::TSegment& seg)
176
193
{
177
 
    std::vector<unsigned>::const_iterator it  = seg.m_syllables.begin ();
178
 
    std::vector<unsigned>::const_iterator ite = seg.m_syllables.end ();
179
 
 
180
 
    for (; it != ite; ++it)
181
 
        _forwardSingleSyllable (i, j, *it, seg);
182
 
 
183
 
    it  = seg.m_fuzzy_syllables.begin ();
184
 
    ite = seg.m_fuzzy_syllables.end ();
185
 
 
186
 
    for (; it != ite; ++it)
187
 
        _forwardSingleSyllable (i, j, *it, seg, true);
 
194
    std::vector<unsigned>::const_iterator it = seg.m_syllables.begin();
 
195
    std::vector<unsigned>::const_iterator ite = seg.m_syllables.end();
 
196
 
 
197
    for (; it != ite; ++it)
 
198
        _forwardSingleSyllable(i, j, *it, seg);
 
199
 
 
200
    it = seg.m_fuzzy_syllables.begin();
 
201
    ite = seg.m_fuzzy_syllables.end();
 
202
 
 
203
    for (; it != ite; ++it)
 
204
        _forwardSingleSyllable(i, j, *it, seg, true);
188
205
}
189
206
 
190
207
 
191
 
void CIMIContext::_forwardString (unsigned i, unsigned j, const std::vector<unsigned>& strbuf)
 
208
void
 
209
CIMIContext::_forwardString(unsigned i,
 
210
                            unsigned j,
 
211
                            const std::vector<unsigned>& strbuf)
192
212
{
193
213
    if (strbuf.size() == 1) {
194
214
        unsigned ch = strbuf[0];
195
 
        ispunct(ch)? _forwardPunctChar (i, j, ch): _forwardOrdinaryChar (i, j, ch);
 
215
        if (ispunct(ch)) {
 
216
            _forwardPunctChar(i, j, ch);
 
217
        } else {
 
218
            _forwardOrdinaryChar(i, j, ch);
 
219
        }
196
220
    } else{
197
221
        CLatticeFrame &fr = m_lattice[j];
198
 
        fr.m_wstr.assign (strbuf.begin(), strbuf.end());
199
 
        fr.m_lexiconStates.push_back (TLexiconState(i, 0));
 
222
        fr.m_wstr.assign(strbuf.begin(), strbuf.end());
 
223
        fr.m_lexiconStates.push_back(TLexiconState(i, 0));
200
224
    }
201
225
}
202
226
 
203
 
void CIMIContext::_forwardSingleSyllable (unsigned i, unsigned j, TSyllable syllable, const IPySegmentor::TSegment& seg, bool fuzzy)
 
227
void
 
228
CIMIContext::_forwardSingleSyllable(unsigned i,
 
229
                                    unsigned j,
 
230
                                    TSyllable syllable,
 
231
                                    const IPySegmentor::TSegment& seg,
 
232
                                    bool fuzzy)
204
233
{
205
234
    const CPinyinTrie::TNode * pn = NULL;
206
235
 
207
236
    CLatticeFrame &fr = m_lattice[j];
208
237
    fr.m_type = CLatticeFrame::SYLLABLE;
209
238
 
210
 
    CLexiconStates::iterator it  = m_lattice[i].m_lexiconStates.begin ();
211
 
    CLexiconStates::iterator ite = m_lattice[i].m_lexiconStates.end ();
 
239
    CLexiconStates::iterator it = m_lattice[i].m_lexiconStates.begin();
 
240
    CLexiconStates::iterator ite = m_lattice[i].m_lexiconStates.end();
212
241
    for (; it != ite; ++it) {
213
242
        TLexiconState &lxst = *it;
214
243
        bool added_from_sysdict = false;
216
245
        if (lxst.m_pPYNode) {
217
246
            // try to match a word from lattice i to lattice j
218
247
            // and if match, we'll count it as a new lexicon on lattice j
219
 
            pn = m_pPinyinTrie->transfer (lxst.m_pPYNode, syllable);
 
248
            pn = m_pPinyinTrie->transfer(lxst.m_pPYNode, syllable);
220
249
            if (pn) {
221
250
                added_from_sysdict = true;
222
 
                TLexiconState new_lxst = TLexiconState (lxst.m_start, pn, lxst.m_syls, lxst.m_seg_path, fuzzy);
223
 
                new_lxst.m_syls.push_back (syllable);
224
 
                new_lxst.m_num_of_inner_fuzzies = lxst.m_num_of_inner_fuzzies + (seg.m_inner_fuzzy? 1: 0);
225
 
                new_lxst.m_seg_path.push_back (seg.m_start+seg.m_len);
226
 
                fr.m_lexiconStates.push_back (new_lxst);
 
251
                TLexiconState new_lxst = TLexiconState(lxst.m_start,
 
252
                                                       pn,
 
253
                                                       lxst.m_syls,
 
254
                                                       lxst.m_seg_path,
 
255
                                                       fuzzy);
 
256
                new_lxst.m_syls.push_back(syllable);
 
257
                new_lxst.m_num_of_inner_fuzzies = lxst.m_num_of_inner_fuzzies +
 
258
                                                  (seg.m_inner_fuzzy ? 1 : 0);
 
259
                new_lxst.m_seg_path.push_back(seg.m_start + seg.m_len);
 
260
                fr.m_lexiconStates.push_back(new_lxst);
227
261
            }
228
262
        }
229
263
 
230
264
        if (m_pUserDict && lxst.m_syls.size() < MAX_USRDEF_WORD_LEN) {
231
265
            // try to match a word from user dict
232
266
            CSyllables syls = lxst.m_syls;
233
 
            syls.push_back (syllable);
 
267
            syls.push_back(syllable);
234
268
            std::vector<CPinyinTrie::TWordIdInfo> words;
235
 
            m_pUserDict->getWords (syls, words);
 
269
            m_pUserDict->getWords(syls, words);
236
270
            if (!words.empty() || !added_from_sysdict) {
237
271
                // even if the words is empty we'll add a fake lexicon
238
272
                // here. This helps _saveUserDict detect new words.
239
 
                TLexiconState new_lxst = TLexiconState (lxst.m_start, words, lxst.m_syls, lxst.m_seg_path, fuzzy);
240
 
                new_lxst.m_syls.push_back (syllable);
241
 
                new_lxst.m_num_of_inner_fuzzies = lxst.m_num_of_inner_fuzzies + (seg.m_inner_fuzzy? 1: 0);
242
 
                new_lxst.m_seg_path.push_back (seg.m_start+seg.m_len);
243
 
                fr.m_lexiconStates.push_back (new_lxst);
 
273
                TLexiconState new_lxst = TLexiconState(lxst.m_start,
 
274
                                                       words,
 
275
                                                       lxst.m_syls,
 
276
                                                       lxst.m_seg_path,
 
277
                                                       fuzzy);
 
278
                new_lxst.m_syls.push_back(syllable);
 
279
                new_lxst.m_num_of_inner_fuzzies = lxst.m_num_of_inner_fuzzies +
 
280
                                                  (seg.m_inner_fuzzy ? 1 : 0);
 
281
                new_lxst.m_seg_path.push_back(seg.m_start + seg.m_len);
 
282
                fr.m_lexiconStates.push_back(new_lxst);
244
283
            }
245
284
        }
246
285
    }
247
286
 
248
287
    // last, create a lexicon for single character with only one syllable
249
 
    pn = m_pPinyinTrie->transfer (syllable);
 
288
    pn = m_pPinyinTrie->transfer(syllable);
250
289
    if (pn) {
251
290
        CSyllables syls;
252
 
        syls.push_back (syllable);
 
291
        syls.push_back(syllable);
253
292
        std::vector<unsigned> seg_path;
254
 
        seg_path.push_back (seg.m_start);
255
 
        seg_path.push_back (seg.m_start+seg.m_len);
256
 
        TLexiconState new_lxst = TLexiconState (i, pn, syls, seg_path, fuzzy);
257
 
        new_lxst.m_num_of_inner_fuzzies = seg.m_inner_fuzzy? 1: 0;
258
 
        fr.m_lexiconStates.push_back (new_lxst);
 
293
        seg_path.push_back(seg.m_start);
 
294
        seg_path.push_back(seg.m_start + seg.m_len);
 
295
        TLexiconState new_lxst = TLexiconState(i, pn, syls, seg_path, fuzzy);
 
296
        new_lxst.m_num_of_inner_fuzzies = seg.m_inner_fuzzy ? 1 : 0;
 
297
        fr.m_lexiconStates.push_back(new_lxst);
259
298
    }
260
299
}
261
300
 
262
 
void CIMIContext::_forwardSyllableSep (unsigned i, unsigned j)
 
301
void
 
302
CIMIContext::_forwardSyllableSep(unsigned i, unsigned j)
263
303
{
264
304
    CLatticeFrame &fr = m_lattice[j];
265
305
    fr.m_type = CLatticeFrame::SYLLABLE | CLatticeFrame::SYLLABLE_SEP;
266
306
    fr.m_lexiconStates = m_lattice[i].m_lexiconStates;
267
307
 
268
 
    CLexiconStates::iterator it  = fr.m_lexiconStates.begin();
 
308
    CLexiconStates::iterator it = fr.m_lexiconStates.begin();
269
309
    CLexiconStates::iterator ite = fr.m_lexiconStates.end();
270
310
    for (; it != ite; ++it) {
271
311
        it->m_seg_path.back() = j;
272
312
    }
273
313
}
274
314
 
275
 
void CIMIContext::_forwardPunctChar (unsigned i, unsigned j, unsigned ch)
 
315
void
 
316
CIMIContext::_forwardPunctChar(unsigned i, unsigned j, unsigned ch)
276
317
{
277
318
    CLatticeFrame &fr = m_lattice[j];
278
319
 
279
 
    wstring wstr; 
 
320
    wstring wstr;
280
321
    unsigned wid = 0;
281
322
 
282
323
    if (m_pGetFullPunctOp) {
283
324
        if (m_bFullPunctForwarding && !m_bOmitPunct) {
284
 
            wstr = (*m_pGetFullPunctOp) (ch);
285
 
            wid = m_pPinyinTrie->getSymbolId (wstr);
 
325
            wstr = (*m_pGetFullPunctOp)(ch);
 
326
            wid = m_pPinyinTrie->getSymbolId(wstr);
286
327
        }
287
328
    }
288
329
 
291
332
    if (!wstr.empty())
292
333
        fr.m_wstr = wstr;
293
334
    else
294
 
        fr.m_wstr.push_back (ch);
 
335
        fr.m_wstr.push_back(ch);
295
336
 
296
 
    fr.m_lexiconStates.push_back (TLexiconState(i, wid));
 
337
    fr.m_lexiconStates.push_back(TLexiconState(i, wid));
297
338
}
298
339
 
299
 
void CIMIContext::_forwardOrdinaryChar (unsigned i, unsigned j, unsigned ch)
 
340
void
 
341
CIMIContext::_forwardOrdinaryChar(unsigned i, unsigned j, unsigned ch)
300
342
{
301
343
    CLatticeFrame &fr = m_lattice[j];
302
344
 
303
 
    wstring wstr; 
 
345
    wstring wstr;
304
346
    unsigned wid = 0;
305
347
 
306
348
    if (m_pGetFullSymbolOp) {
307
 
        wstr = (*m_pGetFullSymbolOp) (ch);
308
 
        wid = m_pPinyinTrie->getSymbolId (wstr);
 
349
        wstr = (*m_pGetFullSymbolOp)(ch);
 
350
        wid = m_pPinyinTrie->getSymbolId(wstr);
309
351
 
310
352
        if (!m_bFullSymbolForwarding)
311
 
            wstr.clear ();
 
353
            wstr.clear();
312
354
    }
313
355
 
314
 
    fr.m_type = wid? CLatticeFrame::SYMBOL: CLatticeFrame::ASCII;
 
356
    fr.m_type = wid ? CLatticeFrame::SYMBOL : CLatticeFrame::ASCII;
315
357
 
316
 
    if (!wstr.empty ())
 
358
    if (!wstr.empty())
317
359
        fr.m_wstr = wstr;
318
360
    else
319
 
        fr.m_wstr.push_back (ch);
 
361
        fr.m_wstr.push_back(ch);
320
362
 
321
 
    fr.m_lexiconStates.push_back (TLexiconState(i, wid));
 
363
    fr.m_lexiconStates.push_back(TLexiconState(i, wid));
322
364
}
323
365
 
324
 
void CIMIContext::_forwardTail (unsigned i, unsigned j)
 
366
void
 
367
CIMIContext::_forwardTail(unsigned i, unsigned j)
325
368
{
326
369
    CLatticeFrame &fr = m_lattice[j];
327
370
    fr.m_type = CLatticeFrame::TAIL;
328
371
 
329
 
    fr.m_lexiconStates.push_back (TLexiconState (i, ENDING_WORD_ID));
 
372
    fr.m_lexiconStates.push_back(TLexiconState(i, ENDING_WORD_ID));
330
373
}
331
374
 
332
 
bool CIMIContext::searchFrom (unsigned idx)
 
375
double exp2_tbl[32] = {exp2(0),  exp2(1),  exp2(2),  exp2(3),  exp2(4),  exp2(5),  exp2(6),  exp2(7),
 
376
                       exp2(8),  exp2(9),  exp2(10), exp2(11), exp2(12), exp2(13), exp2(14), exp2(15),
 
377
                       exp2(16), exp2(17), exp2(18), exp2(19), exp2(20), exp2(21), exp2(22), exp2(23),
 
378
                       exp2(24), exp2(25), exp2(26), exp2(27), exp2(28), exp2(29), exp2(30), exp2(31),};
 
379
 
 
380
bool
 
381
CIMIContext::searchFrom(unsigned idx)
333
382
{
334
383
    bool affectCandidates = (idx <= m_candiEnds);
335
384
 
336
 
    _clearBestPaths ();
337
 
 
338
 
    for (; idx<=m_tailIdx; ++idx) {
 
385
    for (; idx <= m_tailIdx; ++idx) {
339
386
        CLatticeFrame &fr = m_lattice[idx];
340
387
 
341
388
        if (fr.m_type == CLatticeFrame::UNUSED)
342
389
            continue;
343
390
 
344
 
        fr.m_latticeStates.clear ();
 
391
        fr.m_latticeStates.clear();
345
392
 
346
393
        /* user selected word might be cut in next step */
347
 
        if (fr.m_bwType & CLatticeFrame::USER_SELECTED)
348
 
            _transferBetween (fr.m_bestWord.m_start, idx, fr.m_bestWord.m_pLexiconState, fr.m_bestWord.m_wordId);
 
394
        if (fr.m_bwType & CLatticeFrame::USER_SELECTED) {
 
395
            _transferBetween(fr.m_selWord.m_start, idx,
 
396
                             fr.m_selWord.m_pLexiconState,
 
397
                             fr.m_selWord.m_wordId);
 
398
        }
349
399
 
350
 
        CLexiconStates::iterator it  = fr.m_lexiconStates.begin ();
351
 
        CLexiconStates::iterator ite = fr.m_lexiconStates.end ();
 
400
        CLexiconStates::iterator it = fr.m_lexiconStates.begin();
 
401
        CLexiconStates::iterator ite = fr.m_lexiconStates.end();
352
402
        for (; it != ite; ++it) {
353
403
            unsigned word_num = 0;
354
404
            TLexiconState &lxst = *it;
355
 
            const CPinyinTrie::TWordIdInfo *words = lxst.getWords (word_num);
 
405
            const CPinyinTrie::TWordIdInfo *words = lxst.getWords(word_num);
356
406
 
357
407
            if (!word_num)
358
408
                continue;
360
410
            if (lxst.m_start == m_candiStarts && idx > m_candiEnds)
361
411
                affectCandidates = true;
362
412
 
363
 
            // only selected the word with higher unigram probablities, and 
 
413
            // only selected the word with higher unigram probablities, and
364
414
            // narrow the search deepth and lower the initial score for fuzzy
365
415
            // syllables
366
 
            int maxsz = it->m_bFuzzy? MAX_LEXICON_TRIES/2: MAX_LEXICON_TRIES;
367
 
            double ic = it->m_bFuzzy? 0.5: 1.0;
368
 
 
369
 
            int sz = word_num<maxsz? word_num: maxsz;
 
416
            int maxsz = it->m_bFuzzy ? MAX_LEXICON_TRIES /
 
417
                        2 : MAX_LEXICON_TRIES;
 
418
 
 
419
            double ic = it->m_bFuzzy ? 0.5 : 1.0;
 
420
 
 
421
            int sz = (int) word_num < maxsz ? (int) word_num : maxsz;
370
422
            int i = 0, count = 0;
371
 
            for (i = 0; count < sz && i < sz && (words[i].m_bSeen || count < 2); ++i) {
 
423
 
 
424
            while (count < sz && i < sz && (words[i].m_bSeen || count < 2)) {
372
425
                if (m_csLevel >= words[i].m_csLevel) {
373
 
                    _transferBetween (lxst.m_start, idx, &lxst, words[i].m_id, ic);
374
 
                    ++ count;
 
426
                    _transferBetween(lxst.m_start, idx, &lxst, words[i].m_id,
 
427
                                     ic * exp2_tbl[-(words[i].m_cost)]);
 
428
                    ++count;
375
429
                }
 
430
                i++;
376
431
            }
377
432
 
378
433
            /* try extra words in history cache */
379
434
            if (m_pHistory) {
380
 
                for (; i < word_num; ++i) {
381
 
                    if (m_csLevel >= words[i].m_csLevel && m_pHistory->seenBefore (words[i].m_id))
382
 
                        _transferBetween (lxst.m_start, idx, &lxst, words[i].m_id);
 
435
                while (i < (int) word_num) {
 
436
                    if (m_csLevel >= words[i].m_csLevel
 
437
                        && m_pHistory->seenBefore(words[i].m_id))
 
438
                        _transferBetween(lxst.m_start, idx, &lxst,
 
439
                                         words[i].m_id,
 
440
                                         ic * exp2_tbl[-(words[i].m_cost)]);
 
441
                    i++;
383
442
                }
384
443
            }
385
444
        }
386
445
    }
387
446
 
388
 
    _backTraceBestPaths ();
 
447
    _clearPaths();
 
448
    m_path.clear();
 
449
    m_segPath.clear();
 
450
    m_nBest = 0;
 
451
 
 
452
    std::vector<TLatticeState> tail_states =
 
453
        m_lattice[m_tailIdx].m_latticeStates.getFilteredResult();
 
454
 
 
455
#ifdef DEBUG
 
456
    for (int i = 0; i < tail_states.size(); i++) {
 
457
        std::string score;
 
458
        tail_states[i].m_score.toString(score);
 
459
        printf("score[%d]: %s\n", i, score.c_str());
 
460
    }
 
461
#endif
 
462
 
 
463
    for (size_t i = 0; i < m_maxBest; i++) {
 
464
        TPath path, segpath;
 
465
        if (_backTracePaths(tail_states, m_nBest, path, segpath)) {
 
466
            m_path.push_back(path);
 
467
            m_segPath.push_back(segpath);
 
468
            m_nBest++;
 
469
        }
 
470
    }
 
471
 
 
472
    if (m_pPySegmentor && m_nBest > 0 && !m_segPath[0].empty())
 
473
        m_pPySegmentor->notify_best_segpath(m_segPath[0]);
389
474
 
390
475
    return affectCandidates;
391
476
}
392
477
 
393
 
void CIMIContext::_transferBetween (unsigned start, unsigned end, TLexiconState* plxst, unsigned wid, double ic)
 
478
void
 
479
CIMIContext::_transferBetween(unsigned start, unsigned end,
 
480
                              TLexiconState* plxst, unsigned wid,
 
481
                              double ic)
394
482
{
395
483
    CLatticeFrame &start_fr = m_lattice[start];
396
 
    CLatticeFrame &end_fr   = m_lattice[end];
397
 
 
398
 
    TLatticeState node (-1.0, end, plxst);
399
 
    TSentenceScore efic (ic);
400
 
 
401
 
    if ((end_fr.m_bwType & CLatticeFrame::USER_SELECTED) && end_fr.m_bestWord.m_wordId == wid)
402
 
        efic = TSentenceScore (30000, 1.0);
403
 
 
404
 
    static double s_history_distribution[11] = {0.0, 0.05, 0.10, 0.15, 0.20, 0.25, 0.30, 0.35, 0.40, 0.45, 0.50};
 
484
    CLatticeFrame &end_fr = m_lattice[end];
 
485
 
 
486
    TLatticeState node(-1.0, end, plxst);
 
487
    TSentenceScore efic(ic);
 
488
 
 
489
    if ((end_fr.m_bwType & CLatticeFrame::USER_SELECTED)
 
490
        && end_fr.m_selWord.m_wordId == wid)
 
491
        efic = TSentenceScore(30000, 1.0);
 
492
 
 
493
    static double s_history_distribution[] = {
 
494
        0.0, 0.05, 0.10, 0.15, 0.20, 0.25, 0.30, 0.35, 0.40, 0.45, 0.50
 
495
    };
 
496
 
405
497
    double weight_h = s_history_distribution[m_historyPower];
406
498
    double weight_s = 1.0 - weight_h;
407
499
 
408
 
    CLatticeStates::iterator it  = start_fr.m_latticeStates.begin();
 
500
    CLatticeStates::iterator it = start_fr.m_latticeStates.begin();
409
501
    CLatticeStates::iterator ite = start_fr.m_latticeStates.end();
410
502
 
411
 
    // for 1-length lattice states, replace ending_word_id (comma) with none_word_id (recognized by CThreadSlm)
412
 
    if (wid == ENDING_WORD_ID && it != ite && it->m_pBackTraceNode && it->m_pBackTraceNode->m_frIdx == 0)
413
 
        wid = NONE_WORD_ID;
414
 
 
415
503
    for (; it != ite; ++it) {
 
504
        // for 1-length lattice states, replace ending_word_id (comma)
 
505
        // with none_word_id (recognized by CThreadSlm)
 
506
        unsigned _wid = wid;
 
507
        if (wid == ENDING_WORD_ID && it->m_pBackTraceNode && it->m_pBackTraceNode->m_frIdx == 0)
 
508
            _wid = NONE_WORD_ID;
 
509
 
416
510
        node.m_pBackTraceNode = &(*it);
417
511
        node.m_backTraceWordId = wid;
418
512
 
419
 
        double ts = m_pModel->transfer(it->m_slmState, wid, node.m_slmState);
 
513
        double ts = m_pModel->transfer(it->m_slmState, _wid, node.m_slmState);
420
514
        m_pModel->historify(node.m_slmState);
421
515
 
422
 
        // backward to psuedo root, so wid is probably a user word, save the wid in idx field,
423
 
        // so that later we could get it via CThreadSlm::lastWordId, to calculate p_{cache} correctly.
424
 
        if (node.m_slmState.getLevel() == 0 && m_pHistory && m_pHistory->seenBefore(wid))
 
516
        // backward to psuedo root, so wid is probably a user word,
 
517
        // save the wid in idx field, so that later we could get it via
 
518
        // CThreadSlm::lastWordId, to calculate p_{cache} correctly.
 
519
        if (node.m_slmState.getLevel() == 0
 
520
            && m_pHistory && m_pHistory->seenBefore(wid))
425
521
            node.m_slmState.setIdx(wid);  // an psuedo unigram node state
426
522
 
427
523
        if (m_pHistory) {
428
 
            unsigned history[2] = {m_pModel->lastWordId(it->m_slmState), wid};
429
 
            double hpr = m_pHistory->pr(history, history+2);
430
 
            ts = weight_s * ts + weight_h*hpr;
 
524
            unsigned history[2] = { m_pModel->lastWordId(it->m_slmState), _wid };
 
525
            double hpr = m_pHistory->pr(history, history + 2);
 
526
            ts = weight_s * ts + weight_h * hpr;
431
527
        }
432
528
 
433
529
        node.m_score = it->m_score * efic * TSentenceScore(ts);
434
 
        end_fr.m_latticeStates.push_back (node);
 
530
        end_fr.m_latticeStates.add(node);
435
531
    }
436
532
}
437
533
 
438
 
void CIMIContext::_backTraceBestPaths ()
 
534
bool
 
535
CIMIContext::_backTracePaths(const std::vector<TLatticeState>& tail_states,
 
536
                             int rank, TPath& path, TPath& segmentPath)
439
537
{
440
 
    CLatticeStates& tail_states = m_lattice[m_tailIdx].m_latticeStates;
441
 
 
442
 
    // there must be some transfer errors
443
 
    if (!tail_states.size())
444
 
        return;
445
 
 
446
 
    TLatticeState *bs = &(tail_states[0]);
 
538
    path.clear();
 
539
    segmentPath.clear();
 
540
 
 
541
    if (rank >= (int) tail_states.size()) {
 
542
        // rank out of bounds, only return the segment path
 
543
        return false;
 
544
    }
 
545
 
 
546
    const TLatticeState *bs = &(tail_states[rank]);
447
547
 
448
548
    while (bs->m_pBackTraceNode) {
449
549
        unsigned start = bs->m_pBackTraceNode->m_frIdx;
450
 
        unsigned end   = bs->m_frIdx;
 
550
        unsigned end = bs->m_frIdx;
451
551
        CLatticeFrame & end_fr = m_lattice[end];
452
552
 
453
 
        if (! (end_fr.m_bwType & CLatticeFrame::USER_SELECTED)) {
 
553
        if (!(end_fr.m_bwType & CLatticeFrame::USER_SELECTED)) {
 
554
            const TWCHAR* cwstr = NULL;
 
555
            if (end_fr.m_wstr.empty()) {
 
556
                cwstr = _getWstr(bs->m_backTraceWordId);
 
557
            } else {
 
558
                cwstr = end_fr.m_wstr.c_str();
 
559
            }
 
560
 
 
561
            CCandidate candi(start, end, bs->m_pLexiconState, cwstr,
 
562
                             bs->m_backTraceWordId);
 
563
 
454
564
            end_fr.m_bwType |= CLatticeFrame::BESTWORD;
455
 
 
456
 
            end_fr.m_bestWord.m_start = start;
457
 
            end_fr.m_bestWord.m_end = end;
458
 
            end_fr.m_bestWord.m_pLexiconState = bs->m_pLexiconState;
459
 
            end_fr.m_bestWord.m_wordId = bs->m_backTraceWordId;
460
 
            end_fr.m_bestWord.m_cwstr = end_fr.m_wstr.empty()?
461
 
                                        _getWstr (bs->m_backTraceWordId):
462
 
                                        end_fr.m_wstr.c_str();
 
565
            end_fr.m_bestWords[rank] = candi;
 
566
            if (rank == 0) {
 
567
                end_fr.m_selWord = candi; // select the first by default.
 
568
            }
463
569
        }
464
570
 
465
571
        if (bs->m_pBackTraceNode->m_pLexiconState) {
466
 
            std::vector<unsigned> seg_path = bs->m_pBackTraceNode->m_pLexiconState->m_seg_path;
467
 
            std::vector<unsigned>::reverse_iterator it  = seg_path.rbegin();
468
 
            std::vector<unsigned>::reverse_iterator ite = seg_path.rend();
 
572
            std::vector<unsigned> seg_path =
 
573
                bs->m_pBackTraceNode->m_pLexiconState->m_seg_path;
 
574
            std::vector<unsigned>::reverse_iterator it = seg_path.rbegin();
469
575
 
470
576
            for (; it != seg_path.rend(); ++it) {
471
 
                if (m_bestSegPath.empty() || m_bestSegPath.back() != *it)
472
 
                    m_bestSegPath.push_back (*it);
 
577
                if (segmentPath.empty() || segmentPath.back() != *it)
 
578
                    segmentPath.push_back(*it);
473
579
            }
474
580
        }
475
581
 
476
 
        m_bestPath.push_back (end);
 
582
        path.push_back(end);
477
583
        bs = bs->m_pBackTraceNode;
478
584
    }
479
585
 
480
 
    std::reverse (m_bestPath.begin(), m_bestPath.end());
481
 
    std::reverse (m_bestSegPath.begin(), m_bestSegPath.end());
482
 
 
483
 
    if (m_pPySegmentor)
484
 
        m_pPySegmentor->notify_best_segpath (m_bestSegPath);
 
586
    std::reverse(path.begin(), path.end());
 
587
    std::reverse(segmentPath.begin(), segmentPath.end());
485
588
 
486
589
#ifdef DEBUG
487
590
    std::vector<unsigned>::iterator it;
488
591
 
489
 
    printf ("best lattice path: ");
490
 
    for (it = m_bestPath.begin(); it != m_bestPath.end(); ++it)
491
 
        printf ("%d ", *it);
 
592
    printf("trace lattice path[%d]: ", rank);
 
593
    for (it = path.begin(); it != path.end(); ++it)
 
594
        printf("%d ", *it);
 
595
    printf("\n");
492
596
 
493
 
    printf ("best segments path: ");
494
 
    for (it = m_bestSegPath.begin(); it != m_bestSegPath.end(); ++it)
495
 
        printf ("%d ", *it);
496
 
    printf ("\n");
 
597
    printf("trace segments path[%d]: ", rank);
 
598
    for (it = segmentPath.begin(); it != segmentPath.end(); ++it)
 
599
        printf("%d ", *it);
 
600
    printf("\n");
497
601
#endif
498
602
 
499
 
}
500
 
 
501
 
void CIMIContext::_clearBestPaths ()
502
 
{
503
 
    m_bestPath.clear ();
504
 
    m_bestSegPath.clear ();
505
 
}
506
 
 
507
 
unsigned CIMIContext::getBestSentence (wstring& result, unsigned start, unsigned end)
508
 
{
509
 
    result.clear();
510
 
 
511
 
    if (UINT_MAX == end) end = m_tailIdx - 1;
512
 
 
513
 
    while (end > start && m_lattice[end].m_bwType == CLatticeFrame::NO_BESTWORD)
514
 
        end --;
515
 
 
516
 
    unsigned i = end, nWordConverted = 0;
517
 
    while (i > start) {
518
 
        CLatticeFrame &fr = m_lattice[i];
519
 
        result.insert (0, fr.m_bestWord.m_cwstr);
520
 
        i = fr.m_bestWord.m_start;
521
 
        nWordConverted ++;
522
 
    }
523
 
 
524
 
    return nWordConverted;
525
 
}
526
 
 
527
 
unsigned CIMIContext::getBestSentence (std::vector<unsigned>& result, unsigned start, unsigned end)
528
 
{
529
 
    result.clear();
530
 
 
531
 
    if (UINT_MAX == end) end = m_tailIdx - 1;
532
 
 
533
 
    while (end > start && m_lattice[end].m_bwType == CLatticeFrame::NO_BESTWORD)
534
 
        end --;
535
 
 
536
 
    unsigned i = end, nWordConverted = 0;
537
 
    while (i > start) {
538
 
        CLatticeFrame &fr = m_lattice[i];
539
 
        result.insert (result.begin(), fr.m_bestWord.m_wordId);
540
 
        i = fr.m_bestWord.m_start;
541
 
        nWordConverted ++;
542
 
    }
543
 
 
544
 
    return nWordConverted;
 
603
    return true;
 
604
}
 
605
 
 
606
void
 
607
CIMIContext::_clearPaths()
 
608
{
 
609
    m_path.clear();
 
610
    m_segPath.clear();
 
611
}
 
612
 
 
613
std::vector<CCandidates>
 
614
CIMIContext::getBestSentenceTails(int rank, unsigned start, unsigned end)
 
615
{
 
616
    std::vector<CCandidates> result;
 
617
    if (rank < 0) {
 
618
        return result;
 
619
    }
 
620
 
 
621
    CCandidates sentence;
 
622
    unsigned word_num = getBestSentence(sentence, rank, start, end);
 
623
    unsigned tail_word_num = word_num;
 
624
 
 
625
    while (tail_word_num > 1) {
 
626
        unsigned dec = tail_word_num / (m_maxTailCandidateNum + 1) + 1;
 
627
        tail_word_num -= std::min(dec, tail_word_num);
 
628
        if (tail_word_num <= 1) {
 
629
            break;
 
630
        }
 
631
        CCandidates tail(sentence.begin(), sentence.begin() + tail_word_num);
 
632
        result.push_back(tail);
 
633
    }
 
634
    return result;
 
635
}
 
636
 
 
637
unsigned
 
638
CIMIContext::getBestSentence(CCandidates& result, int rank,
 
639
                             unsigned start, unsigned end)
 
640
{
 
641
    // -1 means selected sentence
 
642
    if (rank < -1 || rank >= (int) m_nBest)
 
643
        return 0;
 
644
 
 
645
    result.clear();
 
646
 
 
647
    if (end == UINT_MAX)
 
648
        end = m_tailIdx - 1;
 
649
 
 
650
    while (end > start && m_lattice[end].m_bwType == CLatticeFrame::NO_BESTWORD)
 
651
        end--;
 
652
 
 
653
    unsigned i = end, nWordConverted = 0;
 
654
    while (i > start) {
 
655
        CLatticeFrame& fr = m_lattice[i];
 
656
        if (rank < 0) {
 
657
            result.insert(result.begin(), fr.m_selWord);
 
658
            i = fr.m_selWord.m_start;
 
659
        } else {
 
660
            result.insert(result.begin(), fr.m_bestWords[rank]);
 
661
            i = fr.m_bestWords[rank].m_start;
 
662
        }
 
663
        nWordConverted++;
 
664
    }
 
665
    return nWordConverted;
 
666
}
 
667
 
 
668
unsigned
 
669
CIMIContext::getBestSentence(wstring& result, int rank,
 
670
                             unsigned start, unsigned end)
 
671
{
 
672
    CCandidates sentence;
 
673
    unsigned nWordConverted = getBestSentence(sentence, rank, start, end);
 
674
    result.clear();
 
675
    for (size_t i = 0; i < sentence.size(); i++) {
 
676
        result += sentence[i].m_cwstr;
 
677
    }
 
678
    return nWordConverted;
 
679
}
 
680
 
 
681
unsigned
 
682
CIMIContext::getBestSentence(std::vector<unsigned>& result, int rank,
 
683
                             unsigned start, unsigned end)
 
684
{
 
685
    CCandidates sentence;
 
686
    unsigned nWordConverted = getBestSentence(sentence, rank, start, end);
 
687
    result.clear();
 
688
    for (size_t i = 0; i < sentence.size(); i++) {
 
689
        result.push_back(sentence[i].m_wordId);
 
690
    }
 
691
    return nWordConverted;
 
692
}
 
693
 
 
694
 
 
695
unsigned
 
696
CIMIContext::getSelectedSentence(wstring& result,
 
697
                                 unsigned start, unsigned end)
 
698
{
 
699
    return getBestSentence(result, -1, start, end);
 
700
}
 
701
 
 
702
 
 
703
unsigned
 
704
CIMIContext::getSelectedSentence(std::vector<unsigned>& result,
 
705
                                 unsigned start, unsigned end)
 
706
{
 
707
    return getBestSentence(result, -1, start, end);
545
708
}
546
709
 
547
710
struct TCandiPair {
548
 
    CCandidate                      m_candi;
549
 
    TCandiRank                      m_Rank;
 
711
    CCandidate m_candi;
 
712
    TCandiRank m_Rank;
550
713
 
551
 
    TCandiPair() : m_candi(), m_Rank() { }
 
714
    TCandiPair() : m_candi(), m_Rank()
 
715
    {
 
716
    }
552
717
};
553
718
 
554
719
struct TCandiPairPtr {
555
720
    TCandiPair*                     m_Ptr;
556
721
 
557
 
    TCandiPairPtr(TCandiPair* p=NULL) : m_Ptr(p)
558
 
    { }
 
722
    TCandiPairPtr(TCandiPair* p = NULL) : m_Ptr(p)
 
723
    {
 
724
    }
559
725
 
560
726
    bool
561
 
    operator< (const TCandiPairPtr& b) const
562
 
    { return m_Ptr->m_Rank < b.m_Ptr->m_Rank; }
 
727
    operator<(const TCandiPairPtr& b) const
 
728
    {
 
729
        return m_Ptr->m_Rank < b.m_Ptr->m_Rank;
 
730
    }
563
731
};
564
732
 
565
 
const TWCHAR *CIMIContext::_getWstr (unsigned wid)
 
733
const TWCHAR *
 
734
CIMIContext::_getWstr(unsigned wid)
566
735
{
567
736
    if (wid < m_pPinyinTrie->getWordCount())
568
737
        return (*m_pPinyinTrie)[wid];
572
741
        return NULL;
573
742
}
574
743
 
575
 
void CIMIContext::getCandidates (unsigned frIdx, CCandidates& result)
 
744
void
 
745
CIMIContext::getCandidates(unsigned frIdx, CCandidates& result)
576
746
{
577
747
    TCandiPair cp;
578
 
    static std::map<wstring, TCandiPair> map;
579
 
    std::map<wstring, TCandiPair>::iterator it_map;
 
748
    static std::map<wstring, TCandiPair> candidates_map;
 
749
    std::map<wstring, TCandiPair>::iterator candidates_it;
580
750
 
581
 
    map.clear();
 
751
    candidates_map.clear();
582
752
    result.clear();
583
753
 
584
754
    std::vector<unsigned> st;
585
 
    getBestSentence (st, frIdx);
 
755
    getSelectedSentence(st, frIdx);
586
756
 
587
757
    cp.m_candi.m_start = m_candiStarts = frIdx++;
588
758
 
589
 
    for (;frIdx < m_tailIdx; ++frIdx)  {
590
 
        if (m_lattice[frIdx+1].isSyllableSepFrame())
 
759
    for (; frIdx < m_tailIdx; ++frIdx) {
 
760
        if (m_lattice[frIdx + 1].isSyllableSepFrame())
591
761
            continue;
592
762
 
593
763
        CLatticeFrame &fr = m_lattice[frIdx];
594
 
        if (!fr.isSyllableFrame ())
 
764
        if (!fr.isSyllableFrame())
595
765
            continue;
596
766
 
597
767
        cp.m_candi.m_end = frIdx;
598
 
        if (fr.m_bwType != CLatticeFrame::NO_BESTWORD && fr.m_bestWord.m_start == m_candiStarts) {
599
 
            cp.m_candi = fr.m_bestWord;
600
 
            TLexiconState & lxst = *(cp.m_candi.m_pLexiconState);
601
 
            int len = lxst.m_syls.size() - lxst.m_num_of_inner_fuzzies;
602
 
            if (0 == len) len = 1;
603
 
            cp.m_Rank = TCandiRank(fr.m_bwType & CLatticeFrame::USER_SELECTED,
604
 
                                   fr.m_bwType & CLatticeFrame::BESTWORD,
605
 
                                   len, false, 0);
606
 
            map [cp.m_candi.m_cwstr] = cp;
 
768
        if (fr.m_bwType != CLatticeFrame::NO_BESTWORD) {
 
769
            for (size_t i = 0; i < m_nBest; i++) {
 
770
                if (fr.m_bestWords.find(i) == fr.m_bestWords.end())
 
771
                    continue;
 
772
                CCandidate candi = fr.m_bestWords[i];
 
773
                if (candi.m_start != m_candiStarts)
 
774
                    continue;
 
775
                if (candi.m_pLexiconState == NULL)
 
776
                    continue;
 
777
 
 
778
                TLexiconState & lxst = *(candi.m_pLexiconState);
 
779
                int len = lxst.m_syls.size() - lxst.m_num_of_inner_fuzzies;
 
780
                if (len == 0) len = 1;
 
781
 
 
782
                cp.m_candi = candi;
 
783
                cp.m_Rank =
 
784
                    TCandiRank(fr.m_bwType & CLatticeFrame::USER_SELECTED,
 
785
                               fr.m_bwType & CLatticeFrame::BESTWORD,
 
786
                               len, false, 0);
 
787
                candidates_map[candi.m_cwstr] = cp;
 
788
            }
607
789
        }
608
790
 
609
791
        bool found = false;
610
 
        CLexiconStates::iterator it  = fr.m_lexiconStates.begin();
 
792
        CLexiconStates::iterator it = fr.m_lexiconStates.begin();
611
793
        CLexiconStates::iterator ite = fr.m_lexiconStates.end();
612
794
        for (; it != ite; ++it) {
613
795
            TLexiconState & lxst = *it;
620
802
 
621
803
            found = true;
622
804
            unsigned word_num;
623
 
            const CPinyinTrie::TWordIdInfo *words = lxst.getWords (word_num);
 
805
            const CPinyinTrie::TWordIdInfo *words = lxst.getWords(word_num);
624
806
 
625
 
            for (unsigned i=0; i<word_num; ++i) {
 
807
            for (unsigned i = 0; i < word_num; ++i) {
626
808
                if (m_csLevel < words[i].m_csLevel)
627
809
                    continue;
628
810
 
629
811
                cp.m_candi.m_wordId = words[i].m_id;
630
 
                cp.m_candi.m_cwstr = _getWstr (cp.m_candi.m_wordId);
 
812
                cp.m_candi.m_cwstr = _getWstr(cp.m_candi.m_wordId);
631
813
                cp.m_candi.m_pLexiconState = &lxst;
632
814
                if (!cp.m_candi.m_cwstr)
633
815
                    continue;
634
816
 
635
817
                //sorting according to the order in PinYinTire
636
 
                cp.m_Rank = TCandiRank(false, !st.empty() && st.front() == cp.m_candi.m_wordId,
637
 
                                       len, false, i);
638
 
                it_map = map.find(cp.m_candi.m_cwstr);
639
 
                if (it_map == map.end() || cp.m_Rank < it_map->second.m_Rank || cp.m_candi.m_wordId > INI_USRDEF_WID)
640
 
                    map [cp.m_candi.m_cwstr] = cp;
 
818
                cp.m_Rank =
 
819
                    TCandiRank(false,
 
820
                               !st.empty() && st.front() == cp.m_candi.m_wordId,
 
821
                               len, false, i);
 
822
                candidates_it = candidates_map.find(cp.m_candi.m_cwstr);
 
823
                if (candidates_it == candidates_map.end()
 
824
                    || cp.m_Rank < candidates_it->second.m_Rank
 
825
                    || cp.m_candi.m_wordId > INI_USRDEF_WID)
 
826
                    candidates_map[cp.m_candi.m_cwstr] = cp;
641
827
            }
642
828
        }
643
829
 
644
 
        if (!found) continue; // FIXME: need better solution later
 
830
        if (!found) continue;  // FIXME: need better solution later
645
831
 
646
832
        if (m_bDynaCandiOrder) {
647
 
            CLatticeStates::iterator it  = fr.m_latticeStates.begin();
 
833
            CLatticeStates::iterator it = fr.m_latticeStates.begin();
648
834
            CLatticeStates::iterator ite = fr.m_latticeStates.end();
649
835
            for (; it != ite; ++it) {
650
836
                TLatticeState & ltst = *it;
653
839
                    continue;
654
840
 
655
841
                cp.m_candi.m_wordId = ltst.m_backTraceWordId;
656
 
                cp.m_candi.m_cwstr = _getWstr (cp.m_candi.m_wordId);
 
842
                cp.m_candi.m_cwstr = _getWstr(cp.m_candi.m_wordId);
657
843
                cp.m_candi.m_pLexiconState = ltst.m_pLexiconState;
658
844
                if (!cp.m_candi.m_cwstr)
659
845
                    continue;
661
847
                int len = cp.m_candi.m_pLexiconState->m_syls.size() -
662
848
                          cp.m_candi.m_pLexiconState->m_num_of_inner_fuzzies;
663
849
                if (0 == len) len = 1;
664
 
                cp.m_Rank = TCandiRank(false, !st.empty() && st.front() == cp.m_candi.m_wordId,
665
 
                                       len, true, ltst.m_score/ltst.m_pBackTraceNode->m_score);
666
 
                it_map = map.find(cp.m_candi.m_cwstr);
667
 
                if (it_map == map.end() || cp.m_Rank < it_map->second.m_Rank || cp.m_candi.m_wordId > INI_USRDEF_WID)
668
 
                    map[cp.m_candi.m_cwstr] = cp;
 
850
                cp.m_Rank = TCandiRank(false,
 
851
                                       !st.empty() && st.front() ==
 
852
                                       cp.m_candi.m_wordId,
 
853
                                       len, true, ltst.m_score /
 
854
                                       ltst.m_pBackTraceNode->m_score);
 
855
                candidates_it = candidates_map.find(cp.m_candi.m_cwstr);
 
856
                if (candidates_it == candidates_map.end()
 
857
                    || cp.m_Rank < candidates_it->second.m_Rank
 
858
                    || cp.m_candi.m_wordId > INI_USRDEF_WID)
 
859
                    candidates_map[cp.m_candi.m_cwstr] = cp;
669
860
            }
670
861
        }
671
862
 
674
865
 
675
866
    std::vector<TCandiPairPtr> vec;
676
867
 
677
 
    vec.reserve(map.size());
678
 
    std::map<wstring, TCandiPair>::iterator it_mapE = map.end();
679
 
    for (it_map = map.begin(); it_map != it_mapE; ++it_map)
680
 
        vec.push_back(TCandiPairPtr(&(it_map->second)));
681
 
    std::make_heap(vec.begin(), vec.end());
682
 
    std::sort_heap(vec.begin(), vec.end());
 
868
    vec.reserve(candidates_map.size());
 
869
    for (candidates_it = candidates_map.begin();
 
870
         candidates_it != candidates_map.end(); ++candidates_it) {
 
871
        vec.push_back(TCandiPairPtr(&(candidates_it->second)));
 
872
    }
683
873
 
684
 
    for (int i=0, sz=vec.size(); i < sz; ++i)
 
874
    std::sort(vec.begin(), vec.end());
 
875
    for (size_t i = 0; i < vec.size(); i++) {
685
876
        result.push_back(vec[i].m_Ptr->m_candi);
 
877
    }
686
878
}
687
879
 
688
 
unsigned CIMIContext::cancelSelection (unsigned frIdx, bool doSearch)
 
880
unsigned
 
881
CIMIContext::cancelSelection(unsigned frIdx, bool doSearch)
689
882
{
690
883
    unsigned ret = frIdx;
691
884
 
694
887
        --frIdx;
695
888
        fr = m_lattice[frIdx];
696
889
    }
697
 
    
698
 
    if (fr.m_bwType & (CLatticeFrame::USER_SELECTED | CLatticeFrame::BESTWORD)) {
699
 
        ret = fr.m_bestWord.m_start;
 
890
 
 
891
    if (fr.m_bwType &
 
892
        (CLatticeFrame::USER_SELECTED | CLatticeFrame::BESTWORD)) {
 
893
        ret = fr.m_selWord.m_start;
700
894
        fr.m_bwType = CLatticeFrame::NO_BESTWORD;
701
 
        if (doSearch) searchFrom (frIdx);
 
895
        if (doSearch) searchFrom(frIdx);
702
896
    }
703
897
 
704
898
    return ret;
705
899
}
706
900
 
707
 
void CIMIContext::makeSelection (CCandidate &candi, bool doSearch)
 
901
void
 
902
CIMIContext::makeSelection(CCandidate &candi, bool doSearch)
708
903
{
709
904
    CLatticeFrame &fr = m_lattice[candi.m_end];
710
905
    fr.m_bwType = fr.m_bwType | CLatticeFrame::USER_SELECTED;
711
 
    fr.m_bestWord = candi;
712
 
    if (doSearch) searchFrom (candi.m_end);
713
 
}
714
 
 
715
 
void CIMIContext::memorize ()
716
 
{
717
 
    _saveUserDict ();
718
 
    _saveHistoryCache ();
719
 
}
720
 
 
721
 
void CIMIContext::_saveUserDict ()
 
906
    fr.m_selWord = candi;
 
907
    // make best sentence word consistent as well
 
908
    for (size_t i = 0; i < m_nBest; i++) {
 
909
        fr.m_bestWords[i] = candi;
 
910
    }
 
911
 
 
912
    if (doSearch) searchFrom(candi.m_end);
 
913
}
 
914
 
 
915
void
 
916
CIMIContext::selectSentence(int idx)
 
917
{
 
918
    unsigned i = m_tailIdx - 1;
 
919
    while (i > 0 && m_lattice[i].m_bwType == CLatticeFrame::NO_BESTWORD)
 
920
        i--;
 
921
 
 
922
    while (i > 0) {
 
923
        CLatticeFrame &fr = m_lattice[i];
 
924
        fr.m_selWord = fr.m_bestWords[idx];
 
925
        i = fr.m_selWord.m_start;
 
926
    }
 
927
}
 
928
 
 
929
void
 
930
CIMIContext::memorize()
 
931
{
 
932
    _saveUserDict();
 
933
    _saveHistoryCache();
 
934
}
 
935
 
 
936
void
 
937
CIMIContext::_saveUserDict()
722
938
{
723
939
    if (!m_pUserDict)
724
940
        return;
725
941
 
726
 
    if (m_bestPath.empty())
727
 
        return;
728
 
    
729
942
    CSyllables syls;
730
 
    unsigned s = 0;
731
943
    bool has_user_selected = false;
732
 
    std::vector<unsigned>::iterator it  = m_bestPath.begin();
733
 
    std::vector<unsigned>::iterator ite = m_bestPath.end();
734
 
    for (; it != ite; ++it, ++s) {
735
 
        CLatticeFrame &fr = m_lattice[*it];
736
 
        if (!fr.isSyllableFrame ()) {
737
 
            --it;
738
 
            break;
739
 
        }
740
 
 
741
 
        CSyllables &tmp = fr.m_bestWord.m_pLexiconState->m_syls;
742
 
        if (syls.size() + tmp.size() > MAX_USRDEF_WORD_LEN) {
743
 
            --it;
744
 
            break;
745
 
        }
 
944
    unsigned i = m_tailIdx - 1;
 
945
    unsigned e_pos = 0;
 
946
 
 
947
    while (i > 0 && m_lattice[i].m_bwType == CLatticeFrame::NO_BESTWORD)
 
948
        i--;
 
949
 
 
950
    while (i > 0) {
 
951
        CLatticeFrame &fr = m_lattice[i];
 
952
        if (!fr.isSyllableFrame()) {
 
953
            i = fr.m_selWord.m_start;
 
954
            break;
 
955
        }
 
956
 
 
957
        TLexiconState* state = fr.m_selWord.m_pLexiconState;
 
958
        if (!state) {
 
959
            i = fr.m_selWord.m_start;
 
960
            continue;
 
961
        }
 
962
 
 
963
        if (syls.size() + state->m_syls.size() > MAX_USRDEF_WORD_LEN) {
 
964
            i = fr.m_selWord.m_start;
 
965
            break;
 
966
        }
 
967
 
 
968
        if (!e_pos) e_pos = i;
746
969
 
747
970
        has_user_selected |= (fr.m_bwType & CLatticeFrame::USER_SELECTED);
748
 
        std::copy (tmp.begin(), tmp.end(), back_inserter(syls));
 
971
        std::copy(state->m_syls.begin(), state->m_syls.end(), inserter(syls, syls.begin()));
 
972
        i = fr.m_selWord.m_start;
749
973
    }
750
974
 
751
 
    if (s >= 2 && has_user_selected && !syls.empty()) {
 
975
    if (has_user_selected && syls.size() > 1) {
752
976
        wstring phrase;
753
 
        getBestSentence (phrase, 0, *it);
 
977
        getSelectedSentence (phrase, 0, e_pos);
754
978
        m_pUserDict->addWord (syls, phrase);
755
979
    }
756
980
}
757
981
 
758
 
void CIMIContext::_saveHistoryCache ()
 
982
void
 
983
CIMIContext::_saveHistoryCache()
759
984
{
760
985
    if (!m_pHistory)
761
986
        return;
762
987
 
763
 
    if (m_bestPath.empty())
764
 
        return;
765
 
 
766
988
    std::vector<unsigned> result;
767
 
    std::vector<unsigned>::const_iterator it  = m_bestPath.begin();
768
 
    std::vector<unsigned>::const_iterator ite = m_bestPath.end() - 1;
769
 
    for (; it != ite; ++it) {
770
 
        CLatticeFrame &fr = m_lattice[*it];
771
 
        if (fr.isSyllableFrame ())
772
 
            result.push_back (fr.m_bestWord.m_wordId);
773
 
        else 
774
 
            result.push_back (0);
 
989
    unsigned i = m_tailIdx - 1;
 
990
    while (i > 0 && m_lattice[i].m_bwType == CLatticeFrame::NO_BESTWORD)
 
991
        i--;
 
992
 
 
993
    while (i > 0) {
 
994
        CLatticeFrame &fr = m_lattice[i];
 
995
        if (fr.isSyllableFrame()) {
 
996
            result.insert(result.begin(), fr.m_selWord.m_wordId);
 
997
        } else {
 
998
            result.insert(result.begin(), 0);
 
999
        }
 
1000
        i = fr.m_selWord.m_start;
775
1001
    }
776
1002
 
777
1003
    if (!result.empty())
778
 
        m_pHistory->memorize (&(result[0]), &(result[0]) + result.size());
779
 
 
 
1004
        m_pHistory->memorize(&(result[0]), &(result[0]) + result.size());
780
1005
}
781
1006
 
782
 
void CIMIContext::deleteCandidate (CCandidate &candi)
 
1007
void
 
1008
CIMIContext::deleteCandidate(CCandidate &candi)
783
1009
{
784
1010
    unsigned wid = candi.m_wordId;
785
1011
 
786
1012
    if (wid > INI_USRDEF_WID) {
787
 
        m_pHistory->forget (wid);
788
 
        m_pUserDict->removeWord (wid);
789
 
        _buildLattice (m_pPySegmentor->getSegments(), candi.m_start+1);
 
1013
        m_pHistory->forget(wid);
 
1014
        m_pUserDict->removeWord(wid);
 
1015
        _buildLattice(m_pPySegmentor->getSegments(), candi.m_start + 1);
790
1016
    }
791
1017
}
792
1018
 
793
 
void CIMIContext::removeFromHistoryCache (std::vector<unsigned>& wids)
 
1019
void
 
1020
CIMIContext::removeFromHistoryCache(std::vector<unsigned>& wids)
794
1021
{
795
1022
    if (!m_pHistory)
796
1023
        return;
797
1024
 
798
 
    m_pHistory->forget (&(wids[0]), &(wids[0]) + wids.size());
799
 
    buildLattice (m_pPySegmentor);
 
1025
    m_pHistory->forget(&(wids[0]), &(wids[0]) + wids.size());
 
1026
    buildLattice(m_pPySegmentor);
800
1027
}