2009年2月24日 星期二

yard 的設計理念跟手法

因為有人問到,所以提一下 yard 背後的精神跟設計手法。

從最初開始

讓我們回想一下 recursive decent parser 最原始的模樣,假設我今天想要 parse 的文法是 (ab)*xyz[cd] 那我會怎麼寫我的 parser?大概是這樣
// ab
bool ab() {
char* q = p ;
// 成功
if ( *p++ == 'a' && *p++ == 'b' )
return true ;
// 失敗,roll back
else {
p = q ;
return false ;
}
}
// xyz
bool xyz() {
char* q = p ;
if ( *p++ == 'x' && *p++ == 'y' && *p++== 'z' )
return true ;
else {
p = q ;
return false ;
}
}
// (ab)*xyz[cd]
bool abab_xyz_cd() {
char* q = p ;
if ( abab() && xyz() && cd() )
return true ;
else {
p = q ;
return false ;
}
}

可以看得出來,其實這些函數的架構都非常相似,首先是保留 roll back 時需要的目前指標的位置,然後是一個一個比對吃進來的序列,最後如果失敗就進行 roll back,除了裡面用來比對所呼叫的函數不一樣,整個架構都是一樣的。

C++ template function 帶來曙光

既然這些函數架構都一樣,除了裡面呼叫的函數不一樣,那讓我們想到:C++ 的 template 剛剛好可以派上用場!我們可以寫一個 function template。
template < class F0, class F1, class F2 >
bool Seq () {
char* q = p ;
if ( F0() && F1() && F2() ) {
return true ;
}
else {
p = q ;
return false ;
}
}

於是 abab_xyz_cd() 其實可以寫成這樣…
//(ab)*xyz[cd]
bool Seq < abab, xyz, cd > () ;


預設型別引數

不過這邊有兩個問題要解決,一個是小問題,另外一個比較麻煩,小的那個問題是:如果我只想傳入兩個參數怎麼辦?好在 C++ 的 template 支援了預設參數的功能!我們可以設計一個函數永遠傳回 true
bool True () { return true ; }

然後把我們的 Seq 改寫成
template < class F0, class F1=True, class F2=True >
bool Seq () {
........
}

事情輕輕鬆鬆就解決了!注意一下第一個參數沒有預設值,因為當你說你要一個 "Seq" 的時候,想當然你不會什麼東西都不給他就叫他去比對吧。當然如果你想要實現一個不吃東西的 rule,那是另外一回事,這邊不多說,可以自己看看 yard 的 source 是怎麼做的 :)

用 class template 封裝跟命名新規則

另外一個問題比較麻煩,讓我們回頭看一下剛剛新寫好的那個規則…
//(ab)*xyz[cd]
bool Seq < abab, xyz, cd > () ;

其實這東西編譯根本不會過,他看起來像是一個特化函數,但是語法也不對。而且他沒有名字,你沒辦法重複使用這個新定義出來的函數,沒有人會希望每次用到這個規則的時候都要重複打上整串東西。

聰明的人馬上就想到:我可以用 function pointer 阿!
bool (*abab_xyz_cd)() = Seq < abab, xyz, cd > ;

媽阿,這鬼東西編譯會過嗎?會。不過事情沒這麼美好,當你想要
//(ab)*xyz[cd]gg
bool (*abab_xyz_cd_gg)() = Seq < abab_xyz_cd, gg > ;

的時候你就 gg 了。編譯器會跟你靠北一個你看不懂的錯誤訊息,不用看懂沒關係,簡單的原因就是因為這時候 abab_xyz_cd 不是一個型別也不是函數,而是一個變數,函數指標不是函數,是變數,而你不能把變數塞到 template 裡面當作參數,於是你現在有辦法定義一個函數,但是你辦法復用他,等於還是沒用。

解決的方法是把這些函數 rule 用 class 包起來。
template < class F0, class F1, class F2 >
class Seq {
bool match() {
char* q = p ;
if (F0.match()&&F1.match()&&F2.match()) {
return true ;
}
else {
p = q ;
return false ;
}
}
}

然後當你要定義新規則的時候,定一個 class,繼承那些泛型的 rule,
class abab_xyz_cd
: Seq < abab, xyz, cd >
{} ;

現在一切都解決了,這些 rule 有名字,也可以被復用!而且改寫成 class 還有另外一個好處:函數指標不能被 inline,但是 funtor 可以!雖然我們取的名字不是 operator()(),但是效果一樣,這對執行效能有很大的提昇。

最後來一點小修飾

我們很接近最後的完成品了,只剩下一點點小問題,就是我們的 p 是個全域變數,我們可以設計一個 ParseState class 把目前處理到的位置跟本文封裝起來,ParseState 的細節就不提了,我們直接看改好的 Seq 是什麼樣子……
template < class F0, class F1, class F2 >
class Seq {
bool match(ParseState& p) {
ParseState::Iter q = p.pos() ;
if (F0.match(p)&&F1.match(p)&&F2.match(p)) {
return true ;
}
else {
p.setPos(q) ;
return false ;
}
}
}

