# 辞書の抽出

English version

この段階では，変形した構文木から辞書 (lexicon) とテンプレートデータベースを抽出します． 辞書というのは， 単語情報 ('word' 型) から語彙項目テンプレートの名前 ('lex_entry' 型) へのマッピングを集めたものです． テンプレートデータベースというのは， 語彙項目テンプレートの名前から語彙項目テンプレートの素性構造 ('hpsg_word' 型) へのマッピングを集めたものです．

抽出処理は，2段階に分かれています． 前半では， 変形された構文木から HPSG などの文法に沿った導出木を作り， 導出木の葉ノードの素性構造から辞書とテンプレートデータベースをつくります． 後半では， 抽出した辞書とテンプレートデータベースに， 頻度の低い項目を消したり，未知語の項目を作ったりといった精製処理を行い， 最終的な辞書とテンプレートデータベースをつくります． これらの処理において， 導出木は "mayz/derivtypes.lil" で定義された型で表現されています．

## 辞書とテンプレートデータベースの抽出

ここでは，変形した構文木から目的の文法による導出木を作り， 辞書とテンプレートデータベースを抽出する過程について説明します． この過程は，mayz の lexextract ツールを利用し、下記のコマンドによって行われます． （lexextract ツールについて詳しくは， mayz のマニュアルも参照してください．）

lexextract 文法獲得モジュール treebank derivbank 辞書 テンプレートデータベース lexbank
文法獲得モジュール | 逆方向のスキーマと語彙規則（後述）などが定義された lilfes ファイル
treebank | 入力の構文木データベース (lildb 形式)
derivbank | 導出木を出力するデータベース (lildb 形式)
辞書 | 辞書を出力するデータベース (lildb 形式)
テンプレートデータベース | 語彙項目テンプレートを出力するデータベース (lildb 形式)
lexbank | 導出木の葉ノードを出力するデータベース (lildb 形式)

Enju の文法開の場合， 文法獲得モジュールは "enju-devel/lexextract.lil" です． 入力 treebank の構文木は， 前段階のコーパスの変形で得られたもの（例）になります． それらの構文木から HPSG による導出木(例)が作られ， 辞書の抽出に使われます．

### 構文木から導出木への変換

lexextract ツールはまず， 入力された構文木をもとにして目的文法による導出木を作ります． 具体的には，はじめに導出木の根ノードをつくり， もとの構文木の形に合わせて逆方向のスキーマを適用して，親ノードから娘ノードを作っていきます． 最後に，葉ノードに導出木の葉ノードとして満たすべき制約をかけ， 導出木の完成となります． 導出木の根ノードや葉ノードの制約はインターフェース述語 `root_constraints/1`， `lexical_constraints/2` でそれぞれ指定できます． 逆方向のスキーマは， インターフェース述語 `inverse_schema_binary/4`， `inverse_schema_unary/3` で指定します． まとめると，導出木は以下の手順で作られます．

1. 導出木の根ノードの sign に述語 `root_constraints/1` で定められた制約をかける．
2. 導出木の他のノードをつくる． もとの構文木で単項木の場合は述語 `inverse_schema_unary/3`， 二分木の場合は述語 `inverse_schema_binary/4` によって逆方向スキーマを適用し， 親ノードの sign から娘ノードの sign をつくる．
3. 導出木の葉ノードに述語 `lexical_constraints/2` で定められた制約をかける． 対応する単語情報 ('word' 型)に応じて制約を変えることができる．

Enju 文法の場合，導出木のノードや逆方向スキーマに次のような制約を指定しています．

- 導出木の根ノードでは， VAL 素性の下の SUBJ，COMPS，SPR，SPEC，CONJ 素性の値は全て空リストでなければいけない．
- 逆方向の Head-Subject schema を使うと親ノードから2つの娘ノードが作られ， 右の娘の sign の VAL\SUBJ 素性と左の娘の sign が単一化される．
- 導出木の葉ノードで単語文字列として "be"，"was" などを持つものは， sign の HEAD\AUX 素性が 'copula_be' でなければならない．

