Showing posts with label complexity. Show all posts
Showing posts with label complexity. Show all posts

Tuesday, August 29, 2006

Graph-based Modeling on Python

Agent-based modeling 的電腦實驗,最核心的架構不外乎一個大迴圈(super loop)包裹著一群規則。大迴圈每跑一輪,系統就更新一次狀態,就如同時鐘的滴答(tick)聲般。通常系統每次滴答都會收集一次統計資料。這類實驗,有許多現成的 famework 可用,如最經典的 Swarm 及其後進 Repast ,還有我模仿 Repast ,自己搞的一個 ,它們都提供了 start, pause, stop 等流程控制的介面。

模擬複雜網路,也可以套用 Agent-based modeling 架構。不過諸如網路的群聚度(clustering coefficient, C)及網路特徵的路經長度(characteristic path length, L)等統計數據計算需耗費的時間,隨著網路的規模成長很快,所以不適合運作太頻繁。但我們卻得靠這些統計數據來判斷網路是否收斂、試驗是否該終止了,想試驗各個參數排列組合時,更是雪上加霜。

透過 Intermediate File 是很直覺的解法。程式每次執行都餵入一個輸入檔來初始網路結構,並以參數決定 super loop 要跑幾次。統計數據只在程式要結束時計算,然後將網路狀態及統計數據吐給輸出檔。下次要執行,就以這個輸出檔當作新的輸入,然後一樣決定要跑幾圈,最後得到另一個輸出檔。採取接力的方式,不用每次都從頭跑,不會浪費先前程式執行的時間。

Multithread 是另一個可行作法。採用 Agent-based modeling framework 的方式,一個 thread 跑核心的規則。另一個 thread 則控制試驗的流程,讓 user 決定何時該暫停下來,計算統計數據,然後決定是否繼續執行。

Dynamic Programming Language 是這次的正解。利用動態程式語言,如 Python ,可以很方便於執行時期控制模擬試驗的程式流程。我就是採用 Python ,搭配 NetworkX 來處理 Graph ,並以 matplotlib 來繪製圖表。接下來就看看如何架設這個試驗平台:

  1. 下載 Python Enthought Edition 的 installer 。它是 Python 的加強版,除了 Python 基本工具外,還整合了許多有用的工具,例如 matplotlib
  2. 這裡下載 NetworkX 的 installer 。
  3. 依序執行這兩個 installer 。

裝好了後,就以 Emergence of a small world from local interactions: modeling acquaintance networks 裡描述的實驗來操刀,試寫第一個 Python 程式:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
"""
Simulation for the verifying of "Emergence of a Small World from Local
Interactions: Modeling Acquaintance Network", Davidsen J. et al. 2002.
 
Public Variables:
    - Iters: the interations of loop, used in loop()
 
Private Variables:
    - _G: graph of the acquaintance network
    - _N: the total of nodes
    - _p: the death-and-birth probability, used in _step2()
    - _run: a generator returned by loop()
 
Usage
=====
 
This module must run on a python shell with interative mode; and call
public functions e.g. runnext().
 
Example
-------
You can simply run this module with default settings.
 
    > python -i acq2002.py
    >>> runnext(10)         # loops 10 times of Iters time-steps.
    ...
 
Setting parameters is allowed.
 
    >>> start(1000, 0.04)   # starts the simulation with new N, and p
    >>> Iters=10000         # sets the iterations of each loop
    >>> runnext(5)          # loops 5 times of 10000 time-steps.
    ...
    >>> Iters=100000        # sets the iterations of each loop
    >>> runnext(2)          # loops another 2 times of 100000 time-steps
    ...
 
After above, you may want to save the result.
 
    >>> savepkfig()
    >>> savenet()
 
"""
__author__ = "Jiang Yu-Kuan, yukuan.jiang(at)gmail.com"
__date__ = "2006/08/22~2006/10/02"
__revision__ = "1.10"
 
import random as rnd
import networkx as nx # Must import this as a name to avoid namespace collision!
 
 
def _create():
    """Create an empty acquaintance network.
 
    Adds _N nodes to _G, and _G contains no any edges.
    """
    global _G
    _G = nx.Graph()
    _G.add_nodes_from(xrange(_N))  # adds n nodes into _G
 
 