終於大功告成啦!這個是用來 match 序列的 class template,只要明白設計理念以後,其實勝下的像是 Or, Star, Plus 或是 Repeat 都很簡單了,

阿上次不是說要講 AST?嗯……下次吧,我是個沒信用的人 XD 最近先翻 C++0x rvalue reference 的文章,我覺得這比較有趣 XD

yard parser framework

Yet Another Recursive Descent (YARD) parsing framework for C++

網站 http://code.google.com/p/yardparser/

網站上面沒有什麼教學,只有下載,然後抓下來的東西裡面有 demo 程式,因為本身非常簡單,所以大致上是看了就懂,但是我還是想寫一篇教學,這樣大家可以減少一點摸索的時間。

這篇文章會先介紹 yard 跟其他 parsing gramework 的比較,然後我會從非常簡單的範例開始出發,一直到最後給一個很難的範例,讓你們熟悉如何使用 yard 建立自己的 grammar。在學會了如何使用 yard 建立自己的 grammar 之後,我會示範如何使用 yard 來自動建立 abstract syntax tree (AST),並且把 yard 使用在自己的程式裡面。

跟 boost::spirit 的比較

yard 跟 boost::spirit 一樣的地方是他們的 grammar 都不限於 LR(1),可以寫 EBNF 的 parsing rule,語法好寫好讀。boost::spirit 強勢的地方在於支援 dynamic parsing,也就是 parsing rule 可以在 runtime 動態改變。

boost::spirit 最大的弱點在於編譯效能,boost::spirit 很難用來開發大型的 parser,當你的 parsing rule 到了 30~40 以後,編譯時間就快要一個小時,一個 78 parsing rule 的 grammar,編譯要兩個小時。

執行效能也是 boost::spirit 的一個問題,每個 parsing rule 被引用的時候,都涉及一次 virtual function 的呼叫。相較於此,yard 的編譯速度非常快速!編譯完整的 c 語言語法 + XML 語法 + scheme 語法,全部加起來不用一秒。

跟 yacc 的比較

沒什麼好比的 -________-|| yacc 再見再見

簡單教學範例

好,在使用 yard 的時候,我們都要 include ,如果你要 parse 一般簡單的文字的話,順便 include ,然後為了方便,就 using namespace 吧!所以你開發的每個 grammar 原始碼架構大概是這樣的。
// == my_grammar.hpp ==
#include <yard.hpp>
#include <yard_text_grammar.hpp>