これらはインターフェース述語を使って，次のように指定されます． 詳しい実装は "enju-devel/invschema.lil" を見てください．

>     root_constraints($Sign) :-
>         $Sign = (SYNSEM\(LOCAL\CAT\(HEAD\MOD\[] &
>     				VAL\(SUBJ\[] & COMPS\[] &
>     				SPR\hpsg_synsem_exp_nil &
>     				SPEC\[] & CONJ\[])))).

>     inverse_schema_binary(subj_head_schema,
>     		      $Mother, $Left, $Right) :-
>         $Left = (SYNSEM\($LeftSynsem &
>     		     LOCAL\CAT\(HEAD\MOD\[] &
>     				VAL\(SUBJ\[] &
>     				     COMPS\[] &
>     				     SPR\[] &
>     				     SPEC\[] &
>     				     CONJ\[])))),
>         $Subj = $LeftSynsem,
>         $Right = (SYNSEM\(LOCAL\CAT\(HEAD\$Head &
>     				 VAL\(SUBJ\[$Subj] &
>     				      COMPS\[] &
>     				      SPR\[] &
>     				      SPEC\$Spec &
>     				      CONJ\[])))),
>         $Mother = (SYNSEM\(LOCAL\CAT\(HEAD\$Head &
>     				  VAL\(SUBJ\[] &
>     				       COMPS\[] &
>     				       SPR\[] &
>     				       SPEC\$Spec &
>     				       CONJ\[])))).

>     lexical_constraints(SURFACE\$Surface,
>                         SYNSEM\LOCAL\CAT\HEAD\AUX\hpsg_copula_be) :-
>         auxiliary_be($Surface).

### 辞書項目と語彙項目テンプレートの抽出

lexextract ツールは次に， 導出木の葉ノードから，辞書とテンプレートデータベースを作ります． 葉ノードの単語情報からは辞書のキーが，葉ノードの sign からは語彙項目テンプレートが得られます． ここでは， 語彙項目テンプレートをそのまま登録するのではなく， 語彙項目テンプレートの元となる「語彙素テンプレート」という素性構造を作って登録することもできます． 語彙項目テンプレートから語彙素テンプレートを作る方法， つまり逆方向の語彙規則はインターフェース述語 `reduce_lexical_template/5` で指定します． 他にも辞書のキーの作り方などを，インターフェース述語 `lexeme_name/4`，`lexical_entry_template/3`， `lexicon_key/2` で指定できます． これらの述語を用いて，以下のように抽出作業が行われます．

1. 導出木の葉ノードに述語 `lexical_entry_template/3` を適用して，語彙項目テンプレートを作る．
2. 得られた語彙項目テンプレートに述語 `reduce_lexical_template/5` で定義した逆方向の語彙規則を適用し，語彙素テンプレートを作る．このとき，この語彙素テンプレートのための辞書のキーも計算する．
3. 語彙素テンプレートの名前を述語`lexeme_name/4` により計算しデータベースに登録する．(語彙素テンプレートが初出のものの場合)
4. 辞書に 2. で計算したキーから語彙素テンプレートの名前へのマッピングを登録する． また 2. のキーの出現回数をインクリメントする．
5. 1. で得た語彙項目テンプレートのための辞書のキーを述語 `lexicon_key/2` を使って計算する．辞書にそのキーから語彙項目テンプレートの名前へのマッピングを登録し，キーの出現回数をインクリメントする．

Enju の文法開発では，上記インターフェース述語で 次のような指定をしています．

- 語彙項目テンプレートを作るとき，sign の CAT，NONLOCAL 素性の値は葉ノードの sign の CAT，NONLOCAL 素性の制約を緩めたものにする．これはいくつかの素性の値を最も一般的な型にすることで行われる．
- 語彙素テンプレートは， 語彙項目テンプレートに語彙規則を逆適用してつくる．
- 語彙素の名前は，CAT 素性の値を表す文字列と VAL\SUBJ 素性等の値を表す文字列を組み合わせて作る．例えば名詞句の主語と目的語をとる他動詞のテンプレートの場合名前は，[NP.nom<V.bse>NP.acc]_lxm 等となる．

