#元ネタ
おもちゃのプロダクションシステムについては、後藤滋樹先生の「記号処理プログラミング」のLispでの題材が元ネタです。化学反応を調べるプロダクションシステムです。
#化学の復習
炭素と水素、酸素は次のプロセスをたどって二酸化炭素と水になります。高校時代に化学でやったはずなのですが、忘却の彼方です。(およそ40年前)
これには2つの経路があります。
(1) C + 2H2 + 2O2 => CO2 + 2H2 + O2 => CO2 + 2H2O
(2) C + 2H2 + 2O2 => CH4 + 2O2 => CO2 + 2H2O
#金物表現
Prologでは大文字のC,Hなどは変数と解釈されていまいます。’C'とすればいいのですが、煩わしいので小文字ということにします。また、2H2Oというのも先頭が数になるためアトムとしては使えません。この場合は H2O + H2O ということにします。
#動作
とりあえず動かしてみます。
| ?-reaction([c,h2,o2,o2,h2,],Y).
[ch4,o2,o2]
[co2,h2o,h2o]
Y = [co2,h2o,h2o]
yes
|
(2)の経路をたどっています。
#仕組み
プロダクションシステムは次の3つから構成されます。
(1)ルール(あるいは長期記憶)
(2)短期記憶
(3)制御部
(1)のルールは化学反応の個々のルールです。
(2)はその時点での操作対象となっているデータを保持している部分です。今回はリストで表現しています。
(3)短期記憶に対してどのようにルールを適用するかを判断し、ルールに応じた動作を行う部分です。今回はここを手抜きをして単純にPrologのルールの並んでいる順番に適応することにしています。
#コード
トイプログラムです。とても単純なものです。
reaction(X,Y) :-
rule(X,Y).
%ルール
rule(X,Y) :-
check(c,1,X),
check(h2,2,X),
remove(c,1,X,X1),
remove(h2,2,X1,X2),
append([ch4],X2,Z),
write(Z),nl,
rule(Z,Y).
rule(X,Y) :-
check(c,1,X),
check(o2,1,X),
remove(c,1,X,X1),
remove(o2,1,X1,X2),
append([co2],X2,Z),
write(Z),nl,
rule(Z,Y).
rule(X,Y) :-
check(h2,2,X),
check(o2,1,X),
remove(h2,2,X,X1),
remove(o2,1,X1,X2),
append([h2o,h2o],X2,Z),
write(Z),nl,
rule(Z,Y).
rule(X,Y) :-
check(ch4,1,X),
check(o2,2,X),
remove(ch4,1,X,X1),
remove(o2,2,X1,X2),
append([co2,h2o,h2o],X2,Z),
write(Z),nl,
rule(Z,Y).
rule(X,X).
%元素が一定の個数以上あるかどうか
check(A,B,X) :-
count(A,C,X),
C >= B.
%元素の数を数える
count(A,0,[]).
count(A,C,[A|L]) :-
count(A,C1,L),
C is C1 + 1.
count(A,C,[L|Ls]) :-
count(A,C,Ls).
%元素を指定した個数分、削除する。
remove(A,0,L,L).
remove(A,B,[A|L],Y) :-
B1 is B - 1,
remove(A,B1,L,Y).
remove(A,B,[L|Ls],[L|Y]) :-
remove(A,B,Ls,Y).
#問題点
実行例では(2)の経路で求められていました。これは単純にルールの順番に呼び出しているからです。(1)の経路で求めるにはルールの順番を変更する必要があります。
#本格的には
本格的には制御部をちゃんと作らないといけません。どのようにルールを適用していくのかという工夫をしないと実用になるものにはなりません。第二次AIブームの頃にOPS5というエキスパートシステム構築用のツールがあったように記憶しています。
#受験勉強のお供に
量子力学を学ぶとどうして、炭素には手がいっぱいあるのか、など納得がいくようになります。しかし、高校時代は暗記しかないようです。Prologに化学反応のことを教えるという立場になれば、化学受験勉強もいくらか楽しいものになるかもしれません。
#参考文献
「記号処理プログラミング」 後藤滋樹 著 岩波書店