Archive for October, 2007

绿色呆丸除了会歪曲事实还会干什么?

被台湾媒体渲染的所谓被侮辱的选手自己的话:

謝謝大家關心 我們已經回到台灣了
今天早上05:48分抵達台灣了,謝謝大家的關心。

我剛剛看論壇還是有幾個人很不高興這件事情,那我最後再澄清一次吧,
當天是有衝突,但真的沒有像媒體說的那麼誇張。


一、
劉祐辰拿完國旗下臺後就去後台領獎,根本沒有被搶國旗………
大陸人是去找我們WCG領隊理論,雙方達不成共識才開始吵起來,
而且主要吵的是我們WCG領隊、聯合報記者和星海選手PJ、大陸領隊兩方,
我們選手在旁邊看都沒怎樣阿,SKY、FLY根本就沒有罵我們。


二、
包圍飯店也沒有,我們要回飯店時大陸選手是剛好在後門聊天,
我們的世紀帝國選手還在他們身邊走來走去也沒怎樣,
他看到大陸選手在後門就跟我們說,領隊怕跟他們碰面又不愉快,所以我們改走大廳回去而已。

三、
大陸那邊也只有PJ最激動,他個性本來就很衝動吧,
PJ罵髒話是他不對,不過不能因為他這個特例就把SKY、FLY、KING以及所有大陸選手跟他畫為等號,
事實上PJ最激動時,他們也都極力拉住PJ,希望能夠理性解決。


我是覺得大陸選手也很無奈吧,他們如果沒有解決這個問題,回去後可能會被政府當作不愛國,
可能政府不讓他們參加WCG,影響了大陸電子競技,
所以選手們都只是單純的想參加比賽,實現自己的夢想罷了,
而且FLY事後也有跟我道歉,他不是針對我們台灣選手,只是想讓事情有個解決而已。

政治的事情我們不想碰觸,劉祐辰當時也沒想那麼多,就是領獎很開心而已,
發生這樣的事情他也很擔心,怕影響了日後台灣WCG參賽權,回國後還要面對媒體、學校等等的壓力
我這樣說不是指他不愛台灣,是希望大家不要把一個單純得獎很快樂的21歲年輕人參雜太多政治色彩…….

回國後,我們都不想再談這件事情了,今天在機場時包括劉祐辰、WCG領隊接受記者採訪時也沒有回應什麼,
現在我以當事人的身分來管理ESM論壇,再有什麼激動或是偏激不實的言論我就直接砍文禁言30天,
我希望這件事情不要影響了兩岸WAR3玩家的友誼,大家把焦點多放在關心比賽和選手,才是真的對我們選手有幫助。

最後,要感謝台灣WCG領隊帶領我們、媒體朋友關注WCG,你們辛苦了,
也感謝論壇所有玩家,不管是來自台灣或是大陸的玩家,謝謝大家的關心,
希望台灣明年WCG成績會更好,台灣加油。


下面先跟大家分享幾張今天早上在機場的照片,其他照片等我整理好後會再發上來。

大家都是黑头发黄皮肤的人, 真不知道造谣是为了什么。 拼经济?
汪笨糊说: 大家一起造谣, 就是爱台湾啦!

Comments (2)

Build VHDL simulation tool chain on Linux

I take Computer Architecture course this semester and study basic VHDL for digital design. The instructor recommends ModelSim with both Windows and Linux versions. But unfortunately, ModelSim for Linux can only be installed on RH Linux. I tried to install it on Ubuntu but obviously it didn’t work. It turned out that the only solution would be using ModelSim for Windows in our computer lab. But as a dead-head Linux fan, I simply want to find alternative software to get things done on Linux platform. After some googling and asking help from friends, I found two handy software packages that form a tool chain to do VHDL simulation on Linux: GHDL and GTKWave.

What