これらの制約はたとえば次のように指定されます． 正確な実装は "enju-devel/lextemplate.lil"，"enju-devel/invlexrule.lil" を見てください．

>     lexical_entry_template($WordInfo, $Sign, $Template) :-
>         make_semantics($WordInfo, $Sign, $LexName1, $Cont1),
>         ...
>         abstract_lexical_template($Template).

>     abstract_lexical_template($Template):-
>         $Template = (SYNSEM\(LOCAL\CAT\(HEAD\($Head & MOD\$Mod) &
>     				    VAL\(SUBJ\$Subj &
>     					 COMPS\$Comps &
>     					 SPR\$Spr &
>     					 SPEC\$Spec &
>     					 CONJ\$Conj)) &
>     			 NONLOCAL\INHER\(REL\$Rel &
>     					 SLASH\$Slash &
>     					 F_REL\$FRel))),
>         abstract_mod($Mod, $Head),
>         abstract_subj_list($Subj, $Template),
>         abstract_comp_list($Comps, $Template),
>         ...
>         abstract_head($Head).

>     abstract_subj($Synsem, SYNSEM\LOCAL\CAT\HEAD\$Head) :-
>         restriction($Synsem, [NONLOCAL\]),
>         restriction($Synsem, [LOCAL\, CAT\, HEAD\, POSTHEAD\]),
>         restriction($Synsem, [LOCAL\, CAT\, HEAD\, AGR\]),
>         restriction($Synsem, [LOCAL\, CAT\, HEAD\, AUX\]),
>         ...
>         generalize_subj_head($Synsem, $Head).

>     reduce_lexical_template($WordInfo, $LexEntry, $Key, $Lexeme, $Rules) :-
>         get_sign($LexEntry, $Sign),
>         get_lexeme($WordInfo, $LexEntry, $BaseWordInfo, $Lexeme1, [], $Rules1),
>         canonical_copy($Lexeme1, $Lexeme),
>         $Rules = $Rules1,
>         $BaseWordInfo = (BASE\$Base & POS\$POS),
>         $Key = (BASE\$Base & POS\$POS).

>     get_lexeme($WordInfo, $InTemplate, $NewWordInfo, $NewTemplate,
>     	   $InRules, $NewRules) :-
>         ($InRules = [$Rule1|_] ->
>          upper_rule($Rule1, $Rule); true),
>         inverse_rule_lex($Rule, $WordInfo, $InTemplate, $WordInfo1, $Template1),
>         get_lexeme($WordInfo1, $Template1, $NewWordInfo, $NewTemplate,
>     	       [$Rule|$InRules], $NewRules).

## 辞書とテンプレートデータベースの精製

ここでは，抽出された辞書とテンプレートデータベースを精製する過程について説明します． この過程は，mayz の lexrefine ツールを利用し、下記のコマンドによって行われます． （lexrefine ツールについて詳しくは， mayz のマニュアルも参照してください．）

lexrefine ルールモジュール 元辞書 元テンプレートデータベース 新辞書 新テンプレートデータベース
ルールモジュール | 語彙規則が定義されたモジュール
元辞書 | 入力の辞書
元テンプレートデータベース | 入力のテンプレートデータベース
新辞書 | 精製された出力辞書
新テンプレートデータベース | 精製された出力テンプレートデータベース

lexrefine ツールでは， まず出現回数の少ないテンプレートを削除したりしてテンプレートベータベースを精製します． 次にテンプレートデータベースの精製による変化に辞書を追随させます． また未知語に対応するため，未知語エントリを辞書に作ります． Enju の文法開発の場合， ルールモジュールは "enju-devel/lexrule.lil" を使っています．

### テンプレートデータベースの精製

lexrefine ツールでは，まず入力のテンプレートデータベースが精製されます． 具体的には，頻度の小さいテンプレートを削除した後， 残ったテンプレートに語彙規則が適用され 派生語のテンプレートが作られます． 語彙規則はインターフェース述語 `expand_lexical_template/5` によって指定してください． 具体的な精製作業は次のようになります．