namespace my_grammar {
using namespace yard ;
using namespace yard::text_grammar ;
/*...[[[ 這邊就是我們要寫自己的 grammar 的地方 ]]]...
}

那這篇文章之後的範例就不寫這部份了,只著重在 grammar 的地方。

yard 的設計是建立在 C++ 強大的 template 機制上面,每一個 parsing rule 就是一個 struct,藉由組合不同的 struct 來完成複雜的 grammar。

先來一個最簡單的例子
// AB
struct AB
: CharSeq < 'A', 'B' >
{} ;

這樣就完成一個可以用來 parse "AB" 這個字串的 rule 了,CharSeq 是 yard 裡面已經定義好的 struct,會從來源讀入一個一個字元來進行 match 的動作。實做細節其實很不難,但是很有創意!有興趣的去看翻一下原始碼就知道。

再來一個稍微難一點的
// (AB)*
struct ABAB
: Star < AB > // 這邊 AB 當然是接續前面的範例
{}

不用說,Star 也是 yard 裡面已經定義好的一個 struct,可以 match 零到無限多個你放在 < > 裡面當作 template 參數的規則。

馬上應用剛剛學到的兩個…
// ABC(AB)*
struct ABC_ABAB
: Seq <
CharSeq < 'A', 'B', 'C' >,
ABAB
>
{} ;

Seq 也是 yard 已經有的 struct,可以用來 match 一串序列的 rule,他跟 CharSeq 一樣都可以接不同數量的 template 參數,但是也不是沒有上限,他內部設計是 10 還是 16 我忘記了,你可以自己改,但是最後的限制會取決於你的編譯器所支援的上限。

有的時候你會想 match 多種可能的其中一種
// (AB|XYZ)
struct AB_or_XYZ
: Or <
AB,
CharSeq < 'X', 'Y', 'Z' >,
>
{} ;

當你用 Or 的時候,你就可以只 match 其中一種 rule,注意一下,當某個順序在前面的 rule match 成功的時候,match 就結束,這跟一般我們 C/C++ 預設的 operator || 行為一樣,因為 Or 底層就是這樣實做的。
所以注意下面這個例子
Or<CharSeq<'A','B'>, CharSeq<'A'>> //   match   "A"
Or<CharSeq<'A','B'>, CharSeq<'A'>> // match "AB"

Or<CharSeq<'A'>, CharSeq<'A','B'>> // match "A"
Or<CharSeq<'A'>, CharSeq<'A','B'>> // not match "AB"

因為當 rule 看到第一個 'A' 的時候,rule 會把這個 'A' 消耗掉,剩下一個 'B',但是你的 grammar 已經結束了,所以 parsing 失敗。

最後一個整合的範例

上面的例子為了示範,都非常簡單,但是你其實可以用 yard 直接建立非常複雜的 rule,例如:
// (+|-)?[0-9]\+(\.[0-9]\*)?    就是一般的浮點數啦
struct number
: Seq <
// (+\-)?
Opt<Or<Char<'+'>,Char<'-'>>>,
// [0-9]+
Plus<Digit>,
// (.[0-9]*)?
Opt<Seq<Char<'.'>,Star<Digit>>>
>
{} ;

最後總結一下:

yard 讓你可以用高階的語法寫成 parsing rule,這點跟 boost::spirit 一樣,平心而論,template 寫起來比起 boost::spirit 的 operator overloading 是稍微麻煩了一點,但是 boost::spirit 的編譯時間實在讓人不敢恭維。

yard 本質上是一個 recursive descent parser generator,執行速度非常快,他跟你用手寫出來的 recursive descent parser 一樣好,如果你要處理的東西不需要 dynamic parsing,那 yard 會是你的第一選擇。

yard 跟 boost::spirit 一樣,支援自動的 abstract syntax tree (AST) 生成,我很想繼續寫下去,但是剛剛右下角跟我說活屍日記完檔了,所以 AST 跟怎麼在自己的程式當中使用 yard 就下次再說,先這樣囉掰。

2008年6月19日 星期四

撿到虎斑鸚鵡一隻

昨天十八號,早上從宿舍下來的時候,走到水木前面,聽到很好聽的鳥叫聲,想說那就呆一下聽一聽,結果突然本來應該在前方高處的鳥叫聲,突然從旁邊傳出來,就覺得很奇怪,眼睛飄過去,看到地上有一隻鳥。

一隻看起來像是鸚鵡的東西,坐在地上,距離我大概兩公尺的地方。

再看一次,天哪!還真的就是一隻鸚鵡!我沒看錯!好!靠近看看……疑,不會飛走耶,這種東西應該沒有野生的吧,而且好像也不太怕人,想說過去直接抓應該會嚇到他抓不到,脫了外套從後面慢慢靠近,用蓋的,抓到了!好!給詩芳!哈哈哈!她一定很開心!

就帶著去餐廳買早餐啦,他從外套裡面鑽出來,冒出一個小小的腦袋,東看西看,結果輪到我點餐的時候,掙脫出來,飛走了 -_____- 天哪~~~馬上追殺過去!追到飲料部那邊,結果不見了,嗚嗚~就這樣不見了,我本來要送給詩芳的驚喜,就這樣不見了,天哪!你知道要撿到一隻鳥送給詩芳是多困難的事情嗎!怎麼會就這樣不見了!我在那邊鑽來鑽去找來找去就是找不到阿,飲料部的人正在忙,但是也有幫我找一下,但是就找不到阿,我明明就看到他飛到冰箱這邊阿,旁邊掃地的北北說從門口飛出去了,可是沒有阿,我就看到他飛過來。趴在地上找阿找,但是就沒看到,在飲料部的冰箱後面找阿找,但是就沒看到,但是就不時有聽到鳥叫聲,啾的一聲,然後又沒了,可惡!明明就有聽到聲音阿,但是為什麼看不到人呢?因為有聽到聲音,所以就繼續找,但是一直找阿找阿,後來發現啾的聲音好像是往來的人走路的時候鞋底跟地板摩擦發出來的,突然好難過喔,因為鳥就不見了。真的很想要放棄了,準備要走的時候,都已經轉身了,想說:可惡,再一下下就好!就眼睛東看西看,然後突然聽到「啾!」然後看到一隻鳥在飛,大家都喊「在那邊!在那邊!」就看到他飛去撞玻璃,然後掉在玻璃跟桌子中間的縫,趕快跑去看,看到他在縫裡面,呼呼~這個縫他自己是絕對上不來的,我來救你!你運氣真好阿,遇到我~

抓起來,抓在手裡面,怕他痛,不敢抓太用力,但是在手裡面就可以看到他的樣貌,是很嘴巴有受傷喔,有裂痕,看起來很恐怖,好像隨時都快要斷掉那樣,看看羽毛,是全身都長了,但是感覺是小孩子的羽毛,因為就還不光順,鬚鬚的那種感覺,而且也可以看到一些沒長好的羽管。握在手裡,一直掙扎,叫得很可憐,嘎嘎嘎嘎的那種很難聽的叫聲,跟我剛剛發現他的時候的叫聲很不一樣,然後他一直咬我的手,雖然說不是很痛啦,但是咬久了還真是有一點點痛,然後呢,他就一直咬一直咬,他真的很害怕,咬一咬又會哭叫,但是沒辦法喔,對不起,不敢用外套包你了,雖然外套比較舒服,可是很怕你又飛走,下次我可不一定還能抓回來。一直咬我。

重新排隊買早餐的時候,一直仔細端詳你,覺得很奇怪,想不透為什麼一隻虎皮鸚鵡會在水木前面的柏油路旁邊,到底是從哪裡飛來的?理解不能阿,只能猜說本來是學校的人養的,但是不小心讓你飛掉了吧(講到這邊,再去PO版一次好了)?一直咬我。好不容易買到早餐了,去到研究室的途中也一直咬我,一直咬我,真的很怕讓你飛走,所以只好抓的稍微緊一點,歹勢阿,你多擔待,好不容易到了研究室,看到怡亭跟詩芳在喔,跟平常一樣的把書包放好,早餐放好,然後把手伸到詩芳面前:「這個給你」

「ㄟㄟㄟㄟㄟ!?!?!?!?哪來的!!?」
「水木前面撿到的 = =」
「怎麼會給你撿到?」
「阿就撿到。」

詩芳還真的蠻開心的,我就想說送這個鳥給她,她一定很開心,她最喜歡拯救落難的小鳥了,剛好這邊就有一隻落難的小鳥,林詩芳很開心的說要去買籠子跟飼料啦,所以我們就出發去買籠子跟飼料啦,但是在那之前,先去網路上po了鸚鵡招領文,然後跑去賣啦,林詩芳說她沒帶錢啦,我說我先借她,但是阿,就騎車去的過程當中阿,就沒想要跟她拿錢了,因為覺得這個鳥是我撿回來的阿,這樣就丟給詩芳感覺好不負責任喔,應該還是要自己照顧吧。很開心的買了五十塊錢的飼料,還有兩百五十塊錢的籠子,就回家了。附帶一提,有看到小白很想要的金太陽喔,一隻八千,真是高級鳥。

回家看到怡亭正在跟紙箱裡面的小鳥很開心的玩樂,說小鳥站在她手上不肯下來。我們把小鳥移到新家裡面,附上食物,他咬了兩口,就休息了,發呆。休息。睡覺。

然後又過了十分鐘左右吧,開始吃,這一吃就真的厲害了,從中午十二點左右一直吃到下午四點,幾乎都沒有停過,一直吃一直吃,我機係郎沒有見過鳥這麼會吃的,一直吃一直吃,吃到天荒地老海枯石爛去了,中間除了休息幾次的幾分鐘以外,全都在吃,太可怕了!怡亭給我們看了他剛剛在理毛的錄影,還真的蠻可愛的,羽毛張開的時候才發現他其實還蠻漂亮的。

到了晚上,本來我想要把他放在研究室的,因為不想一直搬動他,但是怡亭說怕他冷到或是悶到,所以就把他帶回家啦,後來還蠻後悔的啦,覺得不應該搬動的,因為他本來在研究室呆到晚上好不容易比較不緊張的感覺,結果帶到宿舍又很緊張啦,然後第二天又帶回研究室,又讓他緊張一次,這樣真的不太好,所以就決定一直讓他待在研究室了。好!

今天想要去買新的飼料(就是奎瓜子阿,鸚鵡很喜歡的)還有布,要作成罩子可以讓他比較安心,先去了動物王國,結果只有超大包奎瓜子,而且是給老鼠吃的,不知道能不能給鳥吃,所以又去了昨天買飼料的地方,然後問了老闆,老闆說不要布,就用紙箱就好了,然後說中型鸚鵡才有吃奎瓜子,所以我們只有另外買了詩芳說鸚鵡很喜歡的帶殼飼料,很開心的回來了。鳥吃這個很厲害,一下就可以剝殼,太強大了!

鳥還是很怕人耶... so sad... 希望他早日不怕我...

2008年4月20日 星期日

小強學程式設計

一個開心的事情,記一下。

以前在魔力認識的小強,認識他的時候他還是國小,那個時候大家都知道我寫程式,小強有一天跟我說他想要學程式,我開了一本書給他,他也真的去找了書來看,不過找書的過程非常的辛苦就是,就是他住的地方不知道是太偏僻還是怎樣的,像是金石堂那種書店是完全沒有,他必須先訂書,而且能買到的書還很有限,最後他終於買到一本 C++ 的書了(C++ 其實不適合初學者寫,但是沒辦法,這個語言我最熟,也是我唯一敢「教人」的語言,如果他在學習的過程上出現問題,那我一定可以解決),但是不是我開的那本,一開始我是沒有很開心,因為覺得一本好書對初學者來說很重要,要是選到不好的書,真的會差很多,但是現在比較能理解他那個時候其實也才多小,買不到書也很正常。

他也就開始看了,他學習的過程可以說是蠻辛苦的。

有的時候會在 MSN 問我問題,其實有的時候我正在忙,或是我可能心情不太好,不是很想回應,也有的時候我覺得他怎麼一個簡單的迴圈都要弄好久,就不是很開心,但是我還是耐著性子講完,很多時候我覺得這些東西照道理說書上會講的很清楚,我不懂為什麼有看書了還會問這些問題,或是不太理解為什麼學習的進度這麼慢。當然現在是知道他的課業真的很忙,沒有什麼時間再去學課外的東西。日子慢慢過去,其實我也忘記我教過他幾次了,我只是希望他趕快把基本的語法摸熟,然後體會用自己的程式去解決問題的感覺,並沒有想很遠說他以後會把程式寫的很好怎樣的。

小強前兩天丟我,跟我說他去參加了學校的程式設計初選。

哇!他現在已經是高中生了耶,而且還會去參加程式設計賽!當然題目都是不難的三秒題,但是會去參加程式設計比賽就是對程式有愛啦~聽到這件事情,其實就可以知道他以後有很大機會會把程式寫的很好,因為對程式的愛是把程式寫好的第一條件喔 ^^。看到他會去參加比賽,我就突然整個熱血都來了說,很想盡量教他我會的東西,我覺得只要稍微訓練一下,他就可以很輕鬆的在區域賽拿到名次,然後就可以參加全國比賽,這對保送是很有幫助的。唉,高中的時候沒有去參加程式設計比賽可是我很大的遺憾呢,難得小強有這個機會哩。話說小強給了我一個網址,說是他們老師在 google 論壇開的一個討論區(他有一個好老師),我也去申請加入了,可以的話想要盡量幫助小強,讓他能多從我這邊拿到一些東西。

好,重點,重點就是,我真的很感動,就是密寶說得那種「改變一個人的人生」的感覺,沒想到我也能改變別人的人生 ^^,雖然說還不一定啦,但是我覺得機會很大喔,希望小強以後也變成高手 ^^

2008年4月16日 星期三

語言分化,種族優越,利他

關於論文的東西,又有一線曙光了。

之前花了些時間,但是卻沒有抓到那個點,我一直不太清楚我的問題的關鍵點在於哪裡,雖然我知道應該有一個「動力」在促使語言分化,但是我一直去想的,都是「保持距離」這件事情,而不是「增加距離」這件事,但是我之前並沒有很清楚的區別這兩點,感覺上我就是一直搞錯點。上次中鎮來了,跟他聊過以後,他幫我點出這個地方,我覺得這是一個重要的事情,不過糟糕的是,在把問題釐清楚之後,真正的困難來了,就是我發現我對於這個分化的力量的來源,完全沒有想法,我不知道他是哪裡來的,不知道為什麼語言能夠這樣分化開來。我會這樣想:如果一個社會好好的,那他根本就沒有必要分化阿,為什麼語言會分開呢?沒有道理阿……

雖然 inspire 我的是 Axelrod 那篇關於種族優越的論文,但是其實昨才是第一次認真看完他,只能說有看有差,人真的要多唸書。我一邊看,一邊思考,仔細的在想這個過程當中本質上影響互助的關鍵在哪裡,但是更好玩的,剛我看到關於實驗結果的地方,他拿實驗結果來跟「完全沒有種族差別」的群體作比較,完全沒有種族差別的實驗其實結果很明顯,在 one-shoot prisoner's dilemma 裡面所有的人都會偏向背叛對方,也就是大家都是極度自私的人,這其實是很直覺的事情,但是讓我自己意外的是,我沒想到「多一個 marker」就會有這麼大的改變,就是說「有標籤」,竟然就是會比「沒標籤」的群體還要過的更好,顯然這個標籤給他們「有機會去對某些人好」而且這個對別人好的行為,是可以獲得回報的。這蠻神的,當然我也想過背後的原因,很明顯的,這個要成立,必須要有「區域性」這個要素來支援,不然是不可能演化出這種結果的。好,等等,這邊我要跟自己補充一下,如果是 iterated prisoner's dillema 的話,那其實不把 agnet 放到 2-D lattice 上面(沒有考慮空間的連續性)也沒有關係,一樣可以演化出利他行為。Axelrod 這個模擬的過程,其實很類似古早孫春在上課講到的東西(很感謝孫春在老師阿,上課講到的東西就是這邊的關鍵,不然我自己想不知道要想多久)也就是聖人跟聖徒的關係。聖人(利他者)在充滿壞人的環境下,其實是無法生存的,因為他肯定會被壞人吃得屍骨無存,但是當聖人被聖徒(選擇性利他主義者)所包圍保護起來的時候,其實就可以生存,因為聖徒對聖人來說,也是聖人,但是聖徒對壞人來說,就是壞人,這會形成一個保護層,把聖人跟壞人隔絕開來。上面講的這個,不管在 2-D lattice 的 iterated prisoner's dilemma 或是在種族優越意識模型裡面,都是共通的(果然學問到最後都是一樣阿~)。

好,現在我們知道「有區別」是一個可以形成「利他」的條件,因為選擇性利他主義者可以當作無條件利他主義者跟自私者的緩衝區,那麼,加上 game theory 的設定,只要我讓「利他」可以提高一個遊戲平均的生存優勢(講白話就是讓一個個體利他的時候,付出的成本低過被幫助者所獲得的好處,也就是設計一個「正和」遊戲),這樣我就可以演化出利他行為啦~

不過這只是其中一塊石頭,不是我的論文,我現在要想辦法基於這點上面,去演化我的群體,讓他們會「傾向去區分彼此」,如果我能做到這件事情,然後我再設定我的模型是以「語言」來當作區分彼此的的標籤,這樣他們就會傾向去讓彼此的語言有區隔,這個也就是我語言分化的動力來源了!不過我不是很確定我能不能設計出能演化出這樣結果的模型。這邊 note 一下想到的應該要具有的點:要做到的幾個點,首先,我的 agents 要放在 2-D lattice 上面,然後他們要具有區分對方語言是不是跟自己一樣(或是很類似,唷,這邊我可以用相似的程度來決定 agent 是不是要合作的機率?阿!不對!也可能對?我這邊要怎麼設計 encoding?)的能力,然後在區分的過程當中,這邊我要怎麼設計這些 agent 的顏色跟機制阿?顏色是要可以改變的嗎?有限的顏色還是無限的顏色?是可以後天學習的?還是先天決定,但是策略是可以變的?(策略不用可以變吧,因為策略不好的自然會死)這樣設計真的可以引導出最後大家都偏向「有差異」嗎?這邊講的真的好模糊喔,什麼叫做有差異阿?是「喜歡有差異」?還是有差異?我想應該是要「喜歡有差異」這樣才能把一個語言一分為二?這樣的話,我的 encoding 就要包含「喜歡有差異」跟「不喜歡有差異」兩種情形的可能性。這個 OK。可是這邊我還不是很清楚,怎樣的基因叫做「喜歡有差異」,恩,果然這個機制的設計還是問題,希望能想好這個點,這個應該就是目前最需要突破的關鍵吧。這邊又想到,如果 agents 都喜歡有差異,那會不會導致最後演化的結果是整個語言幾乎是完全散亂的?應該不會吧,但是也有可能,我不是很確定,我希望這個點可以在 agent 喜歡跟相似的人合作然後得到好處的這個現象底下被消除掉,會不會這麼順利?

假設以上都很順利好了,但是還有一個更麻煩的地方,那就是我要怎麼做出語言的分化樹?好像沒有辦法,目前看起來,即使以上一切順利,我也只能驅使語言分化,但是這跟要建出「語言分化樹」還真的是差蠻遠的,唉唉,傷腦筋,還是要把題目定小一點呢?定成「語言分化有助於群體生存」好了?這樣還可以間接跟 natural 那篇關於語言分化樹的 paper 佐證,但是就不像一開始計畫的是什麼直接的關係了……

2008年4月15日 星期二

Learning and Planning

最近繼續想到關於 learning 跟 planning 的差異(跟結合?)我想明白這兩個的「差異」到底在哪裡?因為這影響到我為什麼要採取 learning 或是 planning,而我認為這是釐清 learning 本質的關鍵,也就是說我應該什麼時後來用 learning,怎麼用 learning,learning 又能幫我做到什麼?

我在想,人類遇到問題的時候,到底都是怎麼解決的?雖然直覺上 learning 可以解決所有的問題,不過事實上人類的確是有使用 planning 在解決問題的,那哪些時候是人類會使用 planning 呢?我目前能想到的,是從我對 learning 的理解開始出發,learning 沒辦法做到太長遠的預測,應該說,今天根據 learning 來作決策的話,大部分所做出的決策,其實都只有考慮到很短暫的未來。有的狀況,只看但短暫未來是不足夠的,也許這種時候就需要 planning,但是話說回來了,事實上 learning 也可以解決需要長遠預測的問題,只是就是需要非常豐富的經驗,一點一點的在學習的過程當中,倒推回來,然後來決定現在的策略。

想到這邊,那我就很好奇,說到底,什麼問題都可以用 learning 解決,那 planning 要幹嘛?完全不用了?可是不對阿,因為我們真的有在用到 planning,邱中說:「人類的 learning 是用來累積 planning 所需要的資料庫。」我想這個說法差不多了,只是還有一些點沒點清楚,「既然 learning 就可以解決問題,我們又何必用 learning 來累積 planning 所需要的資料?我們根本不必用到 planning 阿~」我能想到的是:「有的時候,我們已經面對一個問題了,但是我還沒學過這個問題應該怎麼解決,也就是說,其實我還沒學到從目前的狀態怎麼到達目標的的那條 path,就是說我還沒有走過那條 path,所以我還不知道目前要做什麼」,像這種時候,大概我們就會開始進行 planning 的動作,嘗試著把中間這些我們不曾經歷過(或經歷不夠)的狀態給補齊。

我想到,當我們在進行 planning 的過程,每次我們走到一個新狀態,我們在思考下一步的動作的時候,其實也是評估各個可能性,然後選出比較好的解,不過我們怎麼知道哪些動作比較好?我們不知道,我們進行更深一層的搜索,一直重複這個過程,直到我們發現某個動作可以帶領我們到達某個我們熟悉的狀態,然後我們知道那個狀態是好的,這個時候我就會 back trace 回去,幫我這一連串的狀態都加分。

講到這裡,那其實跟 learning 的過程根本就很類似嘛,只是這一連串的動作是在「腦中」虛擬的,模擬的進行。好,也就是說,learning 跟 planning 的差異是,今天我就要解決一個問題了,但是我還沒學過這個問題要怎麼解決,那我就在腦中模擬這個過程,模擬這個「學習的過程」,想到這裡我還蠻怕自己想錯的,因為我竟然認為 planning 跟 learning 本質上是一樣的東西,只是一個沒有真的去作,這跟我以前的想法還差蠻多的,不過我也很開心自己會有新的想法。
先不管對錯吧,讓我繼續往下想。

如果我想到這邊是對的,那 planning 的好處之一,就是你不用付出真正執行動作所需的代價,以我經濟學那部份的腦袋來舉例的話:一個投入經濟市場的人,在經過了大量的經驗以後,他會學到一些策略,然後會賺到很多錢。不過這樣做的缺點就是,你要投入市場,然後用錯誤嘗試的方法來學到經驗,這個過程非常的昂貴,因為你必須「真正的在市場當中採取那些可能會讓你賠錢的行為」,好,那如果一個人對市場,或是說對某個遊戲有基本的認識,可以在腦中模擬(進行推導以預測)所採取的動作對市場的影響,以及市場未來的走向的話,那麼他就不必真的付出這個成本,而可以擁有好的策略,只要他「在腦中學習」就可以了。

那人是不是一直都在學習?我的意思是說,當我們在做 planning 的時候,其實我們也是在學習嘛,但是 planning 似乎是針對某個特定問題的?嘗試往那邊前進的,learning 不一定有什麼 goal,只是想要找到在所有狀態下的最好的策略,這邊 inspire 我一點東西,就是 planning 找到的是不是最好的解?阿,這個先不管,我先寫下之前想到的,關於 learning 是用來解決具有 uncertainty,因為 planning 沒辦法解決這個問題,不過後來我發現這個想法不是完全正確,因為事實上人類也在用 planning 解決很多具有 uncertainty 的問題。我修正過的想法是,當 uncertainty 比較高的時候,learning 就比 planning 更適用,但是後來發現還是不太對,有的時候我們就是需要解決問題,而這個問題可能是有高度隨機性的,但是我們依然可以找出「比較」好的策略不是嗎?頂多就是在這個 planning 的過程當中,我們用了更多的成本去作更多可能的分支的搜索跟評估。這邊 note 一下我的點在於「planning 也可以解決具有不確定性的問題,所以 learning 跟 planning 的關鍵差異不在這邊」好,回到剛剛說的 planning 不一定找到最好解,可能只是足夠好的,其實我真正想要講的是「當我們時間很多的時候,我們總可以用 learning 找到最佳解」。ㄟ,不過這好像也不是完全正確,應該說,如果我用 learning,那我可以用很多時間去把每一個狀態都求好,但是用到 planning 的時機,就是我現在就要解決一個特別的問題,我沒這麼多時間可以去算了,我要「攻克」這個問題,我要攻擊這個點!好!就是剛剛冒出來的新想法,寫這麼多就是希望把自己的思緒過程保留下來,我剛剛想到的新想法是:「planning 的重點在於,我要在有限的時間(僅能付出有限的成本)之內,要解決這個問題,那我就要在短短的時間之內,學習(現實或是模擬)怎麼解決這個問題。也就是,接下來我要探索的,我要評估的狀態,要盡可能的落在我目前的狀態跟我的目標之間,如果我能夠趕快找到一條 path(或是在具有不確定性狀態空間裡面的某一片具有足夠高的 accessibility 的區域)連通我目前的狀態跟我的目標,那我這個 planning 就完成了!」

恩,所以我的系統應該是這樣運作:當我沒有特定目標(或是目標緊急性不高)的時候,我的系統會進行類似隨機的嘗試,過著很正常的生活,不會刻意要求出某些特定狀態跟動作的分數,但是當系統遇到一個就要解決的問題,系統就會嘗試著把心思放在那些比較有可能是答案 path 的狀態上,嘗試把這些 path 的值都補滿(做出足夠好的 evaluate)。

好,我現在釐清 learning 跟 planning 的差異了,那你前面說想弄清楚 leaning 能做什麼,你現在有什麼想法了嗎?我想一想……想到的是任何時候其實都在作 learning,而當遇到需要 planning 的時候,我們就把資源集中到那些特定的狀態上面去作 learning,找出 plan。等等,這樣其實也可以反過來說,怎麼說?也就是說,其實 learning 也可以被看作是「其實我們可以隨時隨地的在做 planning,然後一直把 plan library 存起來,存放在對應的 state 上面。只是當沒有急迫任務的時候,我們隨便找任務來解,當有特殊任務的時候,我們就專心解那個特殊任務。」

OK,那 learning 在這邊有什麼優勢嗎?特別以 reinforcement learning 來講(其實前面講的 learning 也都是講 reinforcement learning 而不是 NN 那種 classify 的問題)最大的好處就是處理不確定性,不過這樣的話,其實 planning 領域應該也有在不確定環境當中進行 planning 的研究,雖然我對 planning 不熟,不過我想應該是有的,所以說學問到最後都是互通的?我覺得好像 reinforcement learning 對於問題的泛用性比較好?我不確定,也許我應該以第一種想法為主,也就是以 reinforcement learning 為主要 paradigm ,然後當遇到問題的時候專注起來解決問題。

這邊想到兩件事寫下來,因為我快睡著了,寫下來免得自己忘記,一個是「如果是第一種 paradigm 的話,那當我遇到問題的時候,我要怎麼去鎖定我該把心思放在哪?我的意思是說,我怎麼去辨識哪些狀態比較可能在我要解決的問題的 path 上面?」初步想到的是把狀態向量拿來當作距離值,然後選一些距離目前狀態跟目標狀態比較近的狀態來評估。另一個問題是「怎麼學會更快?(還真是大哉問XD)」特別想到的是 transfer learning,因為之前接觸到的都是這些,所以想到的也是這些(不過我心中隱隱有個想法是「答案在 approximate reinforcement learning 上面」但是怎麼做到這件事情,目前還是完全沒有想法,因為最直覺的模型好像就是 SLP 或是 MLP,但是這兩個東西都已經被顯示不是很好……)

慢慢想……

好,睡覺,明天早上找要給小帥看的東西……

2008年3月4日 星期二

大家的研究

碩二的大家也都開始注意到碩士論文這回事了,怡亭是老早就打理好了,詩芳是一直累積著過去的東西,現在也是很紮實的就可以完成,她們兩個是最不用人擔心的了。信捷那邊雖然不常接觸,但是我想應該也是沒有問題。

現在還不確定的就是我(雖然我覺得自己應該沒問題),毛毛,還有阿達。

過了一個年,終於還是決定放掉老師建議的關於使用 reinforcement learning 來作 natural language parser 的方向,回到 language 的 social simulation 這一塊。感謝建勳給予的書單(也很對不起他關於我在 Google Android 臨陣脫逃的事情),《隱藏的邏輯》給了我很多幫助。我覺得 Social simulation 是真的很有趣,每次在看這些東西的時候,總會有「哇!真是好有創意又有趣的想法!」但是在想了自己的東西以後,我內心也有種感覺是「這種東西真的會有什麼價值嗎?」我不知道,中鎮給我的感覺是他覺得這東西沒什麼價值。說我完全不會被影響是假的,沒有受到肯定是多少都會有失望的感覺。禮拜一跟老師討論過了以後,老師似乎是同意我可以往這邊做了,但是真正困難的不是說我提的東西老師認可不認可,而是我不知道怎麼跟老師說我不打算繼續往 parser 那邊作,因為老師感覺對這個很有興趣,讓他失望我也很悲傷,心裡想著:「我有空的話就兩個都做起來!這樣老師就會開心」但是想是這樣想,但是我也明白自己的個性總是實踐力很弱,每次當我這樣想,我是想真的,但是最後都變成嘴泡,唉。所以還是不要亂說這種事情,有作才是有。老師也給了我模型上的修改方向,雖然不多,但是是關鍵的部份,重點是在辨別語言的分化樹上面,必須想出一個好方法,也許是用地理距離,或是用人工強制隔離,我覺得後者比較可行,也比較明確。

毛毛的話,跑去跟向原做事了,這是令人悲哀的,對向原來說,是悲哀的。

阿達的話,要作六子棋,坦白說,以目前的狀況來看,我覺得他完了,跟老師報的東西完全顯示了他對於研究方向在基礎知識上的不足。我真的很矛盾,說我對他完全沒有負面情緒,我想那是假的,但是說我不想幫他,那也是假的,也許不是每個人都是有善惡兩面同時存在,但是我是有這樣的狀況,說是偽善也好,就像哪裡看到的一句話:「貫徹到底的偽善,也是一種善良吧。」要是他不能順利畢業,也許我內心會一種「哈哈!報應!死好!」的想法,但是我還是希望大家都能順利度過。最快樂的時候,就是碩一暑假那個時候,我們會一起討論東西,他會問我程式,我還會教他東西,大家一起努力的時候,我喜歡那種感覺,就像是現在小帥他們那樣。慢慢變成現在這樣的過程,我都記得,老實說我覺得阿達是白痴,會弄到這樣都是他的智能不足以及幼稚,人都會犯錯,但是不知檢討硬把錯誤推給別人來合理化連自己都知道自己是錯誤的行為,才是真的愚蠢。照道理說,他不能順利畢業,我會開心,但是他要是能順利畢業,我也會開心。我有是總會想到他突然跳出牛角尖,然後跟我道歉了,我知道現實上不可能,但是有時候做夢會夢到,夢到我們會講話,感情不錯,但是做夢只是做夢。

對於書欣、世龍、小帥、阿坤他們,我是內疚的,也許我個性對他們來說還 OK,或是因為我是學長,他們對於我的無能跟不負責任也就沒多苛責,但是過去一年,我對他們的幫助是幾乎沒有的,我過去內心也知道這件事情,但是在現在,我才有比較深刻的體會到這件事情,良心的譴責也越來越大,我還有五個月,我能給他們什麼?我自己在未來的五個月,我能不能順利的把論文完成?我有沒有多餘的時間給他們什麼幫助?我不知道,我不敢說,因為我總是說了卻作不到,一切還是要去作,不管我自己怎麼跟自己說,都是沒用的,就是要去做了才知道(明天就要做了),怡亭在這邊給我很多隱性的助力,一方面是她的認真態度會感染別人,一方面是內心還是會被牽動的,儘管越來越少了。講到這,該睡了,明天還要早起把 ORTS 盡量搞懂更多地方,希望能給他們更多東西。