OSDN Git Service

Initial revision
[chasen-legacy/chasen.git] / mkchadic / makemat.c
1 /*
2  * makemat.c - make table file and matrix file
3  *
4  * $Id: makemat.c,v 1.1 2007/03/13 07:40:10 masayu-a Exp $
5  */
6
7 #include "chadic.h"
8 #include "literal.h"
9
10 #define CTYPE_MAX        500
11 #define REN_TBL_MAX      5000
12 #define RENSETU_CELL_MAX (8192*4)
13
14 #define HINSI_ID_MAX USHRT_MAX
15
16 typedef struct _kankei_t {
17     unsigned short hinsi;
18     unsigned char type;
19 } kankei_t;
20
21 typedef struct _rensetu_pair2_t {
22     short i_pos;     /* the POS index in the current state (= preceding morpheme) */
23     short j_pos;     /* the POS index in the input (= current morpheme) */
24     chasen_cell_t *hinsi; /* POS */
25     unsigned char type;   /* CTYPE */
26     char *form;           /* CFORM */
27     char *goi;            /* Lexicalized POS */
28 } rensetu_pair2_t;
29
30 typedef struct _rensetu_chasen_cell_t {
31     short tbl;
32     short prev;
33     short has_rule;
34 } rensetu_chasen_cell_t;
35
36 static kankei_t kankei_tbl[CTYPE_MAX];
37 static int tbl_num;
38 static rensetu_pair_t rensetu_tbl[RENSETU_CELL_MAX];
39 static int i_num;
40 static int j_num;
41
42 static connect_rule_t **connect_mtr;
43 typedef unsigned char rensetu_mtr_t;
44
45 /*
46  * read_kankei - read chasen's kankei file
47  */
48 static void
49 read_kankei(void)
50 {
51     FILE *fp;
52     chasen_cell_t *cell1, *cell2;
53     int j = 0;
54     int hinsi, type;
55
56     /*
57      * read only from current directory 
58      */
59     fp = cha_fopen(CTYPE_FILE, "r", 1);
60
61     fprintf(stderr, "parsing %s\n", CTYPE_FILE);
62
63     while (!cha_s_feof(fp)) {
64         cell1 = cha_s_read(fp);
65
66         hinsi = cha_get_nhinsi_id(cha_car(cell1));
67         cell1 = cha_car(cha_cdr(cell1));
68
69         while (!nullp(cell2 = cha_car(cell1))) {
70             type = cha_get_type_id(cha_s_atom(cell2));
71             kankei_tbl[j].hinsi = hinsi;
72             kankei_tbl[j].type = type;
73
74             if (++j >= CTYPE_MAX)
75                 cha_exit(1, "not enough size for CTYPE_MAX");
76             cell1 = cha_cdr(cell1);
77         }
78         kankei_tbl[j].hinsi = HINSI_ID_MAX;
79     }
80 }
81
82 /*
83  * get_pair1
84  */
85 static void
86 get_pair1(chasen_cell_t * cell, rensetu_pair_t * pair)
87 {
88     chasen_cell_t *cell_p;
89
90     pair->hinsi = 0;
91     pair->type = 0;
92     pair->form = 0;
93     pair->goi = NULL;
94
95     if (nullp(cell_p = cha_car(cell)))
96         return;
97     pair->hinsi = cha_get_nhinsi_id(cell_p);
98
99     if (nullp(cell_p = cha_car(cell = cha_cdr(cell))))
100         return;
101     pair->type = cha_get_type_id(cha_s_atom(cell_p));
102
103     if (nullp(cell_p = cha_car(cell = cha_cdr(cell))))
104         return;
105     pair->form = cha_get_form_id(cha_s_atom(cell_p), pair->type);
106
107     if (nullp(cell_p = cha_car(cell = cha_cdr(cell))))
108         return;
109     pair->goi = cha_strdup(cha_s_atom(cell_p));
110 }
111
112 /*
113  * get_pair2
114  */
115 static void
116 get_pair2(chasen_cell_t * cell, rensetu_pair2_t * pair)
117 {
118     chasen_cell_t *cell_p;
119     char *s;
120
121     pair->hinsi = NULL;
122     pair->type = 0;
123     pair->form = NULL;
124     pair->goi = NULL;
125
126     if (nullp(cell_p = cha_car(cell)))
127         return;
128
129     s = cha_s_atom(cha_car(cell_p));
130     if (cha_litmatch(s, 2, STR_BOS, STR_EOS)) {
131         pair->hinsi = NULL;
132         return;
133     }
134     pair->hinsi = cell_p;
135
136     if (nullp(cell_p = cha_car(cell = cha_cdr(cell))))
137         return;
138     pair->type = cha_get_type_id(cha_s_atom(cell_p));
139
140     if (nullp(cell_p = cha_car(cell = cha_cdr(cell))))
141         return;
142
143     if (strcmp(s = cha_s_atom(cell_p), "*"))
144         pair->form = cha_strdup(s);
145
146     if (nullp(cell_p = cha_car(cell = cha_cdr(cell))))
147         return;
148     pair->goi = cha_strdup(cha_s_atom(cell_p));
149 }
150
151 /*
152  * match_pair1
153  */
154 static int
155 match_pair1(rensetu_pair_t * pair1, rensetu_pair_t * pair2)
156 {
157     if (pair1->hinsi == pair2->hinsi &&
158         pair1->type == pair2->type &&
159         (!pair2->form || pair1->form == pair2->form) &&
160         !strcmp(pair1->goi, pair2->goi))
161         return 1;
162
163     return 0;
164 }
165
166 /*
167  * match_pair2
168  */
169 static int
170 match_pair2(rensetu_pair2_t * pair, rensetu_pair_t * tbl)
171 {
172     if (pair->hinsi == NULL)       /* BOS/EOS */
173         return tbl->hinsi == 0;
174
175     if (cha_match_nhinsi(pair->hinsi, (int) tbl->hinsi) &&
176         (!pair->type || pair->type == tbl->type) &&
177         (!pair->form ||
178          (tbl->form
179           && !strcmp(pair->form, Cha_form[tbl->type][tbl->form].name)))
180         && (!pair->goi || (tbl->goi && !strcmp(pair->goi, tbl->goi))))
181         return 1;
182
183     return 0;
184 }
185
186 /*
187  * make_rensetu_tbl1 - register hinsi with goi(Lexicalized POS)
188  */
189 void
190 make_rensetu_tbl1(chasen_cell_t * cell1, int *cnt)
191 {
192     int i;
193     rensetu_pair_t r_pair;
194     chasen_cell_t *cell11;
195
196     for (; !nullp(cell11 = cha_car(cell1)); cell1 = cha_cdr(cell1)) {
197         if (nullp(cha_car(cha_cdr(cha_cdr(cha_cdr(cell11))))))
198             continue;
199
200         get_pair1(cell11, &r_pair);
201
202         for (i = 1; i < *cnt; i++)
203             if (match_pair1(&rensetu_tbl[i], &r_pair))
204                 break;
205         if (i < *cnt)
206             continue;
207
208         if (r_pair.type) {
209             for (i = 1; Cha_form[r_pair.type][i].name != NULL; i++) {
210                 rensetu_tbl[*cnt].hinsi = r_pair.hinsi;
211                 rensetu_tbl[*cnt].type = r_pair.type;
212                 rensetu_tbl[*cnt].form = i;
213                 rensetu_tbl[*cnt].goi = r_pair.goi;
214                 if (++*cnt >= REN_TBL_MAX)
215                     cha_exit(1, "not enough size for table");
216             }
217         } else {
218             rensetu_tbl[*cnt].hinsi = r_pair.hinsi;
219             rensetu_tbl[*cnt].type = r_pair.type;
220             rensetu_tbl[*cnt].form = r_pair.form;
221             rensetu_tbl[*cnt].goi = r_pair.goi;
222             if (++*cnt >= REN_TBL_MAX)
223                 cha_exit(1, "not enough size for table");
224         }
225     }
226 }
227
228 /*
229  * make_rensetu_tbl2 - register hinsi
230  */
231 static void
232 make_rensetu_tbl2(int hinsi, int bunrui, int *cnt)
233 {
234     int i, j;
235
236     if (Cha_hinsi[hinsi].kt == 1) { /* with conjugation */
237         for (i = 0; kankei_tbl[i].hinsi != HINSI_ID_MAX; i++) {
238             if (kankei_tbl[i].hinsi == hinsi) {
239                 for (j = 1; Cha_form[kankei_tbl[i].type][j].name != NULL;
240                      j++) {
241                     rensetu_tbl[*cnt].hinsi = hinsi;
242                     rensetu_tbl[*cnt].type = kankei_tbl[i].type;
243                     rensetu_tbl[*cnt].form = j;
244                     rensetu_tbl[*cnt].goi = NULL;
245                     if (++*cnt >= REN_TBL_MAX)
246                         cha_exit(1, "not enough size for table");
247                 }
248             }
249         }
250     } else {  /* without conjugation */
251         rensetu_tbl[*cnt].hinsi = hinsi;   
252         rensetu_tbl[*cnt].type = 0;        
253         rensetu_tbl[*cnt].form = 0;        
254         rensetu_tbl[*cnt].goi = NULL;      
255
256         if (++*cnt >= REN_TBL_MAX)
257             cha_exit(1, "not enough size for table");
258     }
259 }
260
261 /*
262  * make_rensetu_tbl - register hinsi into table
263  */
264 static int
265 make_rensetu_tbl(FILE * fp)
266 {
267     chasen_cell_t *cell;
268     int i, lines;
269     int tbl_count = 1;          /* 0 is for BOS/EOS */
270
271     /* regist POS with lexicalization 
272        ¸ì×äò»ØÄꤷ¤Æ¤¤¤ë¤â¤Î¤ò¥Æ¡¼¥Ö¥ë¤ËÅÐÏ¿  */
273     for (lines = 0; !cha_s_feof(fp); lines++) {
274         for (cell = cha_car(cha_s_read(fp)); !nullp(cell);
275              cell = cha_cdr(cell))
276             make_rensetu_tbl1(cha_car(cell), &tbl_count);
277     }
278
279     /* regist POS with extracted conjugation 
280        ³èÍѤòŸ³«¤·¤Æ¥Æ¡¼¥Ö¥ë¤ËÅÐÏ¿ */
281     for (i = 1; Cha_hinsi[i].name; i++)
282         make_rensetu_tbl2(i, 0, &tbl_count);    /* second argument is dummy for compatibility */
283     tbl_num = tbl_count;
284
285     /* print for check */
286     fprintf(stderr, "table size: %d\n", tbl_num);
287
288     return lines;
289 }
290
291 /*
292  * variables and functions for rensetu_cell
293  */
294 static rensetu_chasen_cell_t rensetu_cell[RENSETU_CELL_MAX];
295 static int cell_num;
296
297 static int new_cell1[RENSETU_CELL_MAX], new_cell2[RENSETU_CELL_MAX];
298 static int new_cell1_num, new_cell2_num;
299
300 static int
301 search_rensetu_cell(int tbl, int prev)
302 {
303     int i;
304
305     for (i = 0; i < cell_num; i++)
306         if (rensetu_cell[i].tbl == tbl)
307             if (rensetu_cell[i].prev == prev)
308                 return i;
309
310     return -1;
311 }
312
313 /*
314  * c2 ¤¬ c1 ¤Î suffix ¤«¤É¤¦¤« 
315  */
316 static int
317 match_rensetu_cell_suffix(int c1, int c2)
318 {
319     int n;
320
321     for (n = 0; c2 >= 0; n++) {
322         if (rensetu_cell[c1].tbl != rensetu_cell[c2].tbl)
323             return 0;
324         c1 = rensetu_cell[c1].prev;
325         c2 = rensetu_cell[c2].prev;
326     }
327
328     return n;
329 }
330
331 static void
332 match_rensetu_cell_tbl(int tbl, int *cells)
333 {
334     int *c, i;
335
336     c = cells;
337     *c++ = tbl;
338     for (i = tbl_num; i < cell_num; i++)
339         if (tbl == rensetu_cell[i].tbl)
340             *c++ = i;
341     *c = -1;
342 }
343
344 /*
345  * add_connect_rule
346  */
347 static void
348 add_connect_rule(int in, int prev, int cost, int is_last, int *in_cells,
349                  int *cur_cells)
350 {
351     int cur, next, *curp, *cellp;
352     int suffix_len, suffix_len_max;
353
354     next = 0;                   /* to avoid warning */
355     match_rensetu_cell_tbl(rensetu_cell[prev].tbl, cur_cells);
356
357     /*
358      * cell Ã椫¤é cur(¸½¾õÂÖ)¤ò¸¡º÷ 
359      */
360     for (curp = cur_cells; (cur = *curp) >= 0; curp++) {
361         /*
362          * prev ¤¬ cur ¤Î suffix ¤Ë¤Ê¤Ã¤Æ¤¤¤ì¤Ð ok 
363          */
364         if (!match_rensetu_cell_suffix(cur, prev))
365             continue;
366         /*
367          * ºÇ¸å¤ÎÉÊ»ì¤Ç¤Ê¤¤¾ì¹ç¤Ïµ¬Â§¤ò¾å½ñ¤­¤·¤Ê¤¤ 
368          */
369         if (!is_last && connect_mtr[cur][in].cost)
370             continue;
371         suffix_len_max = 0;
372         /*
373          * cell Ã椫¤é next(¼¡¾õÂÖ)¤ò¸¡º÷ 
374          */
375         for (cellp = in_cells; *cellp >= 0; cellp++) {
376             /*
377              * cur+in ¤Î suffix ¤Î¤¦¤ÁºÇ¤âŤ¤¤â¤Î¤òõ¤¹ 
378              */
379             suffix_len =
380                 match_rensetu_cell_suffix(cur,
381                                           rensetu_cell[*cellp].prev) + 1;
382             if (suffix_len_max < suffix_len) {
383                 suffix_len_max = suffix_len;
384                 next = *cellp;
385             }
386         }
387 #ifdef DEBUG
388         if (suffix_len_max > 1) {
389             printf("suffix_len:%d,prev:%d,cur:%d,in:%d,next:%d,cost:%d\n",
390                    suffix_len_max, prev, cur, in, next, cost);
391         }
392 #endif
393         /*
394          * µ¬Â§¤òÄɲà
395          */
396         if (suffix_len_max) {
397             connect_mtr[cur][in].next = next - in;
398             connect_mtr[cur][in].cost = cost < 0 ? 0 : cost + 1;
399         }
400     }
401 }
402
403 /*
404  * read_rensetu
405  */
406 static void
407 read_rensetu(FILE * fp, int lines)
408 {
409     chasen_cell_t **rule;
410     int *rule_len;
411     rensetu_pair2_t pair;
412     chasen_cell_t *cell, *cell1;
413     int rule_len_max, rlen;
414     int prev, in, c1, ln, linenum, linecnt;
415     int cost, is_last;
416     int *in_cells, *cur_cells;
417     connect_rule_t *ptr;
418
419     rule = (chasen_cell_t **) cha_malloc(sizeof(chasen_cell_t *) * lines);
420     rule_len = (int *) cha_malloc(sizeof(int) * lines);
421
422     fputs("lines: ", stderr);
423     /*
424      * rensetu_cell ¤Î½é´ü²½ 
425      */
426     if (cell_num >= RENSETU_CELL_MAX)
427         cha_exit(1, "not enough size for cell");
428     for (cell_num = 0; cell_num < tbl_num; cell_num++) {
429         rensetu_cell[cell_num].tbl = cell_num;
430         rensetu_cell[cell_num].prev = -1;
431     }
432
433     rule_len_max = 0;
434     for (ln = 0; !cha_s_feof(fp); ln++) {
435         rule[ln] = cha_s_read(fp);
436         if ((ln % 500) == 0) {
437             fputc('.', stderr);
438             fflush(stderr);
439         }
440
441         /*
442          * ºÇ¤âŤ¤µ¬Â§¤ò¸«¤Ä¤±¤ë 
443          */
444         rule_len[ln] = cha_s_length(cha_car(rule[ln]));
445         if (rule_len[ln] < 2)
446             cha_exit_file(1, "too few morphemes");
447         if (rule_len_max < rule_len[ln])
448             rule_len_max = rule_len[ln];
449
450         /*
451          * new_cell2: ³ÆÉÊ»ì¤ÇÅÐÏ¿¤·¤¿ rensetu_cell 
452          */
453         new_cell2[0] = -1;      /* Ê¸Æ¬¡¦Ê¸Ëö */
454         new_cell2_num = 1;
455         /*
456          * µ¬Â§¤Î¥Î¡¼¥É¤òºîÀ® 
457          */
458         /*
459          * cell: Éʻ췲¤Î¥ê¥¹¥È 
460          */
461         for (cell = cha_car(rule[ln]); !nullp(cha_cdr(cell));
462              cell = cha_cdr(cell)) {
463             /*
464              * new_cell2 ¤ò new_cell1 ¤Ë¥³¥Ô¡¼ 
465              */
466             memcpy(new_cell1, new_cell2, sizeof(int) * new_cell2_num);
467             new_cell1_num = new_cell2_num;
468             new_cell2_num = 0;
469             /*
470              * cell1: Éʻ췲 
471              */
472             for (cell1 = cha_car(cell); !nullp(cell1);
473                  cell1 = cha_cdr(cell1)) {
474                 int tbl;
475                 /*
476                  * pair: ¥ï¥¤¥ë¥É¥«¡¼¥É¤Ä¤­¤ÎÉÊ»ì 
477                  */
478                 get_pair2(cha_car(cell1), &pair);
479                 /*
480                  * pair ¤«¤é tbl(ÉÊ»ì1¤Ä1¤Ä)¤ò¼è¤ê½Ð¤·¤Æ½èÍý 
481                  */
482                 for (tbl = 0; tbl < tbl_num; tbl++) {
483                     if (!match_pair2(&pair, &rensetu_tbl[tbl]))
484                         continue;
485                     /*
486                      * c1, prev: 1¤ÄÁ°¤ÎÉÊ»ì¤ÇÅÐÏ¿¤µ¤ì¤¿cell 
487                      */
488                     for (c1 = 0; c1 < new_cell1_num; c1++) {
489                         int prev = new_cell1[c1], cellno;
490                         if ((cellno = search_rensetu_cell(tbl, prev)) < 0) {
491                             cellno = cell_num;
492                             if (++cell_num >= RENSETU_CELL_MAX)
493                                 cha_exit_file(1,
494                                               "not enough size for cell");
495                             rensetu_cell[cellno].tbl = tbl;
496                             rensetu_cell[cellno].prev = prev;
497 #ifdef DEBUG
498                             printf("cellno:%d,tbl:%d,prev:%d\n", cellno,
499                                    tbl, prev);
500 #endif
501                         }
502                         new_cell2[new_cell2_num++] = cellno;
503                     }
504                 }
505             }
506         }
507     }
508
509     fprintf(stderr, " %d\n", ln);
510     fprintf(stderr, "number of states: %d\n", cell_num);
511
512     ptr =
513         (connect_rule_t *) cha_malloc(sizeof(connect_rule_t) * cell_num *
514                                       tbl_num);
515     memset(ptr, 0, sizeof(connect_rule_t) * cell_num * tbl_num);
516     connect_mtr =
517         (connect_rule_t **) cha_malloc(sizeof(connect_rule_t *) *
518                                        cell_num);
519     for (c1 = 0; c1 < cell_num; c1++)
520         connect_mtr[c1] = ptr + c1 * tbl_num;
521
522     in_cells = cha_malloc(sizeof(int) * cell_num);
523     cur_cells = cha_malloc(sizeof(int) * cell_num);
524
525     linenum = ln;
526     linecnt = 0;
527
528     /*
529      * Ã»¤¤µ¬Â§¤Î½ç¤Ë½èÍý 
530      */
531     for (rlen = 2; rlen <= rule_len_max; rlen++) {
532                 /*      fprintf(stderr, rlen == 2 ? "bi%s" : rlen == 3 ? "tri%s" : "%d%s",
533                         "-gram: ", rlen); */
534                 if (rlen <= 3)  
535                         fprintf(stderr, rlen == 2 ? "bi%s" : rlen == 3 ? "tri%s" : "%s",
536                                         "-gram: ");     
537                 else    
538                         fprintf(stderr, "%d-gram: ", rlen);
539
540         for (ln = 0; ln < linenum; ln++) {
541             if (rule_len[ln] != rlen)
542                 continue;
543             Cha_lineno_error = Cha_lineno = ln + 1;
544 #ifdef DEBUG
545             printf("Line: %d/%d\n", ln + 1, linenum);
546 #endif
547             if ((++linecnt % 500) == 0) {
548                 fputc('.', stderr);
549                 if ((linecnt % 20000) == 0)
550                     fprintf(stderr, " %d\n", linecnt);
551                 fflush(stderr);
552             }
553
554             cell = cha_car(cha_cdr(rule[ln]));
555             cost = nullp(cell) ? DEFAULT_C_WEIGHT : atoi(cha_s_atom(cell));
556             is_last = 0;
557             /*
558              * new_cell2: ³ÆÉÊ»ì¤ÇÅÐÏ¿¤·¤¿ rensetu_cell 
559              */
560             new_cell2[0] = -1;  /* Ê¸Æ¬¡¦Ê¸Ëö */
561             new_cell2_num = 1;
562             /*
563              * cell: Éʻ췲¤Î¥ê¥¹¥È 
564              */
565             for (cell = cha_car(rule[ln]); !is_last; cell = cha_cdr(cell)) {
566                 is_last = nullp(cha_cdr(cell));
567                 /*
568                  * new_cell2 ¤ò new_cell1 ¤Ë¥³¥Ô¡¼ 
569                  */
570                 memcpy(new_cell1, new_cell2, sizeof(int) * new_cell2_num);
571                 new_cell1_num = new_cell2_num;
572                 new_cell2_num = 0;
573                 /*
574                  * cell1: Éʻ췲 
575                  */
576                 for (cell1 = cha_car(cell); !nullp(cell1);
577                      cell1 = cha_cdr(cell1)) {
578                     /*
579                      * pair: ¥ï¥¤¥ë¥É¥«¡¼¥É¤Ä¤­¤ÎÉÊ»ì 
580                      */
581                     get_pair2(cha_car(cell1), &pair);
582                     /*
583                      * pair ¤«¤é in(ÉÊ»ì1¤Ä1¤Ä)¤ò¼è¤ê½Ð¤·¤Æ½èÍý 
584                      */
585                     for (in = 0; in < tbl_num; in++) {
586                         if (!match_pair2(&pair, &rensetu_tbl[in]))
587                             continue;
588                         match_rensetu_cell_tbl(in, in_cells);
589                         /*
590                          * c1, prev: 1¤ÄÁ°¤ÎÉÊ»ì¤ÇÅÐÏ¿¤µ¤ì¤¿cell 
591                          */
592                         for (c1 = 0; c1 < new_cell1_num; c1++) {
593                             prev = new_cell1[c1];
594                             if (!is_last) {
595                                 int cellno = search_rensetu_cell(in, prev);
596                                 new_cell2[new_cell2_num++] = cellno;
597                             }
598                             /*
599                              * µ¬Â§¤òÄɲà
600                              */
601                             add_connect_rule(in, prev, cost, is_last,
602                                              in_cells, cur_cells);
603                         }
604                     }
605                 }
606             }
607         }
608         printf(" %d\n", linecnt);
609     }
610 }
611
612 static int
613 compare_vector1(int k, int j, int num)
614 {
615     int i;
616
617     for (i = 0; i < num; i++)
618         if (connect_mtr[i][k].next != connect_mtr[i][j].next ||
619             connect_mtr[i][k].cost != connect_mtr[i][j].cost)
620             return 0;
621
622     return 1;
623 }
624
625 static void
626 copy_vector1(int j, int j_n, int num)
627 {
628     int i;
629
630     for (i = 0; i < num; i++) {
631         connect_mtr[i][j_n].next = connect_mtr[i][j].next;
632         connect_mtr[i][j_n].cost = connect_mtr[i][j].cost;
633     }
634 }
635
636 static int
637 compare_vector2(int k, int i, int num)
638 {
639     int j;
640
641     for (j = 0; j < num; j++)
642         if (connect_mtr[i][j].next != connect_mtr[k][j].next ||
643             connect_mtr[i][j].cost != connect_mtr[k][j].cost)
644             return 0;
645
646     return 1;
647 }
648
649 static void
650 copy_vector2(int i, int i_n, int num)
651 {
652     int j;
653
654     for (j = 0; j < num; j++) {
655         connect_mtr[i_n][j].next = connect_mtr[i][j].next;
656         connect_mtr[i_n][j].cost = connect_mtr[i][j].cost;
657     }
658 }
659
660 /*
661  * condense_matrix
662  */
663 static void
664 condense_matrix(void)
665 {
666     int i, j, k;
667     int i_n = 0;
668     int j_n = 0;
669
670     fprintf(stderr, "matrix size: %dx%d", cell_num, tbl_num);
671
672     for (j = 0; j < tbl_num; j++) {
673         int has_same = 0;
674
675         for (k = 0; k < j_n; k++) {
676             if (compare_vector1(k, j, cell_num)) {
677                 rensetu_tbl[j].j_pos = k;
678                 has_same = 1;
679                 break;
680             }
681         }
682         if (!has_same) {
683             if (j != j_n)
684                 copy_vector1(j, j_n, cell_num);
685             rensetu_tbl[j].j_pos = j_n++;
686         }
687     }
688     j_num = j_n;
689
690     for (i = 0; i < cell_num; i++) {
691         int has_same = 0;
692
693         for (k = 0; k < i_n; k++) {
694             if (compare_vector2(k, i, j_num)) {
695                 rensetu_tbl[i].i_pos = k;
696                 has_same = 1;
697                 break;
698             }
699         }
700         if (!has_same) {
701             if (i != i_n)
702                 copy_vector2(i, i_n, j_num);
703             rensetu_tbl[i].i_pos = i_n++;
704         }
705     }
706     i_num = i_n;
707
708     /*
709      * print for check 
710      */
711     fprintf(stderr, " -> %dx%d\n", i_num, j_num);
712 }
713
714 /*
715  * write_table, write_matrix
716  */
717 static void
718 write_table(void)
719 {
720     FILE *fp;
721     rensetu_pair_t *tbl;
722     int i;
723
724     fp = cha_fopen(TABLE_FILE, "w", 1);
725     fprintf(fp, "%d\n", cell_num);
726     for (i = 0, tbl = &rensetu_tbl[0]; i < tbl_num; i++, tbl++) {
727         /*
728          * comment 
729          */
730         fprintf(fp, "%s %s %s %s\n",
731                 Cha_hinsi[tbl->hinsi].name ?
732                 Cha_hinsi[tbl->hinsi].name : "(null)",
733                 tbl->type ? Cha_type[tbl->type].name : "",
734                 tbl->form ? Cha_form[tbl->type][tbl->form].name : "",
735                 tbl->goi ? tbl->goi : "");
736         /*
737          * data 
738          */
739         fprintf(fp, "%d %d %d %d %d %s\n",
740                 tbl->i_pos, tbl->j_pos, tbl->hinsi,
741                 tbl->type, tbl->form, tbl->goi ? tbl->goi : "*");
742     }
743     for (; i < cell_num; i++, tbl++)
744         fprintf(fp, ";\n%d -1 0 0 0 *\n", tbl->i_pos);
745
746     fclose(fp);
747 }
748
749 static void
750 write_matrix(void)
751 {
752     FILE *fp;
753     int i, j;
754
755     fp = cha_fopen(MATRIX_FILE, "w", 1);
756     fprintf(fp, "%d %d\n", i_num, j_num);
757
758     for (i = 0; i < i_num; i++) {
759         int nval = 0;
760         int next0 = connect_mtr[i][0].next;
761         int cost0 = connect_mtr[i][0].cost;
762         for (j = 0; j < j_num; j++) {
763             if (connect_mtr[i][j].next == next0 &&
764                 connect_mtr[i][j].cost == cost0) {
765                 nval++;
766             } else {
767                 if (next0 == 0 && cost0 == 0)
768                     fprintf(fp, "o%d ", nval);
769                 else if (nval == 1)
770                     fprintf(fp, "%d,%d ", next0, cost0);
771                 else
772                     fprintf(fp, "%d,%dx%d ", next0, cost0, nval);
773                 nval = 1;
774                 next0 = connect_mtr[i][j].next;
775                 cost0 = connect_mtr[i][j].cost;
776             }
777         }
778         if (nval > 0) {
779             if (next0 == 0 && cost0 == 0)
780                 fprintf(fp, "o%d ", nval);
781             else if (nval == 1)
782                 fprintf(fp, "%d,%d ", next0, cost0);
783             else
784                 fprintf(fp, "%d,%dx%d ", next0, cost0, nval);
785         }
786         fprintf(fp, "\n");
787     }
788     fclose(fp);
789 }
790
791 /*
792  * main
793  */
794 int
795 main(int argc, char *argv[])
796 {
797     FILE *fpc;
798     int lines;
799     char *con_filename;
800     int c;
801
802     cha_set_progpath(argv[0]);
803
804     cha_set_encode("");
805     while ((c = cha_getopt(argv, "i:", stderr)) != EOF) {
806         switch (c) {
807         case 'i':
808             cha_set_encode(Cha_optarg);
809             break;
810         }
811     }
812     argv += Cha_optind;
813
814     if (argv[0] == NULL)
815         con_filename = CONNECT_FILE;
816     else
817         con_filename = argv[0];
818
819     /*
820      * .chasenrc ¤ÏÆɤ߹þ¤àɬÍפʤ¤ 
821      */
822
823     /*
824      * Ê¸Ë¡¡¦³èÍÑ¡¦´Ø·¸¥Õ¥¡¥¤¥ë 
825      */
826     cha_read_grammar(stderr, 0, 0);
827     cha_read_katuyou(stderr, 0);
828     read_kankei();
829
830     /*
831      * Ï¢Àܵ¬Â§¥Õ¥¡¥¤¥ë¤Î¥ª¡¼¥×¥ó 
832      */
833     fpc = cha_fopen(con_filename, "r", 1);
834
835     /*
836      * Ï¢Àܵ¬Â§¥Õ¥¡¥¤¥ë¤Î½èÍý 
837      */
838     fprintf(stderr, "parsing %s\n", con_filename);
839     cha_set_skip_char('#');
840     lines = make_rensetu_tbl(fpc);
841     rewind(fpc);
842     Cha_lineno = 0;
843     read_rensetu(fpc, lines);
844     fclose(fpc);
845
846     /*
847      * Ï¢ÀܹÔÎó¤Î°µ½Ì 
848      */
849     condense_matrix();
850     write_table();
851     write_matrix();
852
853     return 0;
854 }
855
856
857 /*---------------------------------------------------
858
859  Memo for connection matrix.
860
861  * chasen automaton:
862
863     current state : the preceding morpheme state number
864     input: the current morpheme state number
865     output: the next state number & connection cost
866
867
868                   +============+
869            input  | cur state  |
870 +-----------+     +------------+
871 | the cur   |---->|  the prec  |
872 | mrph state|     | mrph state |  i_pos in rensetu_pair_t
873 +-----------+     +============+
874 j_pos                   | output
875 in rensetu_pair_t       v
876                   +------------+
877                   | the next   |   lib/chadic.h
878                   |   state    |   typedef struct _connect_rule_t {
879                   +------------+       unsigned short next;   
880                   | connection |       unsigned short cost;   
881                   |   cost     |   } connect_rule_t;
882                   +------------+
883
884   * table.cha
885   ----
886   Àܳ½õ»ì   ¤Ê¤¬¤é                 [POS name]   [lexicalized POS]
887   3 3 64 0 0 ¤Ê¤¬¤é                 i_pos j_pos hinshi type form goi
888   ----
889
890   * matrix.cha
891   -----
892   0,394 0,8001 0,3430 0,8001 0,3766 0,8001x2 0,3094 ....
893   -----
894   Hcolumn: current state = preceding morpheme  (cell_num)
895   Vcolumn: input         = current morpheme    (tbl_num)
896
897   the entry X,Yx2 means as follows:
898
899   X = next state number (nonzero for tri-gram context, zero for bi-gram context)
900   Y = connection cost
901
902   `x2' means two times of state(compressed expression)
903
904 */