def _step1():
    """Friend making of two persons.
 
    One randomly chosen person picks any two his acquaintances and
    introduces them to each another. If they have not met before, a new
    link between them is formed. In case the person chosen has less than
    two acquaintances, he introduces himself to one other random person.
    """
    u, v = rnd.sample(xrange(_N), 2)
    nb = _G.neighbors(u)
    if len(nb) > 1:
        u, v = rnd.sample(nb, 2)
    _G.add_edge(u, v)
 
 
def _step2(p):
    """Death and Birth of a chosen person.
 
    With probability p, one randomly chosen person is removed from the
    network, including all links connected to this node, and replaced by
    a new person with one randomly chosen acquaintance.
    """
    if rnd.random() < p:
        # sol. 1
        v = rnd.randrange(_N)
        _G.delete_node(v)
        _G.add_node(v)
 
        # sol. 2: slower than sol. 1.
        #_G.delete_edges_from(_G.edges(rnd.randrange(_N)))
 
 
def _avgK2():
    """Return the average square of degree of all nodes."""
    kss = [k*k for k in _G.degree(_G.nodes())]
    return sum(kss)/float(_N)
 
 
def _avgSPL():
    """Return the average shortest path length of Graph _G."""
    pathlengths=[]
    for v in _G.nodes():
        # sol. 1
        #spl = nx.single_source_shortest_path_length(_G,v)  # including v to v
        #for pl in spl.values():
        #    pathlengths.append(pl)
 
        # sol. 2
        pathlengths += nx.single_source_shortest_path_length(_G,v).values()
 
    return sum(pathlengths) / float(len(pathlengths)-_N)
 
 
def _stat():
    """Gather statistics for Graph _G."""
    print "N, p = %d, %f" % (_N, _p)
    print "Degree histogram:", nx.degree_histogram(_G)
    print "Avg. degree, <k>:", 2.*_G.number_of_edges()/_N
    print "Avg. square of degree, <k^2>:", _avgK2()
    print "Avg. clustering coefficient, C:", nx.average_clustering(_G)
    print "Avg. shortest path length, L:", _avgSPL()  # spends huge time
 
 
def savepkfig(fn='acq2002pk.png'):
    """Save the p(k) figure.
 
    - fn: file name
    """
    import pylab as mpl
    dh = nx.degree_histogram(_G)
    pk = mpl.array(dh)/float(_N)
 
    mpl.loglog(pk, 'r--')
    mpl.grid(True)
    mpl.gca().xaxis.grid(True, which='minor')
    mpl.xlabel('k')
    mpl.ylabel('p(k)')
    mpl.title('N=%d, p=%d' % (_N, _p) )
    mpl.savefig(fn)
 
 
def savenet(fn='acq2002', fm='GPickle'):
    """Save the acquaintance network.
 
    - fn: file name
    - fm: file format
    """
    save = {'edgelist':nx.write_edgelist,   # edge list
            'adjlist':nx.write_adjlist,     # node adjacency-list
            'yaml':nx.write_yaml,           # YAML text format
            'gpickle':nx.write_gpickle      # Python pickle format.
            }
    fm = fm.lower()
    if fm not in save.keys():
        fm = 'edgelist'
 
    import os
    fn, ext = os.path.splitext(fn)
    ext = ext[1:].lower()
    if ext in save.keys():
        fm = ext
    save[fm](_G, '.'.join([fn, fm]))
 
 
def _loop():
    """Loop _step1 and _step2 of Iters times and gather statistics.
 
    This function uses yield statement and returns the total iterations of loop
    """
    import time
    t_start = time.time()  # records the start time
    t_ttl = 0  # clears the total time spent
    i_cnt = i_ttl = 0  # clears the loop counter and total loops.
 
    _create()  # create an empty network
 
    while 1:
        i_cnt += 1
 
        _step1()
        _step2(_p)
 
        if i_cnt == Iters:
            i_ttl += i_cnt
            i_cnt = 0
 
            _stat()
 
            t_inc = time.time() - t_start
            t_ttl += t_inc
            print "Time spent (increment,total): (%f,%f)" % (t_inc, t_ttl)
            yield i_ttl
            t_start = time.time()
 
 
