5a0030e4f72613280f93fb9c5939fbf86b70d61f
[platform/upstream/libpinyin.git] / utils / storage / import_interpolation.cpp
1 /* 
2  *  libpinyin
3  *  Library to deal with pinyin.
4  *  
5  *  Copyright (C) 2010 Peng Wu
6  *  
7  *  This program is free software; you can redistribute it and/or modify
8  *  it under the terms of the GNU General Public License as published by
9  *  the Free Software Foundation; either version 2 of the License, or
10  *  (at your option) any later version.
11  * 
12  *  This program is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  *  GNU General Public License for more details.
16  *  
17  *  You should have received a copy of the GNU General Public License
18  *  along with this program; if not, write to the Free Software
19  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
20  */
21
22 #include <stdio.h>
23 #include <locale.h>
24 #include <glib.h>
25 #include "pinyin_internal.h"
26 #include "utils_helper.h"
27
28
29 static const gchar * table_dir = ".";
30
31 static GOptionEntry entries[] =
32 {
33     {"table-dir", 0, 0, G_OPTION_ARG_FILENAME, &table_dir, "table directory", NULL},
34     {NULL}
35 };
36
37
38 enum LINE_TYPE{
39     BEGIN_LINE = 1,
40     END_LINE,
41     GRAM_1_LINE,
42     GRAM_2_LINE,
43     GRAM_1_ITEM_LINE,
44     GRAM_2_ITEM_LINE
45 };
46
47 static int line_type = 0;
48 static GPtrArray * values = NULL;
49 static GHashTable * required = NULL;
50 /* variables for line buffer. */
51 static char * linebuf = NULL;
52 static size_t len = 0;
53
54 bool parse_headline();
55
56 bool parse_unigram(FILE * input, PhraseLargeTable2 * phrase_table,
57                    FacadePhraseIndex * phrase_index);
58
59 bool parse_bigram(FILE * input, PhraseLargeTable2 * phrase_table,
60                   FacadePhraseIndex * phrase_index,
61                   Bigram * bigram);
62
63 static ssize_t my_getline(FILE * input){
64     ssize_t result = getline(&linebuf, &len, input);
65     if ( result == -1 )
66         return result;
67
68     if ( '\n' == linebuf[strlen(linebuf) - 1] ) {
69         linebuf[strlen(linebuf) - 1] = '\0';
70     }
71     return result;
72 }
73
74 bool parse_headline(){
75     /* enter "\data" line */
76     assert(taglib_add_tag(BEGIN_LINE, "\\data", 0, "model", ""));
77
78     /* read "\data" line */
79     if ( !taglib_read(linebuf, line_type, values, required) ) {
80         fprintf(stderr, "error: interpolation model expected.\n");
81         return false;
82     }
83
84     assert(line_type == BEGIN_LINE);
85     /* check header */
86     TAGLIB_GET_TAGVALUE(const char *, model, (const char *));
87     if ( !( strcmp("interpolation", model) == 0 ) ) {
88         fprintf(stderr, "error: interpolation model expected.\n");
89         return false;
90     }
91     return true;
92 }
93
94 bool parse_body(FILE * input, PhraseLargeTable2 * phrase_table,
95                 FacadePhraseIndex * phrase_index,
96                 Bigram * bigram){
97     taglib_push_state();
98
99     assert(taglib_add_tag(END_LINE, "\\end", 0, "", ""));
100     assert(taglib_add_tag(GRAM_1_LINE, "\\1-gram", 0, "", ""));
101     assert(taglib_add_tag(GRAM_2_LINE, "\\2-gram", 0, "", ""));
102
103     do {
104     retry:
105         assert(taglib_read(linebuf, line_type, values, required));
106         switch(line_type) {
107         case END_LINE:
108             goto end;
109         case GRAM_1_LINE:
110             my_getline(input);
111             parse_unigram(input, phrase_table, phrase_index);
112             goto retry;
113         case GRAM_2_LINE:
114             my_getline(input);
115             parse_bigram(input, phrase_table, phrase_index, bigram);
116             goto retry;
117         default:
118             assert(false);
119         }
120     } while (my_getline(input) != -1) ;
121
122  end:
123     taglib_pop_state();
124     return true;
125 }
126
127 bool parse_unigram(FILE * input, PhraseLargeTable2 * phrase_table,
128                    FacadePhraseIndex * phrase_index){
129     taglib_push_state();
130
131     assert(taglib_add_tag(GRAM_1_ITEM_LINE, "\\item", 2, "count", ""));
132
133     do {
134         assert(taglib_read(linebuf, line_type, values, required));
135         switch (line_type) {
136         case GRAM_1_ITEM_LINE:{
137             /* handle \item in \1-gram */
138             TAGLIB_GET_TOKEN(token, 0);
139             TAGLIB_GET_PHRASE_STRING(word, 1);
140             assert(taglib_validate_token_with_string
141                    (phrase_index, token, word));
142
143             TAGLIB_GET_TAGVALUE(glong, count, atol);
144             phrase_index->add_unigram_frequency(token, count);
145             break;
146         }
147         case END_LINE:
148         case GRAM_1_LINE:
149         case GRAM_2_LINE:
150             goto end;
151         default:
152             assert(false);
153         }
154     } while (my_getline(input) != -1);
155
156  end:
157     taglib_pop_state();
158     return true;
159 }
160
161 bool parse_bigram(FILE * input, PhraseLargeTable2 * phrase_table,
162                   FacadePhraseIndex * phrase_index,
163                   Bigram * bigram){
164     taglib_push_state();
165
166     assert(taglib_add_tag(GRAM_2_ITEM_LINE, "\\item", 4, "count", ""));
167
168     phrase_token_t last_token = 0; SingleGram * last_single_gram = NULL;
169     do {
170         assert(taglib_read(linebuf, line_type, values, required));
171         switch (line_type) {
172         case GRAM_2_ITEM_LINE:{
173             /* handle \item in \2-gram */
174             /* two tokens */
175             TAGLIB_GET_TOKEN(token1, 0);
176             TAGLIB_GET_PHRASE_STRING(word1, 1);
177             assert(taglib_validate_token_with_string
178                    (phrase_index, token1, word1));
179
180             TAGLIB_GET_TOKEN(token2, 2);
181             TAGLIB_GET_PHRASE_STRING(word2, 3);
182             assert(taglib_validate_token_with_string
183                    (phrase_index, token2, word2));
184
185             TAGLIB_GET_TAGVALUE(glong, count, atol);
186
187             if ( last_token != token1 ) {
188                 if ( last_token && last_single_gram ) {
189                     bigram->store(last_token, last_single_gram);
190                     delete last_single_gram;
191                     //safe guard
192                     last_token = 0;
193                     last_single_gram = NULL;
194                 }
195                 SingleGram * single_gram = NULL;
196                 bigram->load(token1, single_gram);
197
198                 //create the new single gram
199                 if ( single_gram == NULL )
200                     single_gram = new SingleGram;
201                 last_token = token1;
202                 last_single_gram = single_gram;
203             }
204             //save the freq
205             guint32 total_freq = 0;
206             assert(last_single_gram->get_total_freq(total_freq));
207             assert(last_single_gram->insert_freq(token2, count));
208             total_freq += count;
209             assert(last_single_gram->set_total_freq(total_freq));
210             break;
211         }
212         case END_LINE:
213         case GRAM_1_LINE:
214         case GRAM_2_LINE:
215             goto end;
216         default:
217             assert(false);
218         }
219     } while (my_getline(input) != -1);
220
221  end:
222     if ( last_token && last_single_gram ) {
223         bigram->store(last_token, last_single_gram);
224         delete last_single_gram;
225         //safe guard
226         last_token = 0;
227         last_single_gram = NULL;
228     }
229
230     taglib_pop_state();
231     return true;
232 }
233
234 int main(int argc, char * argv[]){
235     FILE * input = stdin;
236     const char * bigram_filename = "bigram.db";
237
238     setlocale(LC_ALL, "");
239
240     GError * error = NULL;
241     GOptionContext * context;
242
243     context = g_option_context_new("- import interpolation model");
244     g_option_context_add_main_entries(context, entries, NULL);
245     if (!g_option_context_parse(context, &argc, &argv, &error)) {
246         g_print("option parsing failed:%s\n", error->message);
247         exit(EINVAL);
248     }
249
250     SystemTableInfo system_table_info;
251
252     gchar * filename = g_build_filename(table_dir, "table.conf", NULL);
253     bool retval = system_table_info.load(filename);
254     if (!retval) {
255         fprintf(stderr, "load table.conf failed.\n");
256         exit(ENOENT);
257     }
258     g_free(filename);
259
260     PhraseLargeTable2 phrase_table;
261
262     MemoryChunk * chunk = new MemoryChunk;
263     retval = chunk->load("phrase_index.bin");
264     if (!retval) {
265         fprintf(stderr, "open phrase_index.bin failed!\n");
266         exit(ENOENT);
267     }
268     phrase_table.load(chunk);
269
270     FacadePhraseIndex phrase_index;
271
272     const pinyin_table_info_t * phrase_files =
273         system_table_info.get_table_info();
274
275     if (!load_phrase_index(phrase_files, &phrase_index))
276         exit(ENOENT);
277
278     Bigram bigram;
279     retval = bigram.attach(bigram_filename, ATTACH_CREATE|ATTACH_READWRITE);
280     if (!retval) {
281         fprintf(stderr, "open %s failed!\n", bigram_filename);
282         exit(ENOENT);
283     }
284
285     taglib_init();
286
287     values = g_ptr_array_new();
288     required = g_hash_table_new(g_str_hash, g_str_equal);
289
290     /* read first line */
291     ssize_t result = my_getline(input);
292     if ( result == -1 ) {
293         fprintf(stderr, "empty file input.\n");
294         exit(ENODATA);
295     }
296
297     if (!parse_headline())
298         exit(ENODATA);
299
300     result = my_getline(input);
301     if ( result != -1 )
302         parse_body(input, &phrase_table, &phrase_index, &bigram);
303
304     taglib_fini();
305
306     if (!save_phrase_index(phrase_files, &phrase_index))
307         exit(ENOENT);
308
309     return 0;
310 }