GHDL is an amazing package that it employ gcc and compile VHDL code to objective code. It can’t translate your design into a netlist but it’s sufficient for us to do the simulation.
GTKwave is another tool which can help you view the wave form dumped by GHDL simulation. There two, in principle, can help you handle all the VHDL simulation tasks involved in a one-semester-course like computer architecture.

How

Build the tool chain

If you are using a Debian family (Debian/Ubuntu, etc) Linux, an apt-get will save your life. Try:
apt-get install ghdl
and
apt-get install gtkwave.
[You might need sudo or run it as root.]

If you not, try to download the package and read the README. It’s easy. If you want to install it on Mac as what I’ve done, remember to install X11. The whole procedure should take you less than five minutes.

How to use it

It’s very simple. GHDL will compile the VHDL code for you to object code and convert it to executable. For example, if I have CPU.vhdl which is a simple computer description. Try to type:

ghdl -a cpu.vhdl

to compile it, and

ghdl -e cpu

to make executable file (do linking).

Finally you can use

./cpu --help

to see how to run it.

Some tips:
If you include ieee package, add this option: –ieee=synopsys
If you want to let the simulation run certain amount of time, use something like

./cpu --stop-time=100ns

If you want to dump a signal wave format for gtkwave, just add –vcd=vcd.file

After that, you can use

gtkwave vcd.file to see the wave. You might need to add all the signals to the wave window via “Search->Signal Search Tree”.

Why

You might ask why it’s handy than ModelSim. It’s obvious. For example, if you write a shell script that can issue all the compiling/dumping/viewing command in the right order, you only need two keyboard stoke to run a test, in comparing with in ModelSim, where you need to do at least 10 mouse click and maybe type these commands:

