[Python練習向] 簡易元胞自動機框架


  關於元胞自動機(Cellular Automata, CA)的原理這里就不再敘述了。

  以前的學校地理系有用CA做城市發展研究的大牛,無論在課堂上還是在項目中都會用得到CA模型。雖然CA模型本身並不復雜,但是每次從新寫起也是十分麻煩,因此一個通用的CA模型框架能夠減少很多工作量。幸好對於大多數CA模型的應用來說,其鄰域定義大同小異,最主要的不同在於元胞的轉換規則會根據問題和方法的不同而有所變化。因此這個通用框架的核心在於,用戶可以自行定義元胞的轉換規則。

  PyCA構建CA模型的流程如下:

  創建轉換規則類需要兩類參數:

  1) 鄰域類型和大小

  在PyCA中定義了三種類型的鄰域: von、moore和custom,分別對應Von Neumann鄰域(大小為1時即四鄰域)、Moore領域(大小為1時即八鄰域)和自定義鄰域。

   其中2代表中心元胞。如果需要自定義領域,則需要如上圖所示自行定義鄰域矩陣,使用1代表有效鄰域,2代表中心元胞,其他位置則用0表示。需要注意的是,PyCA沒有其他依賴numpy,定義矩陣時必須使用原生的list。

  2) 自定義轉換規則

  在定義轉換規則時,用戶不需要了解具體的模型運行流程參數。需要處理的參數有三個,包括當前中心元胞的值、有效鄰域元胞的值和環境因子,並根據上述參數給出下一次循環時中心元胞的值。因此轉換規則的定義如下:

newvlaue = rule(oldvalue, neighborhood, envi)

  neighborhood和envi為鄰域元胞值和環境參數。這個兩個參數會傳入和之前定義鄰域大小相一致的矩陣,有效鄰域中保留對應的元胞或環境參數,無效鄰域將賦值為None。由於該框架支持多層環境參數,當輸入的環境參數有多個圖層時,neighborhood是一個包含每一層鄰域的list。

  以最簡單的生命游戲為例,其元胞轉換規則應該如下:

def rule_lifegame(pix, neighborhood, envi):
    # Replace all the None with 0
    for r in range(3):
        for c in range(3):
            if neighborhood[r][c] == None:
                neighborhood[r][c] = 0
    
    # 1 means living, and 0 means dead
    if pix == 1:
        # The central cell can not be counted.
        live = numpy.sum(neighborhood) - 1
        if live < 2:
            return 0
        elif live <= 3:
            return 1
        else:
            return 0
    else:
        live = numpy.sum(neighborhood)
        if agent == 3:
            return 255
        else:
            return 0;

  當定義好轉換規則時,就可以用rulebuilder類來創建模型規則。rulebuilder類有兩種初始化方法,分別對應預定義鄰域(von、moore)和自定義領域:

# Predefined neighborhood: 'von' and 'moore'
rulebuilder = PyCA.rulebuilder(rule, ntype, nsize) # Custome neighborhood:
rulebuilder = PyCA.rulebuilder(rule, neighboorhoodregion)

  當新建好rulebuilder類后就可以調用build()方法類創建模型規則,以上面的生命游戲為例:

rulebuilder = PyCA.rulebuilder(rule_lifegame, 'von', 1)
carule = rulebuilder.build()

  最后一步是利用CA類來創建CA模型。新建CA類需要三個參數:由rulebuilder.build()生成的模型規則、初始元胞分布、環境參數:

ca = PyCA.CA(envi, initialcells, carule)

  然后調用CA類中的evolve()方法來進行迭代:

ca.evolve(time, returnresult, storehistory)

  其中time指定迭代次數,默認值為1。returnresult指定在完成所有迭代后是否返回當前元胞分布,默認為False。storehistory指定每次迭代后是否將元胞分布保存到ca.history中,默認值為False。ca.history是一個dict,定義為 ca.history = {time: result of that time}。用戶可以在完成迭代后調用ca.history得到每次迭代結果。

  至此,一個完整的CA模型創建和運行流程完成。PyCA源碼地址:http://pan.baidu.com/s/1mgwjkLE

  最后,給出一個完整生命游戲Demo:

import PyCA, numpy, random
from PIL import Image

# rule for life game
def rule_lifegame(pix, neighborhood, envi):
    for r in range(3):
        for c in range(3):
            if neighborhood[r][c] == None:
                neighborhood[r][c] = 0
    
    if pix == 255:
        live = numpy.sum(neighborhood) - 255
        if live < 2 * 255:
            return 0
        elif live <= 3 * 255:
            return 255
        else:
            return 0
    else:
        live = numpy.sum(neighborhoodn)
        if agent == 3 * 255:
            return 255
        else:
            return 0;
            
# build initial cell distributioin, randomly pick up 3000 cells as living cells
(row, col) = (100, 100)
cells= numpy.zeros((row, col)).tolist()
for i in range(3000):
    cells[random.randint(0, 99)][random.randint(0, 99)] = 255

# build trasformation rules
rulebuilder = PyCA.rulebuilder(rule_lifegame, 'von', 1)
carule = rulebuilder.build()

# create CA model
ca = PyCA.CA(cells, cells, carule)
ca.evolve(50, False, True)    

# save the array of result as bmp file
for (time, result) in ca.history.items():
    arr = numpy.array(result, dtype = numpy.uint8)
    im = Image.fromarray(arr)
    im.save('time_{0}.bmp'.format(time))

 

P.S: 為避免嚴重的邊界效應,該模型會忽略處於邊界的元胞。

 

如有什么問題歡迎私信討論。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM