Move .so file to devel package
[platform/core/uifw/anthy.git] / calctrans / calctrans.c
1 /*
2  * Ê¸Àá¤ÎÁ«°Ü¹ÔÎó¤òºîÀ®¤¹¤ë
3  *
4  * ¤³¤Î¥³¥Þ¥ó¥É¤ÏÆó¤Ä¤Îµ¡Ç½¤ò»ý¤Ã¤Æ¤¤¤ë¡£(-c¥ª¥×¥·¥ç¥ó¤ÇÀ©¸æ)
5  * (1) proccorpus¤Î·ë²Ì¤«¤é¥Æ¥­¥¹¥È·Á¼°¤Ç·Ð¸³Åª³ÊΨ¤Îɽ¤òºî¤ë
6  * (2) ¥Æ¥­¥¹¥È·Á¼°¤Îɽ¤«¤é¥Ð¥¤¥Ê¥ê·Á¼°¤ËÊÑ´¹¤¹¤ë
7  *
8  * morphological-analyzer¤Î½ÐÎϤˤϲ¼µ­¤Î¥Þ¡¼¥¯¤¬ÉÕ¤±¤Æ¤¢¤ë
9  * ~ ¸õÊä¤Î¸í¤ê
10  * ! Ê¸ÀáŤθí¤ê
11  * ^ Ê£¹çʸÀá¤Î2¤Ä¤á°Ê¹ß¤ÎÍ×ÁÇ
12  *
13  * generate transition matrix
14  *
15  * Copyright (C) 2006 HANAOKA Toshiyuki
16  * Copyright (C) 2006-2007 TABATA Yusuke
17  *
18  */
19 /*
20   This library is free software; you can redistribute it and/or
21   modify it under the terms of the GNU Lesser General Public
22   License as published by the Free Software Foundation; either
23   version 2 of the License, or (at your option) any later version.
24
25   This library is distributed in the hope that it will be useful,
26   but WITHOUT ANY WARRANTY; without even the implied warranty of
27   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
28   Lesser General Public License for more details.
29
30   You should have received a copy of the GNU Lesser General Public
31   License along with this library; if not, write to the Free Software
32   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
33  */
34 #include <stdio.h>
35 #include <string.h>
36 #include <stdlib.h>
37 #include <math.h>
38
39 #include <anthy/anthy.h>
40 #include <anthy/xstr.h>
41 #include <anthy/feature_set.h>
42 #include <anthy/diclib.h>
43 #include "input_set.h"
44 #include <anthy/corpus.h>
45
46 #define FEATURE_SET_SIZE NR_EM_FEATURES
47
48 #define ARRAY_SIZE 16
49
50 struct array {
51   int len;
52   int f[ARRAY_SIZE];
53 };
54
55 #define MAX_SEGMENT 64
56
57 struct segment_info {
58   int orig_hash;
59   int hash;
60 };
61
62 struct sentence_info {
63   int nr_segments;
64   struct segment_info segs[MAX_SEGMENT];
65 };
66
67 /* ³ÎΨ¤Î¥Æ¡¼¥Ö¥ë */
68 struct input_info {
69   /* ¸õÊäÁ´ÂΤÎÁÇÀ­ */
70   struct input_set *cand_is;
71   /* Ê¸Àá¤ÎÁÇÀ­ */
72   struct input_set *seg_is;
73   /* ¼«Î©¸ì¤ÎÁ´Ê¸¸¡º÷ÍѾðÊó */
74   struct corpus *indep_corpus;
75
76   /**/
77   struct array missed_cand_features;
78
79   /**/
80   int nth_input_file;
81
82   /* ÆþÎϤµ¤ì¤¿Îãʸ¤ÎÎ̤˴ؤ¹¤ë¾ðÊó */
83   int nr_sentences;
84   int nr_connections;
85 };
86
87 static struct input_info *
88 init_input_info(void)
89 {
90   struct input_info *m;
91   m = malloc(sizeof(struct input_info));
92   m->seg_is = input_set_create();
93   m->cand_is = input_set_create();
94   m->indep_corpus = corpus_new();
95   m->missed_cand_features.len = 0;
96   m->nth_input_file = 0;
97   m->nr_sentences = 0;
98   m->nr_connections = 0;
99   return m;
100 }
101
102 /* features=1,2,3,,¤Î·Á¼°¤òparse¤¹¤ë */
103 static void
104 parse_features(struct array *features, char *s)
105 {
106   char *tok, *str = s;
107   tok = strtok(str, ",");
108   features->len = 0;
109   do {
110     features->f[features->len] = atoi(tok);
111     features->len++;
112     tok = strtok(NULL, ",");
113   } while(tok);
114 }
115
116 static void
117 add_seg_struct_info(struct input_info *m,
118                     struct array *features,
119                     int weight)
120 {
121   input_set_set_features(m->cand_is, features->f, features->len, weight);
122 }
123
124 static void
125 set_hash(struct sentence_info *sinfo, int error_class,
126          char tag, int hash)
127 {
128   if (tag == '~') {
129     sinfo->segs[sinfo->nr_segments].orig_hash = hash;
130   } else {
131     sinfo->segs[sinfo->nr_segments].hash = hash;
132   }
133   if (!error_class) {
134     sinfo->nr_segments++;
135   }
136 }
137
138 static int
139 compare_array(struct array *a1, struct array *a2)
140 {
141   int i;
142   if (a1->len != a2->len) {
143     return 1;
144   }
145   for (i = 0; i < a1->len; i++) {
146     if (a1->f[i] != a2->f[i]) {
147       return 1;
148     }
149   }
150   return 0;
151 }
152
153 /* ¼«Î©¸ì¤Î¹Ô¤òparse¤¹¤ë */
154 static void
155 parse_indep(struct input_info *m, struct sentence_info *sinfo,
156             char *line, char *buf, int error_class)
157 {
158   struct array features;
159   char *s;
160   int weight = 1;
161   /**/
162   s = strstr(buf, "features=");
163   if (s) {
164     s += 9;
165     parse_features(&features, s);
166     m->nr_connections ++;
167   }
168   s = strstr(buf, "hash=");
169   if (s) {
170     s += 5;
171     set_hash(sinfo, error_class, line[0], atoi(s));
172   }
173
174   /* ²Ã»»¤¹¤ë */
175   if (error_class) {
176     if (line[0] == '~') {
177       /* ¸í¤Ã¤¿¸õÊä¤Î¹½Â¤¤òÊݸ */
178       m->missed_cand_features = features;
179     }
180     if (line[0] == '!') {
181       /* Ê¸ÀáŤθí¤ê */
182       input_set_set_features(m->seg_is, features.f, features.len, -weight);
183     }
184   } else {
185     /* Àܳ¹ÔÎó */
186     input_set_set_features(m->seg_is, features.f, features.len, weight);
187     /* ¸õÊä¤Î¹½Â¤ */
188     if (m->missed_cand_features.len != 0 &&
189         compare_array(&features, &m->missed_cand_features)) {
190       /* Àµ²ò¤È°Û¤Ê¤ë¹½Â¤¤Ê¤éʬÊì¤Ë²Ã»» */
191       add_seg_struct_info(m, &m->missed_cand_features, -weight);
192     }
193     m->missed_cand_features.len = 0;
194     add_seg_struct_info(m, &features, weight);
195   }
196 }
197
198 static void
199 init_sentence_info(struct sentence_info *sinfo)
200 {
201   int i;
202   sinfo->nr_segments = 0;
203   for (i = 0; i < MAX_SEGMENT; i++) {
204     sinfo->segs[i].orig_hash = 0;
205     sinfo->segs[i].hash = 0;
206   }
207 }
208
209 /* °ì¤Ä¤Îʸ¤òÆɤó¤À¤È¤­¤ËÁ´Ê¸¸¡º÷ÍѤΥǡ¼¥¿¤òºî¤ë
210  */
211 static void
212 complete_sentence_info(struct input_info *m, struct sentence_info *sinfo)
213 {
214   int i;
215   if (m->nth_input_file > 0) {
216     /* Æó¤Ä¤á°Ê¹ß¤ÎÆþÎÏ¥Õ¥¡¥¤¥ë¤Ï»È¤ï¤Ê¤¤ */
217     return ;
218   }
219   for (i = 0; i < sinfo->nr_segments; i++) {
220     int flags = ELM_NONE;
221     int nr = 1;
222     int buf[2];
223     if (i == 0) {
224       flags |= ELM_BOS;
225     }
226     /**/
227     buf[0] = sinfo->segs[i].hash;
228     if (sinfo->segs[i].orig_hash) {
229       /*
230       buf[1] = sinfo->segs[i].orig_hash;
231       nr ++;
232       */
233     }
234     corpus_push_back(m->indep_corpus, buf, nr, flags);
235   }
236 }
237
238 static void
239 do_read_file(struct input_info *m, FILE *fp)
240 {
241   char line[1024];
242   struct sentence_info sinfo;
243
244   init_sentence_info(&sinfo);
245
246   while (fgets(line, 1024, fp)) {
247     char *buf = line;
248     int error_class = 0;
249     if (!strncmp(buf, "eos", 3)) {
250       m->nr_sentences ++;
251       complete_sentence_info(m, &sinfo);
252       init_sentence_info(&sinfo);
253     }
254     if (line[0] == '~' || line[0] == '!' ||
255         line[0] == '^') {
256       buf ++;
257       error_class = 1;
258     }
259     if (!strncmp(buf, "indep_word", 10) ||
260         !strncmp(buf, "eos", 3)) {
261       parse_indep(m, &sinfo, line, buf, error_class);
262     }
263   }
264 }
265
266 static void
267 read_file(struct input_info *m, char *fn)
268 {
269   FILE *ifp;
270   ifp = fopen(fn, "r");
271   if (!ifp) {
272     return ;
273   }
274   do_read_file(m, ifp);
275   fclose(ifp);
276 }
277
278 static void
279 write_nl(FILE *fp, int i)
280 {
281   i = anthy_dic_htonl(i);
282   fwrite(&i, sizeof(int), 1, fp);
283 }
284
285 static void
286 dump_line(FILE *ofp, struct input_line *il)
287 {
288   int i;
289   for (i = 0; i < FEATURE_SET_SIZE || i < il->nr_features; i++) {
290     if (i) {
291       fprintf(ofp, ", ");
292     }
293     if (i < il->nr_features) {
294       fprintf(ofp, "%d", il->features[i]);
295     } else {
296       fprintf(ofp, "0");
297     }
298   }
299   fprintf(ofp,",%d,%d\n", (int)il->negative_weight, (int)il->weight);
300 }
301
302 static int
303 compare_line(const void *p1, const void *p2)
304 {
305   const struct input_line *const *il1 = p1;
306   const struct input_line *const *il2 = p2;
307   int i;
308   for (i = 0; i < (*il1)->nr_features &&
309          i < (*il2)->nr_features; i++) {
310     if ((*il1)->features[i] !=
311         (*il2)->features[i]) {
312       return (*il1)->features[i] - (*il2)->features[i];
313     }
314   }
315   return (*il1)->nr_features - (*il2)->nr_features;
316 }
317
318 static void
319 dump_features(FILE *ofp, struct input_set *is)
320 {
321   struct input_line *il, **lines;
322   int i, nr = 0;
323   int weight = 0;
324
325   /* count lines */
326   for (il = input_set_get_input_line(is); il; il = il->next_line) {
327     nr ++;
328     weight += (int)il->weight;
329   }
330   /* copy lines */
331   lines = malloc(sizeof(struct input_line *) * nr);
332   for (il = input_set_get_input_line(is), i = 0; i < nr;
333        i++, il = il->next_line) {
334     lines[i] = il;
335   }
336   /* sort */
337   qsort(lines, nr, sizeof(struct input_line *), compare_line);
338   /* output */
339   fprintf(ofp, "%d %d total_line_weight,count\n", weight, nr);
340   /**/
341   for (i = 0; i < nr; i++) {
342     dump_line(ofp, lines[i]);
343   }
344
345   free(lines);
346 }
347
348 static void
349 dump_input_info(FILE *ofp, struct input_info *m)
350 {
351   fprintf(ofp, "section anthy.trans_info ");
352   dump_features(ofp, m->seg_is);
353   fprintf(ofp, "section anthy.cand_info ");
354   dump_features(ofp, m->cand_is);
355   fprintf(ofp, "section anthy.corpus_bucket ");
356   corpus_write_bucket(ofp, m->indep_corpus);
357   fprintf(ofp, "section anthy.corpus_array ");
358   corpus_write_array(ofp, m->indep_corpus);
359   /**/
360   fprintf(ofp, "section anthy.feature_info ");
361   input_set_output_feature_freq(ofp, m->seg_is);
362 }
363
364 static void
365 convert_line(FILE *ofp, char *buf)
366 {
367   char *tok;
368   tok = strtok(buf, ",");
369   do {
370     int n = atoi(tok);
371     write_nl(ofp, n);
372     tok = strtok(NULL, ",");
373   } while (tok);
374 }
375
376 static void
377 convert_file(FILE *ifp)
378 {
379   char buf[1024];
380   FILE *ofp = NULL;
381   while (fgets(buf, 1024, ifp)) {
382     /**/
383     if (buf[0] == '#') {
384       continue;
385     }
386     if (!strncmp("section", buf, 7)) {
387       int w, n, i;
388       char fn[1024];
389       if (ofp) {
390         fclose(ofp);
391         ofp = NULL;
392       }
393       sscanf(buf, "section %s %d %d", fn, &w, &n);
394       ofp = fopen(fn, "w");
395       if (!ofp) {
396         fprintf(stderr, "failed to open (%s)\n", fn);
397         abort();
398       }
399       write_nl(ofp, w);
400       write_nl(ofp, n);
401       for (i = 0; i < NR_EM_FEATURES; i++) {
402         write_nl(ofp, 0);
403       }
404     } else {
405       convert_line(ofp, buf);
406     }
407   }
408   if (ofp) {
409     fclose(ofp);
410   }
411 }
412
413 static void
414 convert_data(int nr_fn, char **fns)
415 {
416   FILE *ifp;
417   int i;
418   /**/
419   for (i = 0; i < nr_fn; i++) {
420     ifp = fopen(fns[i], "r");
421     if (!ifp) {
422       fprintf(stderr, "failed to open (%s)\n", fns[i]);
423       continue;
424     }
425     convert_file(ifp);
426     fclose(ifp);
427   }
428 }
429
430 /**/
431 #define STRING_HASH_SIZE 256
432 struct string_node {
433   int key;
434   char *str;
435   struct string_node *next_hash;
436 };
437 struct string_pool {
438   int nr;
439   struct string_node hash[STRING_HASH_SIZE];
440   struct string_node **array;
441 };
442 struct resize_info {
443   char *indep;
444   int valid;
445 };
446 struct extract_stat {
447   int nr;
448   struct resize_info info[MAX_SEGMENT];
449 };
450
451 static void
452 string_pool_init(struct string_pool *sp)
453 {
454   int i;
455   for (i = 0; i < STRING_HASH_SIZE; i++) {
456     sp->hash[i].next_hash = NULL;
457   }
458   sp->nr = 0;
459 }
460
461 static int
462 compare_string_node(const void *p1, const void *p2)
463 {
464   const struct string_node *const *n1 = p1;
465   const struct string_node *const *n2 = p2;
466   return (*n1)->key -(*n2)->key;
467 }
468
469 static void
470 string_pool_sort(struct string_pool *sp)
471 {
472   int idx, h;
473   sp->array = malloc(sizeof(struct string_node *) * sp->nr);
474   for (idx = 0, h = 0; h < STRING_HASH_SIZE; h++) {
475     struct string_node *node;
476     for (node = sp->hash[h].next_hash; node; node = node->next_hash) {
477       sp->array[idx] = node;
478       idx ++;
479     }
480   }
481   /**/
482   qsort(sp->array, sp->nr, sizeof(struct string_node *), compare_string_node);
483 }
484
485 static void
486 string_pool_dump(FILE *ofp, struct string_pool *sp)
487 {
488   int i;
489   fprintf(ofp, "section anthy.weak_words 0 %d\n", sp->nr);
490   for (i = 0; i < sp->nr; i++) {
491     fprintf(ofp, "%d\n", sp->array[i]->key);
492   }
493 }
494
495 static unsigned int
496 string_hash(const unsigned char *str)
497 {
498   unsigned int h = 0;
499   while (*str) {
500     h += *str;
501     h *= 13;
502     str ++;
503   }
504   return h % STRING_HASH_SIZE;
505 }
506
507 static struct string_node *
508 find_string_node(struct string_pool *sp, const char *str)
509 {
510   int h = (int)string_hash((const unsigned char *)str);
511   struct string_node *node;
512   for (node = sp->hash[h].next_hash; node; node = node->next_hash) {
513     if (!strcmp(str, node->str)) {
514       return node;
515     }
516   }
517   /* allocate new */
518   node = malloc(sizeof(*node));
519   node->str = strdup(str);
520   node->key = 0;
521   node->next_hash = sp->hash[h].next_hash;
522   sp->hash[h].next_hash = node;
523   sp->nr ++;
524   return node;
525 }
526
527 static void
528 flush_extract_stat(struct extract_stat *es, struct string_pool *sp)
529 {
530   int i;
531   for (i = 0; i < es->nr; i++) {
532     if (es->info[i].valid) {
533       struct string_node *node;
534       node = find_string_node(sp, es->info[i].indep);
535       if (node->key == 0) {
536         xstr *xs = anthy_cstr_to_xstr(node->str, ANTHY_EUC_JP_ENCODING);
537         node->key = anthy_xstr_hash(xs);
538         anthy_free_xstr(xs);
539       }
540       /* printf("(%s)%d\n", es->info[i].indep, node->key); */
541     }
542     free(es->info[i].indep);
543     es->info[i].indep = NULL;
544   }
545   es->nr = 0;
546 }
547
548 static char *
549 get_indep_part(char *buf)
550 {
551   int len;
552   char *c = strchr(buf, '#');
553   if (!c) {
554     return NULL;
555   }
556   c = strchr(c, ' ');
557   if (!c) {
558     return NULL;
559   }
560   c++;
561   c = strchr(c, ' ');
562   if (!c) {
563     return NULL;
564   }
565   c++;
566   len = strlen(c);
567   c[len-1] = 0;
568   return c;
569 }
570
571 static void
572 fixup_missed_word(struct extract_stat *es, char *buf)
573 {
574   int i;
575   char *c = get_indep_part(buf);
576   if (!c) {
577     return ;
578   }
579   for (i = 0; i < es->nr; i++) {
580     if (!strcmp(es->info[i].indep, c)) {
581       es->info[i].valid = 0;
582     }
583   }
584 }
585
586 static void
587 fill_missed_word(struct extract_stat *es, char *buf)
588 {
589   char *c = get_indep_part(buf);
590   if (!c) {
591     return ;
592   }
593   es->info[es->nr].indep = strdup(c);
594   es->info[es->nr].valid = 1;
595   es->nr++;
596 }
597
598 static void
599 extract_word_from_file(FILE *ifp, struct string_pool *sp)
600 {
601   int i;
602   char buf[1024];
603   struct extract_stat es;
604   /**/
605   es.nr = 0;
606   for (i = 0; i < MAX_SEGMENT; i++) {
607     es.info[i].indep = NULL;
608   }
609   /**/
610   while (fgets(buf, 1024, ifp)) {
611     if (buf[0] == '#') {
612       continue;
613     }
614     if (buf[0] == '\n' ||
615         buf[0] == ' ') {
616       flush_extract_stat(&es, sp);
617       continue;
618     }
619     /**/
620     if (!strncmp("!indep_word ", buf, 12)) {
621       fill_missed_word(&es, buf);
622     }
623     if (!strncmp("indep_word", buf, 10)) {
624       fixup_missed_word(&es, buf);
625     }
626   }
627   flush_extract_stat(&es, sp);
628 }
629
630 static void
631 extract_word(int nr_fn, char **fns, FILE *ofp)
632 {
633   struct string_pool sp;
634   FILE *ifp;
635   int i;
636   /**/
637   string_pool_init(&sp);
638   /**/
639   for (i = 0; i < nr_fn; i++) {
640     ifp = fopen(fns[i], "r");
641     if (!ifp) {
642       fprintf(stderr, "failed to open (%s)\n", fns[i]);
643       continue;
644     }
645     extract_word_from_file(ifp, &sp);
646     fclose(ifp);
647   }
648   /**/
649   string_pool_sort(&sp);
650   string_pool_dump(ofp, &sp);
651 }
652
653 /* ÊÑ´¹·ë²Ì¤«¤é³ÎΨ¤Î¥Æ¡¼¥Ö¥ë¤òºî¤ë */
654 static void
655 proc_corpus(int nr_fn, char **fns, FILE *ofp)
656 {
657   int i;
658   struct input_info *m;
659   /**/
660   m = init_input_info();
661   /**/
662   for (i = 0; i < nr_fn; i++) {
663     m->nth_input_file = i;
664     read_file(m, fns[i]);
665   }
666
667   corpus_build(m->indep_corpus);
668   /**/
669   dump_input_info(ofp, m);
670   /**/
671   fprintf(stderr, " %d sentences\n", m->nr_sentences);
672   fprintf(stderr, " %d connections\n", m->nr_connections);
673   fprintf(stderr, " %d segments\n", m->nr_connections - m->nr_sentences);
674 }
675
676 int
677 main(int argc, char **argv)
678 {
679   FILE *ofp;
680   int i;
681   int nr_input = 0;
682   char **input_files;
683   int convert = 0;
684   int extract = 0;
685
686   ofp = NULL;
687   input_files = malloc(sizeof(char *) * argc);
688   
689   for (i = 1; i < argc; i++) {
690     char *arg = argv[i];
691     if (!strcmp(arg, "-o")) {
692       ofp = fopen(argv[i+1], "w");
693       if (!ofp) {
694         fprintf(stderr, "failed to open (%s)\n", argv[i+1]);
695       }
696       i ++;
697     } else if (!strcmp(arg, "-c") ||
698                !strcmp(arg, "--convert")) {
699       convert = 1;
700     } else if (!strcmp(arg, "-e") ||
701                !strcmp(arg, "--extract")) {
702       extract = 1;
703     } else {
704       input_files[nr_input] = arg;
705       nr_input ++;
706     }
707   }
708   if (extract) {
709     printf(" -- extracting missed words\n");
710     if (!ofp) {
711       ofp = stdout;
712     }
713     extract_word(nr_input, input_files, ofp);
714     free(input_files);
715     return 0;
716   }
717   if (ofp) {
718     printf(" -- generating dictionary in text form\n");
719     proc_corpus(nr_input, input_files, ofp);
720     fclose(ofp);
721   }
722   if (convert) {
723     printf(" -- converting dictionary from text to binary form\n");
724     convert_data(nr_input, input_files);
725   }
726
727   free(input_files);
728
729   return 0;
730 }