def runnext(n=1):
    """Call _run.next() of n times."""
    for i in xrange(n):
        print _run.next()
 
 
def start(N=100, p=0.04):
    """Start the module.
 
    - N: the total of nodes of the network
    - p: the death-and-birth probability
    """
    global _N, _p, _run
    _N, _p = N, p
    _run = _loop()  # gets a generator
 
 
Iters = 100000
 
if __name__ == "__main__":
    # Uses Psyco if available
    try:
        import psyco
        psyco.full()
        print "Psyco: OK"
    except ImportError:
        print "Psyco: FAIL"
 
    start(100, .04)
 
    """
    import profile, pstats
    profile.run('runnext()', 'acq2002.prof')
 
    s = pstats.Stats('acq2002.prof')
    s.sort_stats('time','name').print_stats()
    """
  • 行 203~211 的 start() 除了測試這個模組外,也用作主程式。
  • 行 211 讓我們取得 generator 給 _run 。
  • 行 214 設定每次 _run.next() 要跑幾輪 super loop ,每 _run.next() 一次,才統計一次數據。
  • 行 225 執行 start() ,並指定不同的 node 數 N 及死生發生的機率 p 。
  • 這個模組執行後,可以在 Python shell 下 _run.next() ,每 _run.next() 一次,大迴圈就跑 Iters 輪。此外,還可以在 Python shell 中改變 Iters 的次數。
  • 行 197~200 的 runnext() 讓 Python shell 下,調用多次 _run.next() 更方便。
  • 行 217~223 使用 Psyco 來加速。

註:

  • NetworkX 的用法可以參考其 TutorialAPI Reference
  • Python 的 random 模組說明可以參考這裡
  • 要以 matplotlib 繪製圖表,可以參考其 TutorialScreenshots 。其刻意模仿 Matlab 的用法,用來倍感親切。
  • 其他 Python 的說明文件可以參考 Python Tutorials

Friday, July 07, 2006

A Big Buying

既然要再回到象牙塔蹲一陣子,趁機大拜書一下是一定要的啦 :)

除了到各圖書館抱些書過過癮外,買書勢必是免不了的!

說到買書,這年頭誰不是在網路買呢?是吧!(事實是有些書在實體書店找不著 :p)

於是我就逛逛 Amazon ,晃晃若水堂,找些對味的:

Modeling Neural Development
上次被關在塔裡搞論文時,就一直想翻翻這本,跟學校請購卻沒下文;如今再次入塔,當然要抱一本回來當枕頭,也好斷了當年的念 ^_^b

The World in my Mind, My Mind in the World
幾年前拜讀了 Aleksander 的論述後,我整理了〈Weighted and Weightless〉;現在出新書了,當然要忙裡偷閒一下,聽聽他說些什麼 ^____^

Second Nature : Brain Science and Human Knowledge
有沒有搞錯!十月才要出版的書,也到上面兜售,想讓人口水乾流嗎?衝著作者 Edelman 是諾貝爾獎得主, 就值得聽聽他想說些什麼~ Hmm... 不過,我是不預購的,暫時放過這本吧 :p

小小世界
這本是 Duncan Watts 的博士論文,雖說是小世界(Small World)領域的經典,但連這都有人翻譯,會不會太閒了,不不不,是太令人感動了。嗯,給它來個最實際的支持…… :p

深入淺出 ARM7
哇勒,好慫的書名喔,這本是大陸那小有名氣的周立功出的,不久前在街上混吃時翻過,藉這次大採購,順便買本回來存參。

Monday, October 31, 2005

I want my Orkut

