/* * 確定(コミット)後の処理をする。 * 各種の学習処理を呼び出す * * anthy_proc_commit() が外部から呼ばれる */ #include #include #include #include #include #include #include "sorter.h" #define MAX_OCHAIRE_ENTRY_COUNT 100 #define MAX_OCHAIRE_LEN 32 #define MAX_PREDICTION_ENTRY 100 #define MAX_UNKNOWN_WORD 100 /* 交換された候補を探す */ static void learn_swapped_candidates(struct segment_list *sl) { int i; struct seg_ent *seg; for (i = 0; i < sl->nr_segments; i++) { seg = anthy_get_nth_segment(sl, i); if (seg->committed != 0) { /* 最初の候補(0番目)でない候補(seg->committed番目)がコミットされた */ anthy_swap_cand_ent(seg->cands[0], seg->cands[seg->committed]); } } anthy_cand_swap_ageup(); } /* 長さが変わった文節の変更後に対して */ static void learn_resized_segment(struct splitter_context *sc, struct segment_list *sl) { int i; struct meta_word **mw = alloca(sizeof(struct meta_word*) * sl->nr_segments); int *len_array = alloca(sizeof(int) * sl->nr_segments); /* 各文節の長さの配列とmeta_wordの配列を用意する */ for (i = 0; i < sl->nr_segments; i++) { struct seg_ent *se = anthy_get_nth_segment(sl, i); mw[i] = se->cands[se->committed]->mw; len_array[i] = se->str.len; } anthy_commit_border(sc, sl->nr_segments, mw, len_array); } /* 長さが変わった文節の変更前に対して */ static void clear_resized_segment(struct splitter_context *sc, struct segment_list *sl) { int *mark, i, from; struct seg_ent *seg; mark = alloca(sizeof(int)*sc->char_count); for (i = 0; i < sc->char_count; i++) { mark[i] = 0; } /* 実際に確定された文節の長さをマークする */ from = 0; for (i = 0; i < sl->nr_segments; i++) { seg = anthy_get_nth_segment(sl, i); mark[from] = seg->len; from = from + seg->len; } for (i = 0; i < sc->char_count; i++) { int len = sc->ce[i].initial_seg_len; /* 最初の長さと確定された長さが異なれば、 使われなかった未知語の可能性がある */ if (len && len != mark[i]) { xstr xs; xs.str = sc->ce[i].c; xs.len = len; anthy_forget_unused_unknown_word(&xs); } } if (!anthy_select_section("UNKNOWN_WORD", 0)) { anthy_truncate_section(MAX_UNKNOWN_WORD); } } /* recordにお茶入れ学習の結果を書き込む */ static void commit_ochaire(struct seg_ent *seg, int count, xstr* xs) { int i; if (xs->len >= MAX_OCHAIRE_LEN) { return ; } if (anthy_select_row(xs, 1)) { return ; } anthy_set_nth_value(0, count); for (i = 0; i < count; i++, seg = seg->next) { anthy_set_nth_value(i * 2 + 1, seg->len); anthy_set_nth_xstr(i * 2 + 2, &seg->cands[seg->committed]->str); } } /* recordの領域を節約するために、お茶入れ学習のネガティブな エントリを消す */ static void release_negative_ochaire(struct splitter_context *sc, struct segment_list *sl) { int start, len; xstr xs; (void)sl; /* 変換前のひらがな文字列 */ xs.len = sc->char_count; xs.str = sc->ce[0].c; /* xsの部分文字列に対して */ for (start = 0; start < xs.len; start ++) { for (len = 1; len <= xs.len - start && len < MAX_OCHAIRE_LEN; len ++) { xstr part; part.str = &xs.str[start]; part.len = len; if (anthy_select_row(&part, 0) == 0) { anthy_release_row(); } } } } /* お茶入れ学習を行う */ static void learn_ochaire(struct splitter_context *sc, struct segment_list *sl) { int i; int count; if (anthy_select_section("OCHAIRE", 1)) { return ; } /* お茶入れ学習のネガティブなエントリを消す */ release_negative_ochaire(sc, sl); /* お茶入れ学習をする */ for (count = 2; count <= sl->nr_segments && count < 5; count++) { /* 2文節以上の長さの文節列に対して */ for (i = 0; i <= sl->nr_segments - count; i++) { struct seg_ent *head = anthy_get_nth_segment(sl, i); struct seg_ent *s; xstr xs; int j; xs = head->str; if (xs.len < 2 && count < 3) { /* 細切れの文節を学習することを避ける、 * いい加減なheuristics */ continue; } /* 文節列を構成する文字列を作る */ for (j = 1, s = head->next; j < count; j++, s = s->next) { xs.len += s->str.len; } /**/ commit_ochaire(head, count, &xs); } } if (anthy_select_section("OCHAIRE", 1)) { return ; } anthy_truncate_section(MAX_OCHAIRE_ENTRY_COUNT); } static int learn_prediction_str(xstr *idx, xstr *xs) { int nr_predictions; int i; time_t t = time(NULL); if (anthy_select_row(idx, 1)) { return 0; } nr_predictions = anthy_get_nr_values(); /* 既に履歴にある場合はタイムスタンプだけ更新 */ for (i = 0; i < nr_predictions; i += 2) { xstr *log = anthy_get_nth_xstr(i + 1); if (!log) { continue; } if (anthy_xstrcmp(log, xs) == 0) { anthy_set_nth_value(i, t); break; } } /* ない場合は末尾に追加 */ if (i == nr_predictions) { anthy_set_nth_value(nr_predictions, t); anthy_set_nth_xstr(nr_predictions + 1, xs); anthy_mark_row_used(); return 1; } anthy_mark_row_used(); return 0; } static void learn_prediction(struct segment_list *sl) { int i; int added = 0; if (anthy_select_section("PREDICTION", 1)) { return ; } for (i = 0; i < sl->nr_segments; i++) { struct seg_ent *seg = anthy_get_nth_segment(sl, i); xstr *xs = &seg->cands[seg->committed]->str; if (seg->committed < 0) { continue; } if (learn_prediction_str(&seg->str, xs)) { added = 1; } } if (added) { anthy_truncate_section(MAX_PREDICTION_ENTRY); } } static void learn_unknown(struct segment_list *sl) { int i; for (i = 0; i < sl->nr_segments; i++) { struct seg_ent *seg = anthy_get_nth_segment(sl, i); struct cand_ent *ce = seg->cands[seg->committed]; if (ce->nr_words == 0) { anthy_add_unknown_word(&seg->str, &ce->str); } } } void anthy_do_commit_prediction(xstr *src, xstr *xs) { if (anthy_select_section("PREDICTION", 1)) { return ; } learn_prediction_str(src, xs); } void anthy_proc_commit(struct segment_list *sl, struct splitter_context *sc) { /* 各種の学習を行う */ learn_swapped_candidates(sl); learn_resized_segment(sc, sl); clear_resized_segment(sc, sl); learn_ochaire(sc, sl); learn_prediction(sl); learn_unknown(sl); anthy_learn_cand_history(sl); }