1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276
|
/*
* 文節に対する候補をソートする。
* 将来的には近接する文節も見て、単語の結合による評価をする。
* ダブった候補の削除もする。
*
* Funded by IPA未踏ソフトウェア創造事業 2001 9/22
* Copyright (C) 2000-2006 TABATA Yusuke
* Copyright (C) 2001 UGAWA Tomoharu
*
*/
/*
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <limits.h>
#include <stdlib.h>
#include <stdio.h>
#include <anthy/segment.h>
#include <anthy/splitter.h>
#include <anthy/ordering.h>
#include "sorter.h"
/* お茶入れ学習による候補 */
#define OCHAIRE_BASE OCHAIRE_SCORE
/* metawordが十分無理矢理くさいときの、ひらがなカタカナのスコア */
#define NOCONV_WITH_BIAS 900000
/* 普通の候補 */
#define NORMAL_BASE 100
/* 単漢字 */
#define SINGLEWORD_BASE 10
/* 複合語 */
#define COMPOUND_BASE (OCHAIRE_SCORE / 2)
/* 複合語の一部分を一文節にしたもの */
#define COMPOUND_PART_BASE 2
/* 付属語のみ */
#define DEPWORD_BASE (OCHAIRE_SCORE / 2)
/* ひらがなカタカナのデフォルトのスコア */
#define NOCONV_BASE 1
/* 無理っぽい候補割り当てか判断する */
static int
uncertain_segment_p(struct seg_ent *se)
{
struct meta_word *mw;
if (se->nr_metaword == 0) {
return 0;
}
mw = se->mw_array[0];
/* 長さの6割 */
if (se->len * 3 >= mw->len * 5) {
return 1;
}
return 0;
}
static void
release_redundant_candidate(struct seg_ent *se)
{
int i, j;
/* 配列はソートされているのでscoreが0の候補が後ろに並んでいる */
for (i = 0; i < se->nr_cands && se->cands[i]->score; i++);
/* iから後ろの候補を解放 */
if (i < se->nr_cands) {
for (j = i; j < se->nr_cands; j++) {
anthy_release_cand_ent(se->cands[j]);
}
se->nr_cands = i;
}
}
/* qsort用の候補比較関数 */
static int
candidate_compare_func(const void *p1, const void *p2)
{
const struct cand_ent *const *c1 = p1, *const *c2 = p2;
return (*c2)->score - (*c1)->score;
}
static void
sort_segment(struct seg_ent *se)
{
qsort(se->cands, se->nr_cands,
sizeof(struct cand_ent *),
candidate_compare_func);
}
static void
trim_kana_candidate(struct seg_ent *se)
{
int i;
if (NULL == se->cands) { /* 辞書もしくは学習データが壊れていた時の対策 */
return;
}
if (se->cands[0]->flag & CEF_KATAKANA) {
return ;
}
for (i = 1; i < se->nr_cands; i++) {
if (se->cands[i]->flag & CEF_KATAKANA) {
/* 最低点まで下げる */
se->cands[i]->score = NOCONV_BASE;
}
}
}
static void
check_dupl_candidate(struct seg_ent *se)
{
int i,j;
for (i = 0; i < se->nr_cands - 1; i++) {
for (j = i + 1; j < se->nr_cands; j++) {
if (!anthy_xstrcmp(&se->cands[i]->str, &se->cands[j]->str)) {
/* ルールに良くマッチしたものの方を選ぶとかすべき */
se->cands[j]->score = 0;
se->cands[i]->flag |= se->cands[j]->flag;
}
}
}
}
/* 品詞割り当てによって生成された候補を評価する */
static void
eval_candidate_by_metaword(struct cand_ent *ce)
{
int i;
int score = 1;
/* まず、単語の頻度によるscoreを加算 */
for (i = 0; i < ce->nr_words; i++) {
struct cand_elm *elm = &ce->elm[i];
int pos, div = 1;
int freq;
if (elm->nth < 0) {
/* 候補割り当ての対象外なのでスキップ */
continue;
}
pos = anthy_wtype_get_pos(elm->wt);
if (pos == POS_PRE || pos == POS_SUC) {
div = 4;
}
freq = anthy_get_nth_dic_ent_freq(elm->se, elm->nth);
score += freq / div;
}
if (ce->mw) {
score *= ce->mw->struct_score;
score /= RATIO_BASE;
}
ce->score = score;
}
/* 候補を評価する */
static void
eval_candidate(struct cand_ent *ce, int uncertain)
{
if ((ce->flag &
(CEF_OCHAIRE | CEF_SINGLEWORD | CEF_HIRAGANA |
CEF_KATAKANA | CEF_GUESS | CEF_COMPOUND | CEF_COMPOUND_PART |
CEF_BEST)) == 0) {
/* splitterからの情報(metaword)によって生成された候補 */
eval_candidate_by_metaword(ce);
} else if (ce->flag & CEF_OCHAIRE) {
ce->score = OCHAIRE_BASE;
} else if (ce->flag & CEF_SINGLEWORD) {
ce->score = SINGLEWORD_BASE;
} else if (ce->flag & CEF_COMPOUND) {
ce->score = COMPOUND_BASE;
} else if (ce->flag & CEF_COMPOUND_PART) {
ce->score = COMPOUND_PART_BASE;
} else if (ce->flag & CEF_BEST) {
ce->score = OCHAIRE_BASE;
} else if (ce->flag & (CEF_HIRAGANA | CEF_KATAKANA |
CEF_GUESS)) {
if (uncertain) {
/*
* この文節は外来語などのようなので、生成した候補よりも
* ひらがなカタカナの候補を出した方がよい
*/
ce->score = NOCONV_WITH_BIAS;
if (CEF_KATAKANA & ce->flag) {
ce->score ++;
}
if (CEF_GUESS & ce->flag) {
ce->score += 2;
}
} else {
ce->score = NOCONV_BASE;
}
}
ce->score += 1;
}
static void
eval_segment(struct seg_ent *se)
{
int i;
int uncertain = uncertain_segment_p(se);
for (i = 0; i < se->nr_cands; i++) {
eval_candidate(se->cands[i], uncertain);
}
}
/* 学習履歴の内容で順位を調整する */
static void
apply_learning(struct segment_list *sl, int nth)
{
int i;
/*
* 優先順位の低いものから順に適用する
*/
/* 用例辞書による順序の変更 */
anthy_reorder_candidates_by_relation(sl, nth);
/* 候補の交換 */
for (i = nth; i < sl->nr_segments; i++) {
struct seg_ent *seg = anthy_get_nth_segment(sl, i);
/* 候補の交換 */
anthy_proc_swap_candidate(seg);
/* 履歴による順序の変更 */
anthy_reorder_candidates_by_history(anthy_get_nth_segment(sl, i));
}
}
/** 外から呼ばれるエントリポイント
* @nth以降の文節を対象とする
*/
void
anthy_sort_candidate(struct segment_list *sl, int nth)
{
int i;
for (i = nth; i < sl->nr_segments; i++) {
struct seg_ent *seg = anthy_get_nth_segment(sl, i);
/* まず評価する */
eval_segment(seg);
/* つぎにソートする */
sort_segment(seg);
/* ダブったエントリの点の低い方に0点を付ける */
check_dupl_candidate(seg);
/* もういちどソートする */
sort_segment(seg);
/* 評価0の候補を解放 */
release_redundant_candidate(seg);
}
/* 学習の履歴を適用する */
apply_learning(sl, nth);
/* またソートする */
for ( i = nth ; i < sl->nr_segments ; i++){
sort_segment(anthy_get_nth_segment(sl, i));
}
/* カタカナの候補が先頭でなければ最後に回す */
for (i = nth; i < sl->nr_segments; i++) {
trim_kana_candidate(anthy_get_nth_segment(sl, i));
}
/* またソートする */
for ( i = nth ; i < sl->nr_segments ; i++){
sort_segment(anthy_get_nth_segment(sl, i));
}
}
|