第14章 問題をいくつかの部分問題に分ける

第14章
問題をいくつかの部分問題に分ける
1.問題をいくつかの部分に分ける
プログラムはルールから構成され、ルールは問題を簡単化するために使われる。この簡
単化とは何を意味するのだろうか。どのようなルールを書けば、ルールを組み合わせるこ
とで得られるプログラムはうまく動くのだろうか。ここでは、プログラムが満たすべき基
本的な性質と、各ルールが満たすべき条件について学ぶ。
2.述語やアトムの分類
述 語 は 、 ET 言 語 に 組 み 込 ま れ た ル ー チ ン で 計 算 さ れ る 組 み 込 み 述 語 ( B 述 語 : B は
Built-in の 頭 文 字 ) と 、 D ル ー ル で 計 算 さ れ る D 述 語 に 分 け る こ と が で き る 。 な お 、 こ の
分け方をアトムにも適用し、それぞれ B アトム、D アトムと呼ぶ。
D ル ー ル に よ る 計 算 は 、D ア ト ム と B ア ト ム を 用 い て 行 わ れ る 。 B ア ト ム は 、人 間 と 情
報 を や り 取 り し た り 、変 数 を 具 体 化 し た り し て 、計 算 機 の 状 態 を 実 質 的 に 変 更 す る 。一 方 D
ア ト ム は 、ど の よ う な B ア ト ム が 処 理 さ れ る べ き か に 影 響 を 与 え 、B ア ト ム を 介 し て 計 算
機の状態を変更する。このような観点から見ると、D ルールからなるプログラムの実行と
は、B アトムの実行の列を引き起こすものと理解できる。
3.プログラムの正当性
プログラムが想定されるすべての問題を正しく解くとき、プログラムは正当である、あ
る い は 、 プ ロ グ ラ ム は 正 当 性 を 持 つ と い う 。 ET プ ロ グ ラ ミ ン グ で は 、 正 当 性 を 保 証 す る
ために、各ルールが、問題を常に等価な問題に置き換えることを要請する。各ルールを正
し く 書 く と い う こ と を 積 み 重 ね る か ぎ り 、プ ロ グ ラ ム が 誤 っ た 答 を 出 す こ と を 回 避 で き る 。
そうしなければ、プログラムの正当性を保証するのは極めて困難になる場合が多い。
4.停止性
問題を計算機で解こうとするとき、いつまでも計算が止まらず、解が具体的に得られな
いのは好ましくない。プログラムが扱おうとしている問題を解こうとするとき、計算が有
限時間で終結することを保証するためには、必ず問題を簡単化するように各ルールを書く
ことが非常に有効である。そうすれば、ルールが適用されるごとに問題は簡単化され、最
終的には最も簡単な問題に至り、計算は終結する。ただし、何が簡単かを決める尺度を選
75
ぶ必要がある。通常使われる方法は、ボディのすべてのアトムがヘッドのアトムより簡単
であれば、問題は簡単化されると考える。その判定の基礎となるアトム同士の比較は次の
ように決める。
①
B アトムは D アトムより簡単である。
②
D アトム同士は、述語間の順序関係から比較する。
③
同じ述語を持つアトム同士は、引数の S 式のサイズから比較する。
この定義によれば、結局、述語間の順序と項の順序が基礎になって、簡単化に関するすべ
ての順序が決まることになる。
たとえば、リストにおける 2 の出現数を求める次のプログラムを考える。
(occur2 (*A|*X) *N) --> (occur2 *X *M), (count_up *A *M *N).
(occur2 ( ) *N) --> (= *N 0).
(count_up 2 *M *N) --> (:= *N (+ *M 1)).
(count_up *A *M *N) --> (= *N *M).
これは、
①
(*A|*X)よ り *X が 簡 単 と い う 項 の 順 序
②
occur2 よ り count_up が 簡 単 と い う 述 語 の 順 序
によって、停止性が確認できる。
5.ルールのパターン
5.1
B アトムに直す
D アトムを、いくつかの B アトムに直すルールは、最も簡単なタイプのルールである。
B アトムは有限時間で実行可能なアトムなので、この種のルールが、計算の停止性を阻害
することはない。したがって、正当性を保持しながら両辺が等価になることを考えて、ル
ールを記述するとよい。
(1)
1つの B アトムに直す
例 え ば 、 *N の 2 乗 *X を 求 め る ル ー ル は 、 以 下 の よ う に 書 く こ と が で き る 。
(square *N *X) --> (:= *X (x *N *N)).
意 味 : {Head … *N の 2 乗 が *X で あ る 。
Body … *N×*N が *X で あ る 。 }
76
こ の ル ー ル は 、 Body が B ア ト ム ( 組 み 込 み 述 語 は :=) で 記 述 さ れ て い る 。 両 辺 は 、
「 *N の 2 乗 が *X で あ る 」 と 「 *N×*N が *X で あ る 」
なので、等価であることは明らかである。
(2)
2 つの B アトムに直す
整 数 で し か も 2 で 割 り 切 れ る と き 成 功 す る ル ー ル ( 述 語 名 even) は 、
(even *X) --> (int *X), (:= 0 (mod *X 2)).
と 書 け る 。こ れ は 、「 整 数 で あ る 」と い う 条 件 と「 2 で 割 り 切 れ る 」条 件 を 並 べ て い る 。ル
ー ル の ボ デ ィ の コ ン マ は 連 言 ( and、「 か つ 」、「 し か も 」) を 表 す の で 、 明 ら か に ヘ ッ ド と
ボ デ ィ は 等 価 で あ る 。 ち な み に int は 、 与 え ら れ た 値 が 整 数 で あ る か ど う か を 検 査 す る 組
み込み述語であり、値が整数でないときは失敗を返す。
(3)
中間変数がある場合
例 え ば 、200 円 の り ん ご を *N 個 買 い 、そ の 合 計 額 に 消 費 税 を 5% 上 乗 せ し た 金 額 *X を 求
め る 。こ の 問 題 は 、① り ん ご の 値 段 を 計 算 す る 、② 消 費 税 を 上 乗 せ し た 金 額 を 計 算 す る 、
と 2 段 階 に 計 算 で き る の で 、 pay と い う 述 語 を 用 い て 、 次 の ル ー ル を 書 く こ と が で き る 。
(pay *N *P) --> (:= *X (x 200 *N)), (:= *P (d (x *X 105) 100)).
意 味 :{ Head … り ん ご を *N 個 買 っ た と き の 金 額 が *P で あ る 。
Body … *X= 200×*N を 計 算 し 、 *P= *X×105÷100 を 計 算 す る 。 }
こ の ル ー ル の 中 の 変 数 *X は ヘ ッ ド に は 出 現 し な い の で 、中 間 変 数 で あ る 。上 記 の ル ー ル は 、
この中間変数を使わずに次のように書ける。
(pay *N *P) --> (:= *P (d (x (x 200 *N) 105) 100)).
意 味 : {Head … り ん ご を *N 個 買 っ た と き の 金 額 が *P で あ る 。
Body … 200×*N×105÷100 を 計 算 し *P と す る 。 }
5.2
別の述語名の D アトムに直す
ルールのボディには、B アトムだけでなく、D アトムを含むことも可能である。ここで
は、ヘッドの述語名と異なる述語名を持つ D アトムが含まれる場合を考える。このとき、
ボ デ ィ の D ア ト ム は 、ヘ ッ ド の D ア ト ム よ り も 簡 単 で あ る こ と が 仮 定 さ れ て い る 。ヘ ッ ド
の D アトムはボディにおいて、より簡単ないくつかの D アトムと B アトムになり、何回
かの書き換えの結果、いくつかの B アトムになって実行される。
77
(1)
1 つの別の述語名の D アトムに直す
*N の 2 乗 の 関 係 を 表 す ア ト ム を 、 掛 け 算 の 関 係 を 表 現 す る D ア ト ム に 直 す ル ー ル を 考
える。
(square *N *X) --> (mult *N *N *X).
意 味 : {Head … *N の 2 乗 が *X で あ る 。
Body … *N と *N を か け た 答 が *X で あ る 。 }
こ の ル ー ル は 、 square ア ト ム を ユ ー ザ 定 義 の mult ア ト ム ( D ア ト ム ) に 置 き 換 え る 。
(2)
2 つの別の述語名の D アトムに直す
最小公倍数を求めるために、最大公約数を利用することができる。ルールにすると次の
ようになる。
(LCM *N *M *min) --> (GCD *N *M *max), (multdiv *N *M *max *min).
意 味 : {Head … *N と *M の 最 小 公 倍 数 は *min で あ る 。
Body … *N と *M の 最 大 公 約 数 が *max で 、 *N×*M / *max= *min で あ る 。 }
GCD ア ト ム は 再 帰 ル ー ル な ど を 使 っ て 、 最 終 的 に は B ア ト ム に 還 元 さ れ る 。 multdiv ア ト
ム(D アトム)は、直接 B アトムに還元される。
5.3
同一の述語名の D アトムに直す
ルールのボディにヘッドの述語名と同じ述語名を持つ D アトムが含まれる場合を考える。
こ の 場 合 、ボ デ ィ の そ の D ア ト ム は 、ヘ ッ ド の D ア ト ム よ り も 簡 単 で あ る こ と が 仮 定 さ れ
ている。ヘッドの D アトムは、ボディにおいてより簡単ないくつかの D アトムと B アト
ムになり、何回かの書き換えの結果、いくつかの B アトムの実行に置き換えられる。
(1)
1 つの同一の述語名のアトムに直す
例 え ば 、 与 え ら れ た 数 *N が 偶 数 か ど う か を 判 定 す る 問 題 を 考 え る 。
(even *N),{(> *N 1)} --> (:= *N1 (- *N 2)),(even *N1).
意 味 : {Head … *N が 偶 数 で あ る 。
Body … *N- 2= *N1 で 、 *N1 が 偶 数 で あ る 。 }
こ の 場 合 、ボ デ ィ の 最 後 の (even *N1) は 、ヘ ッ ド の (even *N) と 同 一 の 述 語 を 持 つ が 、
*N1 は *N よ り 2 少 な い の で 、 よ り 簡 単 な ア ト ム と い え る 。 一 方 、 ヘ ッ ド と ボ デ ィ が 等 価 で
あ る こ と は 、 ヘ ッ ド が 「 *N は 偶 数 で あ る 」 を 意 味 し 、 ボ デ ィ が 「 *N か ら 2 を 引 い た 数 が
偶数である」を意味することから明らかである。
78
(2)
2 つの同一の述語名のアトムに直す
例えば、2 が出現しないとき成功するプログラムを考える。
(NEtwo (*A|*B)) --> (NEtwo *A), (NEtwo *B).
(NEtwo 2) -->
(false).
(NEtwo *X) -->.
こ の 第 1 番 目 の ル ー ル の ヘ ッ ド に あ る ア ト ム は (NEtwo (*A|*B)) で あ る が 、 こ の 述 語
NEtwo
を 持 つ ア ト ム が ボ デ ィ に 2 つ 存 在 す る 。両 方 と も ヘ ッ ド よ り も 小 さ い 問 題 で あ る 。
また、ヘッドとボディの意味は、
ヘ ッ ド … 「 (*A|*B)に 2 が 含 ま れ な い 」
ボ デ ィ … 「 *A に 2 が 含 ま れ ず 、 *B に 2 が 含 ま れ な い 」
であるから、両者の等価性は明らかである。
79