view wave
add wave -r /*
"set format, etc"

Finally, you can use GHDL as your VHDL code formatter and get a very nice HTML format for your neat code. You can now make it even neater, why not :)

Some really missing features for these small tools.

1. Non-standard signal watch.

If you have a signal which is an array, it’s not handy to view the wave as ghdl doesn’t actually output the signal changing information for this signal.

2. Automatic dependency solving.

Currently GHDL will complain about the dependency, but it doesn’t actually handle this like GNU make. Therefore, you have to either write your own makefile to use make to manage your code dependency, or recompile all the code every time.

My example code of a silly CPU:

    1 -- CSE 560 Homework, a simple CPU
    2 -- Eric You XU
    3 --- version 0.05
    4
    5 library ieee;
    6 use ieee.std_logic_arith.all;
    7 use ieee.std_logic_signed.all;
    8 use ieee.std_logic_1164.all;
    9
   10 entity CPU is
   11         port (  IR      :       in std_logic_vector (31 downto 0);
   12                 READY   :       in bit;
   13                 CLK     :       in bit
   14                 );
   15 end entity CPU;
   16
   17 architecture behav of CPU is
   18     type reg_type is array(0 to 255) of std_logic_vector(31 downto 0);
   19     signal storage: reg_type;
   20
   21     signal d1, d2: std_logic_vector(31 downto 0);
   22     signal raw1, raw2: std_logic_vector(31 downto 0);
   23     signal s1_int, s2_int: integer;
   24     signal prod: std_logic_vector(63 downto 0);
   25     signal status:      std_logic_vector(1 downto 0);
   26     signal phase:       bit;
   27     signal index:       integer;
   28     signal opcode:      std_logic_vector(2 downto 0);
   29     signal needd2:      bit;
   30
   31 begin
   32
   33
   34
   35 process(clk)
   36    begin
   37     if (ready='0') then
   38         phase <= '0';
   39 -- For test
40 storage(0) <= X"00000004";
   41 storage(1) <= X"FFFFFFFD";
   42 storage(2) <= X"01010103";
   43 storage(3) <= X"0F0F0F08";
   44 storage(4) <= X"F0F0F0F0";
   45 storage(5) <= X"FFFFFFFF";
   46 storage(6) <= X"00000000";
   47 storage(7) <= X"0000000E";
   48 storage(8) <= X"00000004";
   49 storage(9) <= X"DEADBEEF";
   50
   51      else
   52        if(clk'event) then
   53           if(clk = '1') then                    -- CLK _| 
   54               if(phase = '0') then              -- state 1, read instructions
   55
   56                   opcode        <=      IR(26 downto 24);
   57                   -- 31 30 29 28 27 26 25 24: Lower 3 bit
   58                   raw1 <= storage(ieee.std_logic_unsigned.conv_integer( IR(23 downto 16) ));
   59                   raw2 <= storage(ieee.std_logic_unsigned.conv_integer( IR(15 downto 8) ));
   60                   -- RAW Hazard 
   61                   --avoid to use s1_int = con_int(raw1)
   62                   s1_int        <=      ieee.std_logic_signed.conv_integer(storage(ieee.std_logic_unsigned.conv_integer( IR(23 downto 16) )));
   63                   s2_int        <=      ieee.std_logic_signed.conv_integer(storage(ieee.std_logic_unsigned.conv_integer( IR(15 downto 8) )));
   64                   index <= ieee.std_logic_unsigned.conv_integer(IR(7 downto 0));
   65
   66               else                              -- state 3, write register files
   67                 case opcode is
   68                         when "000" => -- ADD
   69                                 storage(index) <= d1;
   70                         when "001" => -- SUB
   71                                 storage(index) <= d1;
   72                         when "011" =>
   73                                 storage(index) <= d1;
   74                         when "100" => -- INC
   75                                 storage(index) <= d1;
   76                         when "101" => -- DEC	
   77                                 storage(index) <= d1;
   78                         when "010" => -- MULT
   79                                 storage(index) <= prod(31 downto 0);
   80                                 d2 <= prod(63 downto 32);
   81                                 d1 <= prod(31 downto 0);
   82                                 if (index = 255) then
   83                                          storage(0) <= prod(63 downto 32);
   84                                 else
   85                                          storage(index+1) <= prod(63 downto 32);
   86                                 end if;
   87                         when "110" => -- DIV
   88                                 storage(index) <= d1;
   89                                 if (index = 255) then
   90                                          storage(0) <= d2;
   91                                 else
   92                                          storage(index+1) <= d2;
   93                                 end if;
   94                         when others =>
   95                                 report "Invalid OpCode." severity FAILURE;
   96                   end case;
   97              end if;
   98
   99            else                                 -- CLK |_		
  100               if(phase = '0') then              -- state 2, ALU step
  101
  102                   case opcode is
  103                      when "000" =>  -- ADD
  104                                 d1 <= conv_std_logic_vector((s1_int + s2_int), 32);
  105                                 needd2 <= '0';
  106                      when "001" => -- SUB
  107                                 d1 <= conv_std_logic_vector((s1_int - s2_int), 32);
  108                                 needd2 <= '0';
  109                      when "011" => -- COMP
  110                                 d1 <= conv_std_logic_vector((-s1_int - 1), 32);
  111                                 needd2 <= '0';
  112                      when "100" => -- INC
  113                                 d1 <=  conv_std_logic_vector((s1_int + 1), 32);
  114                                 needd2 <= '0';
  115                      when "101" => -- DEC
  116                                 d1 <=  conv_std_logic_vector((s1_int - 1), 32);
  117                                 needd2 <= '0';
  118                      when "010" => -- MULT
  119                                 -- If I assign the prod value to d1 and d2 here, a RAW hazard will occur.			
  120                                 prod <= raw1 * raw2;
  121                                 needd2 <= '1';
  122                      when "110" => -- DIV
  123                                 d1 <= conv_std_logic_vector((s1_int/s2_int), 32);
  124                                 d2 <= conv_std_logic_vector((s1_int rem s2_int), 32);
  125                                 needd2 <= '1';
  126                      when others =>
  127                              report "Invalid OpCode." severity FAILURE;
  128                   end case;
  129
  130
  131                   phase <= '1';
  132                else                             -- state 4: NOP, Increase PC, etc.
  133
  134                   -- Set STATUS ---
  135                   status <= "00";
  136                   if(needd2 = '0') then -- only look at d1
  137                       if d1 = X"00000000" then
  138                           status <= "01";
  139                       end if;
  140                       if d1(31) = '1' then
  141                           status <= "10";
  142                       end if;
  143                       if d1 = X"FFFFFFFF" then
  144                           status <= "11";
  145                       end if;
  146                   else -- needd2 = 1
  147                      if d1 = X"00000000" and d2 = X"00000000" then
  148                          status <= "01";
  149                      end if;
  150                      if d2(31) = '1' and opcode = "010" then            -- high order bit of mult is 1
  151                         status <= "10";
  152                      else
  153                         if d1(31) = '1' and opcode = "110" then         -- high order bit of div is 1
  154                            status <= "10";
  155                         end if;
  156                      end if;
  157                      if d1 = X"FFFFFFFF" and d2 = X"FFFFFFFF" then
  158                          status <= "11";
  159                      end if;
  160                   end if;
  161                   ------------------
  162
  163                   phase <= '0';
  164               end if;
  165           end if;
  166        end if;
  167     end if;
  168
  169 end process;
  170 end architecture behav;

Comments (1)

转贴两篇Baosheng 同学的文章

黑夜给了我黑色的Thinkpad

刚才看了国家统计局的发布的一个新闻,看完我崩溃了:

2004-2006年农民增收连续三年超过300元,2006年,农民人均纯收入为3587元,比2002年
增加1111元。农村居民人均纯收入增速由2002年的4.8%,提高到2006年的7.4%

也就是说,中国大学的学费高于这个国家70%人口的年收入,也就是说这个国家70%的人,
他们的孩子面临上大学的问题(其实很多人小学都没法上)。

东欧也有很多以前是社会主义的国家,比如保加利亚。我把中国学生没钱上学的事情和同
房间的师姐(来自保加利亚)说了一下,她问我:难道中国没有public school吗? 我顿
时想,是阿,既然是public school,政府就应该保证这些小孩上学阿。可是中国的大学基
本都是public school,但是好像也没有帮我们解决学费问题阿。

天下有一“纸老虎国”,人均年收入是3万“纸老虎币”,公立大学的学费各“纸老虎州”
不同。某一“纸老虎州”,曰得克萨斯共和国,对本州学生学费是1200纸老虎币左右。本
人非“纸老虎国”公民,但因为在公立大学做事,就成为“纸老虎州”政府之雇员,可享
受此等学费。若非此州公民,亦非政府雇员,便需缴纳学费5000“纸老虎币”。此外,学
校提供大量岗位向学生招工,岗位之多,哪怕是学校里面要种一棵树,也要问问有没有同
学要借此赚钱。至于薪水,此“纸老虎州”政府严格执行“纸老虎联邦”政府关于最低工
资法律,平均薪水不低于6“纸老虎币”/小时,研究生薪水可升至10-15“纸老虎币”/小
时,若作TA或RA,薪水更是20“纸老虎币”/小时之上。而一顿自助餐却才要7“纸老虎
币”,本人可以在此充分实现每顿都吃自助餐的梦想。若每顿都吃麦当劳巨无霸汉堡,则
仅需工作1个小时/天。

这么会有这么好的“纸老虎国”呢?交W8BEN表那一天我才搞懂。本人原来以为自己是穷学
生,哪知道学校财务办公室冷冰冰的对我说,你年收入超过20000“纸老虎币”,算是有钱
人,所以你在此之上赚的钱,必须征收24%的税,如果赚的再多,就交50%的税吧。额外
补充:如果你把多出来的钱捐给非盈利性机构,那么这个税的事情,咱们好说。

于是偶恍然大悟,学费降下来不是很简单吗?对有钱人征税不就完了?

想来想去,本人确实太TM有钱了,1000“纸老虎币”(折合2台新笔记本电脑)弄丢了,偶
就不要了。于是我就满世界找non-profit organization送钱,什么Free Software Found
ation,什么Wikipedia Foundation。Eric说有个什么海外华人教育基金会,帮助西部小朋
友上学。好,Eric捐多少,我就翻倍捐。 钱多赤裸裸,多不好意思阿。于是本人自己花钱
买菜,烧了,拿到教堂去给大家分享,没准就吃出下一个《当幸福来敲门》里面的男主角
。光吃饭不行阿,还要有点精神追求。 ACM TTU 支部号召去给黑人小学捐电脑,OK,偶响
应组织要求,在支部起带头作用,准备把Thinkpad捐了,还预装Ubuntu,让小朋友学习开
源技术。

于是偶又想,共同富裕不是也很简单吗?征税不就完了。你自己不为穷人作好事,那么政
府就用暴力把你的税征过来再给穷人,不是一样?谁让你敬酒不吃吃罚酒。

PS:刚来ECHO的时候,zhenfeng 大侠推荐我看一部韩剧,叫做爱在哈佛,里面金泰熙演的
那个女医学生,每周末都跑到贫民窟去帮穷人看病,而且不是她一个,是一帮人。我当时
想,这个导演也太会造神了,也太会编故事了。结果我现在是真tmd相信有这种事情了,因
为周围很多人都这样,我觉得自己RP好差。

上帝在创始纪里说,Let there be light。其实是对每个基督徒说,把真理和光明传播到
那里去。于是我对上帝说:黑夜给了我黑色的Thinkpad, 我要用它去传播光明。

把利益之燃料加于天才之火上

几个月之前,看到Eric写的一个blog

“老板说,要是下月15号报告交不上去,能源部就不给钱了。能源部不给钱,我就没资助了
,没资助的话我就真的成 辍-学-儿-童 了。”

哪知道几个月过后,居然又是15号,本人又要交proposal。今天中午本人请客,跑到学校
的食堂去吃自助餐,同Prof. Donald Lie and Prof. Yuanlin Zhang讨论了一下15号要交
的proposal。最令我崩溃的是,他们2各自也有东西想申请。于是我急了,你们不能和我抢
阿,我就靠这3.5万美金过明年的日子阿。用Eric的话说,就是,我要成辍-学-儿-童了。

你们都是爽歪歪阿,有房子有车子有儿子,还有一个都tenure了。Dr. Zhang对我说,你那
个先放一放,钱不是问题。Dr. Lie说,鲍盛,你看阿,张老师都说了,钱不是问题。我说
,你那个东东我不会作阿。Dr. Zhang怒了,东西我来作,钱拿来给你。 我靠,好,ECHO
的男人们全来我们这里吧-fund申请来,钱归你,东西老板作。

下午韩国老师上课发作业,又是2个10pts, 看来这门课真要得A了。偶突然想到为什么美国
的PhD好好作研究,好好学习,其实很简单。偶,Eric,Lavi 是属于喜欢作研究,但是也喜
欢过奢侈糜烂生活的人,本人最近天天在学校周围寻找带游泳池和52寸HDTV的房子,而且
本人计划通过开会每半年跑出美国玩一趟,今年圣诞节准备去埃及。Lavi 比我更能玩,每
月在汽车装潢上能花几百刀。Eric更加堕落,说自己烧饭太烦,天天买着吃,他吃饭花的
钱比我的房租还多。这么奢侈糜烂的生活,不弄点钱来,怎么混呢?所以我们当然好好干
活,功课都要向A努力。15号交proposal,玩命也要搞出来阿。

李老师中午非要给我10块钱饭钱,本人决定用campus mail给他寄回去,反正non-profit
organization寄信不要钱。拿出5块钱,看到上面林肯的头像,于是想到他在美国专利局门
上写的那句话: 把利益之燃料加于天才之火上。

Comments (4)

Install Ubuntu on Dell Vostro 200

[Keywords for search engine: Ubuntu dell vostro 200 live cd can't boot harddisk]

Make sure add “irqpoll” as the kernel parameter, i.e. :

title           Ubuntu gutsy, kernel 2.6.22-12-generic (recovery mode)
root            (hd0,0)
kernel          /boot/vmlinuz-2.6.22-12-generic root=UUID=78dea514-8cc8-40a9-9e51-13c359bc681b ro  quite splash irqpoll

initrd          /boot/initrd.img-2.6.22-12-generic

These are cited from here.

When the PC boots up, you will see the Grub countdown, which is set to 3 seconds by default. Press “Esc” to intercept this countdown and go enter a Grub menu. Then

  • Press ‘e’ to start editing.
  • Scroll down to the “kernel…” line. The is the line that tells Grub which kernel to boot with and the parameters to be passed to the kernel when it boots are placed at the end of this line.
  • Press ‘e’ again to edit this line.
  • Move to the end of the line. You will see any existing parameters and can add other new parameters to the end. [Add your irqpoll here]
  • Parameters are separated by spaces and are mostly either a single word (e.g. nolapic), or an equation (e.g. acpi=off).
  • Once you have added the parameter to the end of the line, press Enter to accept the editing.
  • Then press ‘b’ to boot using that kernel and those parameters.

Then, go here to see how can you modify the parameter permanently.

Comments (1)

This week’s funny stuff

(With a friend, walking on the street)
She: Why are you walking so fast, are Chinese people usually walking so fast? Why?
I:      Because we don’t have a car.

(On a birthday party with an American friend)
He: Nice party, huh?
I:    It’s really nice — my first birthday party in US, actually.
He: Do people in China usually have birthday parties?
I:     Not too many, once a year.
He:  …… LOL……..

(In a restaurant, with a friend)
He: How’s the food?
I:     It’s good, but you know what, I will take it home.
He: Why?
I:     I am gonna do some reverse engineering and figure out how to cook that.
He:  Emmm, well. (turn to the waiter). What’s the Term of Use of this dish?
(All people in that restaurant looked at us, as we were not from this planet)

Comments (3)

给那些说Linux图形界面不好看的人

iTunes 型窗口切换
Shift Window

Tab 切换窗口时小图动态变化
Tab Switch

平铺桌面
screenshot-2.png

桌面也是展台, 记得配上美女图
Reflect

苹果上的 Expose 效果
screenshot-4.png

我现在就在这么绚的环境下工作 :)

(装一个 Ubuntu 你就可以拥有这一切, 为何还在买世界找盗版的Vista.)

Comments (8)

A Practical Guide to the AIMA Python Code 2

Continued with the last post

Some readers reported that if using graph_search to solve the NQueensProblem provided in search.py, python will complain that:

TypeError: list objects are unhashable

Yes, you are doing perfectly right and the code itself is imperfect. As this point, you might want to make the List objective hashable. Inspired by the idea of Set and FrozenSet in Python, you would expect a frozen(x) function to make any mutable object immutable (and therefore hashable) [Or you can try to use tuple from beginning, but in the NQueensProblem code, it uses .index method, which is only suitable for List]. Unfortunately, this proposal (PEP-351) was rejected by Guido. Hence, we don’t have a unified way to convert any “state” to an immutable object and insert it in to “closed table”. One possible way to do this is to write your own State class and implement the __hashcode__ function. The other handy but awkward way is to convert the list to a tuple when insterting to the “closed table, i.e. edit Line 144 of search.py as:

if tuple(node.state) not in closed:
closed[tuple(node.state)] = True

Here is a toy forzen function.

"""Toy function frozen which can convert mutable objects to immutable
	Author: Eric You XU.
	GPLv2
"""

def frozen(x):
	"""Return the immutable version of an object.
	"""
	if type(x) == type([]):
		return tuple(x)
	elif type(x) == type([]):
		raise "I can't froze dictionary object as they are very hot."
	# fill your type here
	else:
		return x

You can put it in to search.py and edit the Line 144 as:

if frozen(node.state) not in closed:
colsed[
frozen(node.state)] = True

Now the code looks much better.

Comments

A practical guide to the AIMA Python code -1

Part -1 Search

Introduction

images.jpg AIMA (Artificial Intelligence: A Modern Approach) might be the most successful textbook about AI. I take this course with Prof. Yixin Chen this semester. I am going to go through all the source code (Python) provided on the website and use them to finish my homework. Therefore, both for my personal referral purpose and for someone who might be interested in using that code, I write a very simple “practical guide to AIMA python source code” series here. Enjoy the magic of AI and Python!
Step 1, build the environment.

In this section, you will need three python files:

http://aima-python.googlecode.com/svn/trunk/agents.py
http://aima-python.googlecode.com/svn/trunk/search.py
http://aima-python.googlecode.com/svn/trunk/utils.py

Type:
python agents.py
and
python search.py

to make sure that you have all the packages like Image and Tk with your python. If you don’t have them, just download them. The general guideline is to use apt-get if possible. If you are not using Debian family OS, download the Python package and then use

python setup.py

at the python package folder.

Step 2, study the code — tree search

In order to use the code, we have to get familiar with the interface. Let’s get start from search.py and start from depth_first_tree_search (Line 130). The line reads:

def depth_first_tree_search(problem):
return tree_search(problem, Stack())

We all know that depth-first search uses Stack. Now let’s omit the technical detail about the implementation of Stack in util.py and check what the “problem” is.

Let’s move to Line 16 of search.py. Here is the definition of Problem class. Here __init__ just assigns the initial state. All functions like successor and goal_test are abstract. So, let’s take a look a concrete example. Let’s jump to Line 458, NQueenProblem. It’s a subclass of Problem. It defines the initial state, successor function, and goal_test function. Node that the function conflicted and conflict are for internal use only, there are not the essential part of a problem.

Here, by this case study, we at least know that we have to define a problem with

1. self.initial field which is the starting point for a problem.
2. A successor function which generate the successor state for a given state. We will study it carefully later.
3. A goal_test function which returns either False or True.

The initial is really trivial, we can just assign a initial state to it. Note that Python is a dynamic type language, so we don’t actually care about what type of state is. We will exam the type of state later, but now let’s assume that we know the type of state.

The successor function is really tricky. A straight-forward way to design a successor function will return all possible states in a list. But if you do that, you will get an “Too many values to unpack” error. The design here is actually very neat: instead of put a state in to the list, you can put a (action, state) tuple in to a list. [Line 88 of search.py, in

function expand(problem)
...
for (act, next) in problem.successor(self.state)

read this line and you will figure out the date structure to store the successors. The reason is also simple: we can trace the path easily if you record the action down at every expanding step.

Since we moved our eyes to the Node class, let's exam it carefully.

The constructor of Node is fairly simple. The path function will backtrack all the path to the root. We can modify the code of __repr__ here to print the action out if needed. If any search finally return a result in the form of Node, we can actually get everything we need from this Node, e.g., the path to the node, the action series to the node.

Based on the knowledge above, you can write your own problem model based on tree search. Now let's move on to graph search.

Step 3. Graph search.

The only difference between tree search and graph search is that in graph search, we have a fringe that stores the closed notes. As you might know, the fringe is implemented in hash table. In Python, there is a tiny technical point: List is not hash-able as it's mutable, Tuple and String are hash-able. Therefore, if you implement your state as a list, make sure to convert it to a tuple or string or a constant. Otherwise graph search will not be happy with this and complain about it.

If you want to use A* search, another point arises: heuristic function. Note that Line 211 reads:

def f(n):
return max(getattr(n, 'f', -infinity), n.path_cost + h(n))

here n is a Node instead of a State. Hence, if you want to get the state information and implement h, you have to use n.state to get the state information.

Step 4. build your application

Perhaps the best part to study the code is to write your own code to test it. Here are my implementations on eightpuzzle and three-missionaries three cannibals problem. The code is ugly and only for study purpose only. Please don't directly copy it to your homework.

Eightpuzzle.py

#!/usr/bin/python

from utils import *;
from search import *;

class EightPuzzle(Problem):
	"""The problem of solving a eight puzzle problem """
	def __init__(self, state):
		self.initial = tuple(state)

	def successor(self, state):
		"""In the 8 puzzle problem, move the blank to other position."""
		result = []
		position = list(state).index(0)
		for action, newposition in self.possible_position(position).iteritems():
			new = list(state[:])
			new[newposition], new[position] = new[position], new[newposition]
			result.append((action, tuple(new)))
		return result

	def possible_position(self, position):
		“”"return the possible position”"”
		result = {};
		col = position % 3;
		row = position // 3;
		if row != 2:
			result['D'] = position +3
		if col != 0:
			result['L'] = position -1
		if row != 0:
			result['U'] = position -3
		if col != 2:
			result['R'] = position +1

		return result
	

	def goal_test(self, state):
		if state[0] != 0:
			return False
		elif state[1] !=1:
			return False
		elif state[2] !=2:
			return False
		elif state[3] !=3:
			return False
		elif state[4] !=4:
			return False
		elif state[5] !=5:
			return False
		elif state[6] !=6:
			return False
		elif state[7] !=7:
			return False
		elif state[8] !=8:
			return False
		else:
			return True 	

	def h(self, node):
		“”"Heuristic function”"”
		temp=list(node.state)
		sum=0
		for x in range(8):	# mahatten distance
			sum = sum + abs(temp.index(x)-x)
		return sum

	def h2(self, node):
		“”"bad h”"”
		sum = 0
		pos = 0
		for x in node.state:
			sum = sum + abs(x - pos)
			pos = pos + 1
		return sum
if (__name__=="__main__"):

#	state = [1, 2, 3, 4, 5, 6, 7, 8, 0]
	state = [7, 2, 4, 5, 0, 6, 8, 3, 1]
#	state = (2, 6, 4, 7, 0, 3, 5, 8, 1)
	instance = EightPuzzle(state)
#	breadth_first_tree_search(instance)
#	depth_first_tree_search(instance)
#	breadth_first_graph_search(instance)
#	print depth_first_graph_search(instance).path()
	print astar_search(instance, instance.h).path() 

Boat.py

#!/usr/bin/python

from utils import *;
from search import *;

"""state is a tuple with (#m1, #m2, #s1, #s2, where_is_the_boat)"""

class Boat(Problem):
	def __init__(self, state):
		self.initial = tuple(state)
		self.N = state[0]
		self.nodenum = 1

	def successor(self, state):
		result = []
		symbol = state[4]*2 -1; # 0 => -1
		action = 0
		for x in (0, 1, 2):
			for y in (0, 1, 2):
				if x + y >= 1 and x + y <= 2:
					new = (state[0] + symbol*x, state[1]-symbol*x, state[2] + symbol*y, state[3] - symbol*y, 1 - state[4])
					if self.check(new):
						result.append((action, new))
						action = action + 1
		self.nodenum = self.nodenum + action
		print result
		return result

	def check(self, state):
		for x in state[:-1]:
			if x<0:
				return False;

		if state[0]!=0 and state[0] < state[2]: return False;
		if state[1]!=0 and state[1] < state[3]: return False;

		return True

	def goal_test(self, state):
		if state[0] == 0 and state[1] == self.N and state[2] == 0 and state[3] == self.N and state[4] ==1:
			print state
			return True
		return False;

	def h(self, node):
		return 0
		state=node.state
		return state[0]

if (__name__=="__main__"):

	state=[3, 0, 3, 0, 0]

	instance = Boat(state)
#	breadth_first_tree_search(instance)
#	depth_first_tree_search(instance)
#	breadth_first_graph_search(instance)
#	depth_first_graph_search(instance)
	astar_search(instance, instance.h)
	print instance.nodenum

BTW, if you need to highlight your source code and convert it to HTML for example, one of the handy program is GNU source-highlight. I really love this.

Comments (1)

Next entries »