goo blog サービス終了のお知らせ 

不幸改め鈴木のブログ

残業TIMEスルー継続中

Prolog進行具合

2007-11-28 22:04:26 | Prologまとめ
実験状況:我々は抵抗をあきらめ(ry



さて、われらがB2ウェーブレット小隊の本日の成果をメモメモっと。

稼働率:60% 人員2名欠員
作業率:10% GUIほぼ進まず
損害 :20% オレはTAからダメージをうけた!


うーん。よろしくない。非常によろしくない。
このままでは前線に転戦する可能性だってある。

つーか、PrologをJAVAにトランスレータでどーのこーのっつーのはだいたいわかったんだけど、英文解読に時間がかかりすぎてる。
プログラムの出来具合は1,2を争ってる気がするんだけども。
まぁ他の班もGUIにはかなり手間取ってるみたいだし、今のところはセーフか。



とりあえず、賢者がJASPERとJIPLでがんばってた。
オレはXPCEをSICSTUSにリンクさせる方法を現在捜索中。
わかりやすい日本語HowToページがほしいところOTL



あと、我が家にもPrologを導入してみようかな?
SWI-Prologというのがフリーっぽいので。



まぁなんにせよ、戦況は思わしくない。
打開策を模索しているうちに納期がこないことを祈る。


JAVA トランスレータ

2007-11-14 22:33:35 | Prologまとめ
キーワードはJPIとJIPL?






JAVAを用いたGUI作成段階まできたわけなんですけど、具体的にどうやってSicstusとやりとりするのかがいまいちぱっとしない。

他のグループもだいぶてこずっている模様。

とりあえず基本的なプログラムはほぼ完成・・・・・
あれ・・・おかしいな、目から汗が・・・





うん、完成したので、後はGUI関連を作れば残すはDB。
まぁ期限は1月16だったと思うので、まだだいぶ余裕はある。



とはいってもなんつーか・・・
班員が墨谷2中状態。



敵は98のパワフル高校。マジきついw
どうすっかねー・・・

プロログまとめ4

2007-10-10 03:46:09 | Prologまとめ
こんなことになるなら月曜日にやっとくべきだったね(・∀・)




お猿さん問題を解決する!
いよいよプログラミングらしくていい分野に突入であります。



ある部屋にサルがいる。
その部屋の中央にはバナナが吊られている。
サルには高くて届かない。
部屋の窓のそばには、サルが登れるくらいの箱がおいてある。
サルはその箱を押して歩ける。


サルの取れる行動は
歩く
箱を押す
箱に乗る
とする。

バナナの下で箱に登れば手が届くとする。





さて、サルはどうすればバナナがとれるだろうか。






やっとこ人工知能っぽくなってきたなぁ・・・








・世界の初期状態を仮定しよう
まず、存在する世界の初期設定を仮定する。
プロログ的に言うならば事実を述べるといったところか。



サルは初期値として、ドア付近にいる。
サルは床の上にいる(箱の上にのぼっていない)
箱は窓のそばにある。
サルはバナナをもっていない。


できる限り簡略化して、かつ必要な情報を的確に抽出するのがポイントだろうか。



・世界の状態を表現するオブジェクトを作る。

サルは初期値として、ドア付近にいる。
サルは床の上にいる(箱の上にのぼっていない)
箱は窓のそばにある。
サルはバナナをもっていない。

今この4つの初期値が存在するわけだから、

state(neardoor,onfloor,nearwindow,hasnt).

が妥当。
成分は
サルの位置、サルの高さの位置、箱の位置、バナナの有無
である。



・サルは世界に介入する・・・介入された世界は別の世界になる
至極当然のことだが、今、キーボードをたたいている俺がいるからこんな駄文ができるわけだ。
世界への介入である。



さておいて、サルが動けば先ほど定義した世界も変化するつーこと。
では世界を変化させるサルの動作をまとめてみる。


サルはバナナをとる
・・・サルがバナナの真下で箱に登っているときのみ可能
サルは箱に乗れる
・・・サルが箱にのぼっていないならばのぼれるでしょう
サルは箱を押せる
・・・サルが箱の近くにいないと押せません
サルは歩く
・・・生きてる限りうろうろするでしょう

このとき行動の順位に気をつける。
人工知能学では、探索の基本らしい。


つーのは、要するにサルが取れる確立の低い行動から検証しろってこと。
確率の低い行動から検証すれば分岐する確立も減るので、計算時間が短縮する。



・サルの動作を定義してみよう

おサルの動作をmoveとして定義してみることにする。
ある世界の状態Aでサルが行動を取ると、世界の状態はBへ遷移する
つーのがよい。

move(State1,Action,State2).

これに世界状態を代入して行動を定義していく。



サルはバナナをとる
・・・サルがバナナの真下で箱に登っているときのみ可能

世界状態A state(middle,onbox,middle,hasnt).
行動    get
世界状態B state(middle,onbox,middle,has).
こうなればいいわけだ。



サルは箱に乗れる
・・・箱にのぼっていないならばのぼれるでしょう

世界状態A state(X,onfloor,Y,Z).
行動    crimb
世界状態B state(X,onbox,Y,Z).

サルは箱を押せる
・・・サルが箱の近くにいないと押せません

世界状態A state(X,onfloor,X,Z).
行動    push(X,Y)
世界状態B state(Y,onfloor,Y,Z).

X地点にあった箱をY地点まで押してったってこと。


サルは歩く
世界状態A state(X1,onfloor,Y,Z).
行動    walk(X1,X2)
世界状態B state(X2,onfloor,Y,Z).

x1地点からX2地点へ移動。





・定義完了・・・まじか?
あとはサルがバナナを手に入れられるかどうか。の質問が通るようにすればいい。

要求条件
サルはバナナを手に入れられるかどうかを調べる。

事実条件
サルはバナナを持っている。
世界状態Aに、あるアクションを加えたとき、バナナを入手できる。


この、簡素に観察された状態を導き出すのはまだ無理だなぁ・・・



canget(State).とでもしよう。


サルはバナナを持っている。
なら
canget(state(_,_,_,has)).
で安定


世界状態Aに、あるアクションを加えたとき、バナナを入手できる。

canget(StateA) :- move(StateA,Action,StateB) , canget(StateB).

世界Aにアクションを加えた状態が、バナナを持っているならば、真
と。




・完成!

まとめてみる。

move(state(middle,onbox,middle,hasnt),get,state(middle,onbox,middle,has)).
move(state(X,onfloor,Y,Z),crimb,state(X,onbox,Y,Z)).
move(state(X,onfloor,X,Z),push(X,Y),state(Y,onfloor,Y,Z)).
move(state(X1,onfloor,Y,Z),walk(X1,X2),state(X2,onfloor,Y,Z)).

canget(state(_,_,_,has)).
canget(StateA) :- move(StateA,Action,StateB) , canget(StateB).

・・・え?6行?
まじかよ・・・



流れを検証する・・・

?- canget(state(neardoor,onfloor,nearwindow,hasnt)).
初期値を与えて質問。

1・・・サルはバナナを持っている(偽)
 ・・・あるアクションを加えたときバナナを持っているかどうか調べる
2・・・
バナナがつかめるか?偽
箱に登れるか?偽
箱を押せるか?偽
歩けるか?真

よって歩いた後の世界状態がバナナをとっているかどうかを調べる。1へ戻る。


あらま。すごいねこりゃ。








ぷろろぐまとめ3・4終了



ぷろろぐまとめ3

2007-10-10 02:45:04 | Prologまとめ
・プロログとリスト構造
  プロログでリストを構築するには以下のとおり
    [a,b,c,d].

  空リストを生成する場合は
    [].

  また、上記リストにおける a を Head 、残りの b c d を Tail と呼ぶ。

  リスト表現は
    .(a , .(b , .(c , .(d , []))))

  リストは、 [Head | Tail ] のようにも表すことができる。


・リスト探索プログラム
  リストの中から任意の情報を探索するプログラムを書く。

  事実条件
  探したいデータがリストの先頭にあれば、真
  探したいデータがリストの尾部(Tail)に存在すれば、真

search(X,[X|_]).
・・・探したいデータXとリストの先頭がユニファイなら真
search(X,[Head|Tail]) :- search(X,Tail).
  ・・・探したいデータXがリストの尾部にあるならば、探したいデータXはりスト中に存在する。
  ※要検証


・プロログにおけるリスト操作の定義

  連結の定義 
  要求条件
  リストL1とリストL2の連結リストL3を求めたい。

  事実条件
  リストL1とリストL2を連結するとリストL3が存在する
  リストL1が空リストならばリストL3はリストL2と同値
  リストL1が空でない場合、リストL3の先頭はリストL1の先頭と同値
  また、リストL3の尾部はリストL1尾部とリストL2の連結である

  renketu(L1,L2,L3). の関数とする。
  これをプログラム化するには?!

    renketu([],L,L).
    ・・・リストL1が空ならばリストL2とリストL3は同値
    renketu([X|L],L2,[X|L4]) :- renketu(L,L2,L4).
    ・・・結論:リストL1が空でない場合、生成されるリストL3の先頭データはリストL1の先頭データである
    ・・・条件:リストL1が空でないならば、L4はLとL2(すなわち、リストL1の尾部とリスト2)の連結リストである

    まとめると、L1が空でないならば、リストL3の先頭はL1の先頭であり(ということは(:-) )、その尾部はL1の尾部とL2の連結リストである、つーこと・・・

  ※要整理

  L1 = [a, b] L2 = [c , d] L3 = X
  で検証してみる。
  L1は空でないので、L3の先頭データはa
    次
    L4は[b|[]],[c,d]の連結リスト
    L3の先頭データはb、次は[],[c,d]
      L1が空なのでL2=L3からTail=[c,d]
  よって生成されるリストは[a,b,c,d].

イメージとしては
X + L4
・・・・X + L4
・・・・・・・・X + L4
  こんな感じか。最終的には全部まとまって


X + X + X + L4・・・なんかわかりづらいがこんなんなはず。
  L1の先頭データをひとつづつ生成リストに加えていって、L1が空になったらL2をくっつけるってかんじだな。



・追加の定義
  要求条件
  あるリストにデータを追加したい。
  今回はリストの一番前に追加するだけでよい。

  事実条件
  既存リストの先頭データは追加したデータである
  既存リストの尾部データは既存リストである

  add(X,L1,[X|L1]).
  これでおしまい。


・削除の定義
  要求条件
  リスト中に含まれるあるデータを削除したい。
  得られるリストはデータ削除が済んだりストである。
  
  事実条件
  あるデータがリスト内に存在しなければ削除できない。よって作成リスト=既存リスト。
  あるデータがリスト先頭にあるならば、生成リスト=リスト尾部。
  あるデータがリスト先頭になければ、生成リストの先頭はリストの先頭、尾部は、リスト尾部からあるデータを除いた連結リストである。

  X=あるデータ L1=とあるリスト L2=データ削除後のリストとして、
  del(X,L1,L2)のような形で求めるには?

  れっつプログラム

  リスト内の存在しない=最終的に削除対象が存在しない
  ということなので、プログラムする必要はない。

  
  あるデータがリスト先頭にあるならば、生成リスト=リスト尾部。
  ならば
  del(X,[X|Tail],Tail).
  でOK.

  あるデータがリスト先頭になければ、生成リストの先頭はリストの先頭、尾部は、リスト尾部からあるデータを除いた連結リスト
  ならば?
  del(X,[Head,Tail1],[Head,Tail2]) :- del(X,Tail1,Tail2).

  リストの先頭がXじゃないなら、生成リストの先頭はリストの先頭、尾部は・・・
  尾部は、リストの尾部からXを削除したもの。

  めだかの意味の捉え方がむずかしいなぁ・・・
  Xが先頭でないならば生成リストの先頭はリストの先頭、尾部は尾部2である
  が真であるということは
  尾部2は尾部1からXを除去したリストである
  ということ
  ・・・かな?



  ※要検証

  流れは連結のときと似てるかな?
  ヘッダが求めるデータXになるまでひとつづつ後ろにずらしてみていって、先頭がXでないならばヘッダを生成リストにプッシュ。
  先頭がXならば、そのリストの尾部を生成リストにプッシュ、かな。



・リストの置換
  要求条件
  あるリストのデータを置換したリストを求めたい

  事実条件
  あるリストが空ならば置換リストも空。
  あるリストが空でないならば、あるリストの尾部に先頭部を任意に挿入したものが置換リスト


  まず。
  リストの尾部に先頭部を任意に挿入する・・・これは仕事が違う。
  これは別として考えてみる。

  あるリストが空ならば置換リストも空。
  tikan([],[]).

  あるリストが空でないならば、あるリストの尾部に先頭部を任意に挿入したものが置換リスト
tikan([X,T1],L1) :- tikan(T1,L2) , insert(X,L2,L1).
 
  置換によって求められるリストは


  リストの尾部を置換したもの のどこかに リストの先頭をぶちこんだやつ

  です。

  つーことかー!!よくわからん。

  どうやら答えは
  tikan([],[]).
tikan([X|L],P) :- tikan(L,L1) , insert(X,L1,P).
insert(X,L1,P) :- del(X,P,L1).

  らしい。
  L1のどこかにXを挿入して作成されるP
  PからXを削除して作成されるL1
  L1+X=P
  P-X=L1
  おお、ゆにふぁい

  この事実だけで成立するってわかりづらくてしょうがねーな・・・
  で

  tikan([X|L],P) :- tikan(L,L1) , insert(X,L1,P).
  置換によって求められるPは

  リストの尾部を置換したもの に
  Xを任意にぶちこんだもの

  で
 
  insert(X,L1,P) :- del(X,P,L1).

  L1のどこかにXを挿入して作成されるP
  PからXを削除して作成されるL1


  と。

  俺は混乱した。明日・・・今日か。なんとかしよう。






  続きはウェブd(ry まとめ4で!

プロログまとめ2

2007-09-26 22:53:40 | Prologまとめ
・規則の導入

プロログでは、プログラム内の事実を用いた規則を導入することができる。

以下のようなプログラムを与える

parent(gf,f).
parent(gm,f).
parent(f,c1).
parent(m,c1).
parent(f,c2).
parent(m,c2).


この家族関係を示すプログラムに、
offspring(X,Y).

XはYの子供かどうかを示すプログラムを追加する場合。

XがYの子供であるということは、YはXの親であることと同一である。
よって書き方を変えると
parent(Y,X).

ということになる。
これはどのようなX、Yでも適合するルール(すなわち、XがYの子供=YはXの親)である。

このルールをプログラムで表現すると
offspring(X,Y) :- parent(Y,X).

というあらわし方をする。



・規則の読み方
parent(gf,f).
parent(gm,f).
parent(f,c1).
parent(m,c1).
parent(f,c2).
parent(m,c2).
offspring(X,Y) :- parent(Y,X).
というプログラムが与えられているとき、c1がfの子供であるかどうかを質問する。

offspring(c1,f).

このとき、この質問内容が真になるのは、後ろの
parent(Y,X).

が真であるときのみである。

読み方としては

parent(Y,X) が真 ならば offspring(X,Y) は真 である。
というかんじ。

後述部を条件部、前述部を結論部という。
規則で重要なのは
条件部が真ならば結論部もまた真なり、ということ。



・プログラムにおける”かつ”の導入
前回のまとめで、連関質問で”かつ”を使った。
これをプログラムにおいても私用することが可能である。

parent(gf,f).
parent(gm,f).
parent(f,c1).
parent(m,c1).
parent(f,c2).
parent(m,c2).

sex(gf,male).
sex(gm,female).
sex(f,male).
sex(m,female).
sex(c1,male).
sex(c2,female).

このような家族関係と、その性別の事実を書いたプログラムがある。
このプログラムに、父親を定義する規則を導入したい。

XがYの父親である ということは YはXの親である かつ Xは男性である

というプログラムがかければいいわけであるから

father(X,Y) :- parent(Y,X),sex(X,male).

とすればよい。
このとき”かつ”は連関質問のときと同じように","を使う。



・プロログの変数の扱い(追加)
プロログの変数のスコープは、そのプログラム内の節のみである。
どういうことかというと

red(X) :- fruit(apple).

red(X) :- salad(tomato).

のXはまったく別物であるということである。
変数はその一行の中でのみ有効である。


無名変数について
プロログには無名変数というものが存在する。
無名変数とはその名のとおり、名前のない変数である。

どういったときに使うか

Xは子供がいるか ということは Xは”誰かの”親である

というような規則を使いたいときなどがある。
条件部では、Xには誰かしら子供がいればよいわけで、いつものようにYなどの変数を用いても結果は変わらない。
しかし、このとき知りたいのは子供がいるかどうかである。
そこで無名変数を導入する。

haschild(X) :- parent(X,_).

無名変数はアンダーバーで示す。
こうすると、無名変数の部分は主力結果には表示されないようになる。




・ユニフィケーションについて
プロログにはユニフィケーションという機能がある。
ユニフィケーションとは同一などの意味を持つ。


ユニフィケーションってなにをやるの?
ユニフィケーションは、与えられた二つの情報が同値かどうかを確認するものである。

たとえば
A = xyz.

のように質問したとする。
このとき、左辺と右辺が同一となるのは、変数Aが定数xyzであったときのみである。
よって出力は
A = xyz.
yes
である。
Aがxyzであったときのみ同一(ユニファイ)ということである。


関数とユニフィケーション
関数を用いてもユニフィケーションを行うことができる。

date(2007,9,26) = date(Year,9,25).
この場合はYearが2007であったときのみユニファイである。

しかし
date(2007,9,26) = date(2007,9,27).
この場合は、左辺と右辺はどうやっても同一にはならない・・・
26も27も定数であり、変数のように代入によって同一化できないから。


変数とユニフィケーション
両辺に変数が合ってもユニファイできる。

date(9,X) = date(9,Y).
この場合、X=YかY=Xのときは同一である。
出力は
X=Y
yes
となる。両方が変数であっても同値であると判断できる。


定数とユニフィケーション
両辺が定数であった場合、両辺が同じ定数でなければユニファイできない。

2 = 4 もちろんユニファイできない
2 = 2 これならユニファイ可能


関数ユニフィケーションの条件
関数ユニフィケーションの条件として、

右辺と左辺の関数が同じ関数であること

がある。
また、
point(3,5) = point(dot(1,5),5).
はユニファイである。
すなわち
dot(1,5)
が3であればユニファイであるということ。



・トレースについて
プロログにはデバッグを助ける機能であるトレースがある。

トレースオンにするには
trace.

トレースオフにするには
notrace.

と入力すればよい


・プロログにおける再帰的プログラミング
parent(gf,f).
parent(gm,f).
parent(f,c1).
parent(m,c1).
parent(f,c2).
parent(m,c2).

このような家族関係が与えられているとき、先祖を調べるプログラムを追加したい。

XがZの先祖である ということは XはZの親である

ということがまずあげられる。しかし、先祖であるということは、その親の代の親も先祖であり、またその親の親も・・・となるのでこれだけでは不十分である。


すると
XがZの先祖である ということは XはYの親である かつ YはZの先祖である

という一文を追加すればよい。

senzo(X,Z) :- parent(X,Z).
senzo(X,Z) :- parent(X,Y) , senzo(Y,Z).

この2文で再帰的呼び出しが完成する。

手順を追ってみる。
例1
gfはfの先祖かどうかを質問する
senzo(gf,f).

プログラム内のsenzo(X,Z) :- parent(X,Z).を探索する。
するとparent(gf,f).という事実がプログラム内に存在するので、gfはfの先祖であることが真となる。

例2
gfはc2の先祖かどうか質問する
senzo(gf,c2).

プログラム内のsenzo(X,Z) :- parent(X,Z).を探索する。
しかし、parent(gf,c2)という事実がないのでひとつ戻り、
senzo(X,Z) :- parent(X,Y) , senzo(Y,Z).を参照する。

すると
parent(gf,Y)を探索し、このときのYがfであることがわかる。
Yにfが代入され、次のsenzo(Y,c2) すなわち senzo(f,c2).
を探索。
senzo(f,c2) :- parent(f,c2) の探索を行い、
事実が存在するので真を返す。
すると


senzo(X,Z) :- parent(X,Y) , senzo(Y,Z).
において、条件部がともに真を返すので真の値をとる。

ことになる。
再帰的呼び出しになっているので、先祖関係の探索をこの2行だけで行うことが可能になる。

以上

Prologまとめ1

2007-09-19 23:50:22 | Prologまとめ
プロログってなにさ・・・
一般的な言語体系とは別物の言語。論理プログラミング。
Program in Logicの略称でぷろろぐ。




プロログのプログラム(今回の範囲)
プロログはコンパイルをする必要のない言語であり、ファイルを読み込むだけで書いたプログラムを使用可能になる。


プロログの書式
関数(A,B).


プロログにおける定数と変数の扱いについて
プロログにおける定数はすべて小文字で表記する。変数の場合頭文字のみを大文字にする。


プロログにおける変数について
Cなどの変数とは違うので、変数と呼ぶのはやめたほうがいいかもしれない。
プログラム内において変数を使った場合、それは全事象をさす。
サーチするのに用いた場合、それは集合となる。





プロログのプログラミング
今回作成したのは木構造のような、関係を表すデータである。

関数名をparentとし、前には親、後には子を入力する。

父方の祖父母をGF、GM、父母をF、M、子供をC1、C2とした場合

parent(gf,f).
parent(gm,f).
parent(f,c1).
parent(f,c2).
parent(m,c1).
parent(m,c2).

というプログラムになる。
事実のみを淡々と書いているだけである。



変数を用いたプログラム
好物関数likesを作成する。
ここで条件として、この家族の全員はミカンが好きだとすると

likes(X,orange).

となる。
このXはすべての事象を指す、ことになる。





プロログの質問
プロログでは作成したプログラムに質問をする。

上記で作成したプログラムに簡単な質問をしてみる。

parent(gf,f).

このような質問をした場合、プロログは、プログラム内のサーチを行う。
このサーチは、関数名をまず探して、その後の関係が一致するものを捜索すると思われる。

この質問の答えはyesである。

parent(gf,m).

祖父母は父方であり、母の祖父母ではないので、この場合noと返事をしてくれる。





変数を使った質問
質問には変数を使うことができる。

parent(X,f).

このような質問をした場合、f、すなわち父親の親はだれですか?と質問をしていることになる。
このときの解答はgfとgmである。
複数個の解答が存在する場合、;を入力してEnterを押せば次の解答へ移る。
3回目は、存在しない解答となるのでnoが出力される。



parent(gf,X).
とした場合は、祖父の子供は誰ですか?という質問になるので、答えは父親を帰すことになる。


全称限量事実への質問について
さきほどのプログラムにおいて

likes(X,orange).

というのを書いた。
これに対して質問してみると

likes(c1,orange).
yes

likes(c2,orange).
yes

というように答えが返ってくる。

しかし

likes(ichiro,orange).
yes

この場合、イチローは書いたプログラムの中には存在しない。
しかし、likesとparentに相互関係は存在せず、

(もし相互関係が存在するならば、Xは家族関係におけるメンバーの全集合であり、イチローは存在しないことになる)

よってXはこの場合どんな名前を入力してもYesと返すのである。



逆に
likes(X,orange).

とすれば、Xはプログラム内部に存在するデータを参照するので、
この場合イチローは出てこない。

likes(gf,X).

とした場合は、likesで書かれた事実ではorangeのみがヒットするので、orangeを答えとして返してくる。






連関質問
プロログでは質問を連続して出すことができる。
書式は

関数(~),関数(~).

カンマでつなげていけばそれが連関質問となる。




連関質問の特徴
連関質問は&&である。

すなわち

質問Aかつ質問Bの答えを返す、ということになる。





連関質問における変数

連関質問でも変数を使うことができる。


parent(X,c1),parent(X,c2).

このような連関質問をした場合は

C1の親かつC2の親は誰ですか?
という意味合いとなる。


このときの答えは父親と母親、すなわちfとmが答えになる。


parent(X,c1),parent(m,X).

このような場合は
C1の親かつ、Mの子供は誰ですか?となる。

まぁ質問の内容が矛盾しているので一目瞭然だが当然答えは存在しない。







質問と複数の変数
質問には複数の変数を使うことができる。

parent(X,Y).

このような質問をした場合、その出力はすべてのパターンである。
まずXがgfであるパターンを捜索し、次はgm・・・という順番に捜索していくと思われる。



連関質問においても複数の質問が可能である。

parent(gf,X),parent(X,Y).

この質問の意味するところは

祖父の子供の子供、すなわち孫は誰ですか?という質問である。

このときXには祖父の子供、すなわち父親が入る。
そして次の質問では、Xの子供、すなわち父親の子供であるC1とC2がYにはいる。


よって答えはC1とC2が出力されるのである。





まとめ1終了