前不久才接受阿哲的邀請,加入了 Linkist
今天又發現 Google 也推出了 Orkut ,可惜它跟 Gmail 一樣,要有人邀請才可加入 :(

Google 真是神,現在網路上最流行的東西它幾乎都有份,以我這幾天在 survey 的 Wiki 來說好了,剛剛才發現 Google 也有搞個叫作 Google Wiki 的東東出來,只不過還沒正式公開罷了@.@

~~

   提起人際網路,一件滿有名的東西就是所謂的六度分離理論。如果任何彼此認識的兩人間,都為他們拉條鍊標示出來。六度分離理論告訴我們,地球村上的任兩人 間,無論其種族差異多懸殊,也不論他們居住地距離多遙遠,只要六條鍊,就可以將他們串起來--呵!世界真小!(What a small world!)

  系統學家定義的小世界網路(The Small World Network)有「平等式」及「貴族式」兩種。它們都必須滿足兩個條件。

  1. 低分隔度(low degree of separation)
  2. 高群聚度(high degree of clustering)
  通常隨機(random)網路傾向於有低分隔度,有序(order)網傾向於有高群聚度,它們各據在光譜的兩端,特性都很單純。而小世界網路則是介於此兩極端中間的複雜網路。

  在新增連結不必付出額外成本的情況下,容易演變成「貴族式」的 scale-free 網路。網際網路(Internet)就是貴族式的。

  當限度或成本發揮作用時,妨礙了富者愈富,貴族就會逐漸「平民化」,成為每個元素的連結數都差不多的「平民式」網路。人際網路(social network)就是平民式的。

  小世界網路具備許多特性讓科學家非常感興趣。這些網路在物理或生物等系統上呈現出高度的彈性、好的應變能力及高的反應速度,也較容易形成「同步」震盪的秩序表現。

Wednesday, October 19, 2005

《理性之夢》

  • 書名:理性之夢(The Dreams of Reason)——這世界屬於會作夢的人
  • 作者:Heinz R. Pagels
  • 譯者:牟中原、梁仲賢
  • 出版者:天下文化出版股份有限公司
  • 出版日期:1991年7月31日第一版/1993年11月15日第一版第11次印行
  • 內容概要:

首先我要先聲明,閱讀本書最好選擇頭腦清晰的時候。如果可能的話,還要來回多讀幾遍,因為其描述的內容廣泛,但卻圍繞著同一個隱約的中心議題。當然,如果不願花費那麼多時間的話,也可以選幾個自己較感興趣的主題來細細推敲……

書中主要分成兩部分:

一部分〈複雜性科學〉由第二章至第七章。各描述了〈新科學的綜合體〉、〈秩序、複雜性與渾沌〉、〈生命可以是如此的非線性〉、〈模擬真實世界〉、〈結合論與神經網路〉、〈錢賺得越來越快〉等主題。

這一部分說明了電腦的發明對於人類的衝擊,就如同望遠鏡或顯微鏡的發明般,擴展了我們看待著個世界的視野和提供了新的研究途徑。使科學在探索了小宇宙和大宇宙而清楚了其大致整個景觀後;進而能往尚未探歷的處女地「複雜性」踏出第一步。

身體器官、腦、經濟、人口、演化系統、動物行為和大分子等,這些都是複雜系統。有些可以由電腦模擬計算,有些除了自己本身之外,沒有任何東西能模擬它。科學家們正以跨科學的方式來迎接“複雜性”的挑戰。很令人驚訝的是,科學家發現可以從簡單的規則產生複雜系統。

並由「免疫系統」、「分類者系統」,「演化系統」,「神經系統」(或人腦)而歸納出「選擇性系統」的運作通則,進而構成「型態識別」或「學習演算法」。也藉此說明了「科學方法運作的機制」及「思考的過程」都呈現了一個「選擇性系統」。

二部分〈哲學與反哲學〉由第八章至第十三章。分別敘述〈造物主的造物密碼〉、〈等待救世主〉、〈錯以腦為心的人〉、〈軀體從不說謊〉、〈向無限挑戰〉、〈創造的工具〉等主題。

這一部分承接了第一部分。在第二部分最精采的內容是對於「心」(mind)、「物」問題的各種探討:首先說明了「唯心一元論」和「唯物一元論」等一元論的 局限;再來說明了哲學家與科學家主張的各種二元論架構,如「範疇二元論」、「實體二元論」、「屬性二元論」及「認識二元論」。也指出了「範疇二元論」是無 法研究的,「實體」和「屬性」二元論的謬誤。

最後作者說明了其相信「認識二元論」才是正確的。指出它是方法或意向的二元論,建立了「原則上」與「實際上」的分界。並提出了「因果斷鏈」及「複雜性障礙」兩個觀念來支持「認識二元論」。

令人印象深刻的是在第三百一十二頁開始,作者提出了一個哲學式的幻想,並於「哲學家與生物學家的對話」過程,逐漸引導讀者感受作者對於「心」、「物」問題的主張。

Original: Yukuan on Tue, 24 Jun 1997 15:51:12

Thursday, September 25, 2003

[Notes] NEXUS: Small Worlds and the Groundbreaking Science of Networks

  好書值得一再推薦,天下出的這本關於小世界的譯作真得非常值得大家關注一下。畢竟數學是各種科學的媽,何況這本書也寫得蠻淺顯的,不看真得很可惜。

  剛剛又整理好了一些 Notes ,以方便自己日後檢索,現在就和大家分享:

  -- Yukuan 2003/9/25

Forwarded by Jiang Yu-Kuan
----------------------- Original Message -----------------------
--
  一些 key words:

lost-letter technique
random graph
強連繫、弱連繫
同步
群聚度,degree of clustering
分隔度
hierarchical decentralized
power law of links to nodes
diffusion-limited aggregation, DLA
connector、集散點
scale-free
egalitarian, 平等式的 / aristocratic, 貴族式的
引爆點
contact process
平民化
--
群聚度(CD):假設網路上有某一點 X ,考慮所有直接與它相連的點。
   原則上這些點彼此間也可能相連。假如它們每一點都相連,那
   X 的 CD 值就是 1 ,而整個網路的 CD 值即是對每一點作同樣的
   操作後,取其平均。
分隔度(SD):任取網路中的兩點,找出其間最短路徑所用的步數。這就
  是這兩點間的「距離」。對網路中的任兩點重複相同的計算,取其平
  均。這就是網路的「分隔度」。

“群聚度”和“分隔度”要拿來和同樣 degree of node 的 random graph
作比較,以判斷其偏離正常值多遠。
--
  random graph/network 傾向於有低的“分隔度”。
  order graph 傾向於有高的“群聚度”。

  介於其間的 network ,在同樣等級的 edge 成本下,可以具有
“高群聚度”及“低分隔度”的現象。這就是我們感興趣的複雜網路。

  此等網路有高的彈性、應變能力及反應速度上的優勢,且較容易形成
“同步”震盪的秩序表現。

  其中,又可分為“平等式”及“貴族式”等兩類小世界網路:

  在新增連結不必付出額外成本的情況下,容易“演化”成貴族式的
scale-free 網路。

  當限度或成本發揮作用時,妨礙了富者愈富,貴族就會逐漸“平民化
”,成為每個元素的連結數都差不多的平民式網路。
--
  平民式小世界的例子:

螢火蟲同步發光現象、
線蟲的神經網路、
人類大腦區域間的神經連結系統、
貓大腦的同步活動、
交通運輸網、電力輸送網
--
  貴族式的例子:

人際關係網、Internet、WWW、
論文引用、科學家共同寫論文網、語言結構字句的前後關係、
食物網、細胞代謝網、
河流網、DLA、
富者愈富、性接觸網、校友會、大企業的小圈子

  這些都有少數集散點、connector並遵守 scale-free network 的
幕次率。
--

--------------------- Original Message Ends --------------------


--

科學是靠事實建立的,正如房子是用石頭砌成的,
但是一堆事實稱不上是科學,就如一堆石頭算不上是一棟房子。
  -- 龐加萊(Henri Poincare , 法國數學家、物理學家)
--

Friday, September 12, 2003

[心得] Small Worlds

  今天晚上發起狠來,一口氣把天下出的這本《連結》 K 完了。
  這裡非常推薦大家真的可以好好地給他瞧一瞧!
  看看介於秩序及完全隨機間的複雜網路,展現的「小世界」現象。
  更重要的是這種網路所具有的本質--“彈性”及“應變能力”。
  在前陣子,受手邊正在 K 的論文啟發,也曾經費了一個晚上的時間思索過類似的議題。
  不過之前只是模糊的感覺,直覺得相關議題很重要,也沒聽過什麼是小世界;直到此刻,才有著深刻的認識。