1. 入力テンプレートデータベース中の，出現回数が閾値 (-tf オプションで指定)より大きいテンプレートを出力テンプレートデータベースに格納する．
2. 出力データベースの中のテンプレートに述語 `expand_lexical_template/5` によって語彙規則を適用し，派生語のテンプレートを作る．派生語のテンプレートも出力データベースに格納し，その出現回数として元テンプレートの出現回数を与える．

Enju の場合の語彙規則については， 語彙規則のページを参照してください． 語彙規則の指定はたとえば次のようになります． 正確な実装については，"enju-devel/lexrule.lil" を参照してください．

>     expand_lexical_template($InTempName, $InTemplate, $Count, $LexRules, $NewTemplate) :-
>          get_variable('*template_expand_threshold*', $Thres),
>          ($Count > $Thres ->
>           ordered_lexical_rules($LexRules),
>           apply_ordered_lexical_rules(_, $InTemplate, $LexRules, _, $Template1),
>           get_sign($Template1, $NewTemplate);
>           $LexRules = [],
>           get_sign($InTemplate, $NewTemplate)).

### 辞書の精製

ここでは，テンプレートデータベースの精製によって生じた変化に 辞書の追随させる過程を説明します． つまり， テンプレートデータベースで削除されたテンプレートのためのエントリを辞書から消したり， 追加されたテンプレートのエントリを辞書に追加したりして， 新しい辞書を作ります． また未知語のためのエントリを追加します． 追加されたテンプレートのために辞書のキーを作る方法は， インターフェース述語 `expand_lexicon/3` によって指定してください． 新しい辞書は，元の辞書の各エントリに次のような処理をして作られます．

1. エントリのテンプレートが新テンプレートデータベースに残っていたらそのエントリを新辞書に加える．
2. そのエントリのテンプレートから作られた派生語テンプレートがあるなら，述語 `expand_lexicon/3` によって新しい辞書キーを作り派生語テンプレートのためのエントリを新辞書に登録する．新しいキーの出現回数として，元のテンプレートのためのキーの頻度を与える．

Enju の場合，辞書のキーは BASE 素性と POS 素性が特定されている 'word' 型です． インターフェース述語 `expand_lexicon/3` で作る語彙項目のキーは 元テンプレートのキーの POS 素性の値を変えた 'word' 型になります． 新しいキーの POS 素性は，新しいテンプレートを作った語彙規則で決められます． 例えば， 動詞の語彙素テンプレートから3人称現在単数形のテンプレートを作るルールが適用された場合， 語彙項目のキーの POS 素性は "VBZ" となります．

>     expand_lexicon($InKey, $NewTempName, $NewKey) :-
>         $InKey = BASE\$Base & POS\$BasePOS,
>         $NewTempName = LEXICAL_RULES\$Rules,
>         rules_to_inflection($BasePOS, $Rules, $POSList),
>         member($NewPOS, $POSList),
>         $NewKey = BASE\$Base & POS\$NewPOS.

### 未知語の辞書項目の追加

lexrefine は次に，未知語のためのエントリを辞書に追加します． つまり，頻度が閾値以下の単語を未知語とみなして新たなエントリを作ります． 新たなエントリのキーを作る方法は， インターフェース述語 `unknown_word_key/2` で指定します． 具体的な処理は次のようになります．

1. 新辞書のエントリがキーの頻度が閾値 (-uwf オプションで指定) 以下なら，`unknown_word_key/2` によってそのキーから未知語エントリのためのキーを作る．
2. 元のキーに割り当てられているテンプレートのうち，出現頻度が閾値(-utf オプションで指定) より大きいものと未知語キーのエントリを新辞書に追加する．
3. 元のキーの頻度が閾値 (-wf オプションで指定) 以下の場合は，元のキーのエントリを削除する．

Enju の場合，未知語のキーは POS 素性のみ特定されている 'word' 型です． インターフェース述語 `unknown_word_key/2` では， 未知語のキーとして元のキーの POS 素性と同じ値をもつ 'word' 型を返します．

>     unknown_word_key(POS\$POS, POS\$POS).

Enju 開発者用マニュアル Enju ホームページ 辻井研究室