0%

元胞自动机

手酸

基本概念

定义

元胞自动机(Cellular Automata,简称CA)是一种应用比较广泛的模型理论,由冯·诺依曼创始,经数学家Conway、物理学家Wolfram等人的贡献后迅速发展。

在物理学定义上,元胞自动机指的是,定义在一个由具有离散、有限状态的元胞组成的元胞空间上,按照一定的局部规则,在离散的时间维度上演化的动力学系统。

组成

·元胞 :又称细胞、单元或者基元,是元胞自动机最基本的组成部分。元胞分布在离散的欧几里得空间位置上,每个时刻有着离散的状态,如{0,1}等。

·元胞空间 :元胞所分布在欧几里得空间上的网格点的集合。最常见的为二维元胞空间,通常可按三角形、四边形和六边形三种网格排列。

·邻居 :顾名思义,但邻居划分有以下几种形式:

img img img

·边界条件: 实际模拟元胞自动机的演化时不可能处理无限网络,系统必须是有边界的。处理边界格点时,可以为边界的信息进行编码,由此选择不同的演化规则。另一种方法是在边界处扩展,以满足边界有与内部类似的邻居。

边界条件分以下几种:

1.周期型边界

2.固定边界:所有边界外元胞均取某一固定常量。

3.绝热边界:边界外元胞的状态始终和边界元胞的状态保持一致。

·演化规则 :根据元胞当前状态及其邻居状态确定下一时刻该元胞状态的动力学函数。

基本思路框架

状态设置

状态变化规则

示例1-生命游戏

概述

生命游戏是一个零玩家游戏。它包括一个二维矩形世界,这个世界中的每个方格居住着一个活着的或死了的细胞。一个细胞在下一个时刻生死取决于相邻八个方格中活着的或死了的细胞的数量。

如果相邻方格活着的细胞数量过多,这个细胞会因为资源匮乏而在下一个时刻死去;相反,如果周围活细胞过少,这个细胞会因太孤单而死去。

实际中,玩家可以设定周围活细胞的数目怎样时才适宜该细胞的生存。如果这个数目设定过高,世界中的大部分细胞会因为找不到太多的活的邻居而死去,直到整个世界都没有生命;如果这个数目设定过低,世界中又会被生命充满而没有什么变化。

img

代码实现

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
import numpy as np
import random
import copy
import matplotlib.pyplot as plt

length = 100
width = 200

cell = np.zeros((length,width),int)
cell_temp = copy.deepcopy(cell) ##

for i in range(0,length):
for j in range(0,width):
cell_temp[i][j] = random.randint(0,1)
#手动结束
while not(cell_temp == cell).all():
cell = copy.deepcopy(cell_temp)
plt.imshow(cell)
plt.pause(0.2)

for i in range(0,length):
for j in range(0,width):
count = cell[(i-1)%length][j] + cell[(i+1)%length][j] + cell[i][(j-1)%width] + cell[i][(j+1)%width]
if(cell[i][j] == 0 and count != 3):
continue
if(cell[i][j] == 0 and count == 3):
cell_temp[i][j] = 1
continue
if(count==2 or count==3):
continue
cell_temp[i][j] = 0

Py-Copy与DeepCopy

copy()是浅拷贝,只拷贝父对象,不会拷贝对象的内部的子对象。

deepcopy()是深拷贝,会拷贝对象及其子对象,哪怕以后对其有改动,也不会影响其第一次的拷贝。

预备知识1-python清空命令行

1
2
3
import os
def clear():os.system('cls')
clear()

预备知识2-不可变对象与可变对象

二者区别在于对象(Object)本身是否可变

我们日常理解的复制是DeepCopy,比如94版蜘蛛侠里面一科学家复制MJ,连记忆和情感都复制

浅拷贝就是换了个标签

概念

python内置类型中:

·可变对象:list dict set

·不可变对象:tuple string int float bool

1
2
3
4
5
6
7
8
9
10
11
#可变对象
>>> a = [1,2,3]
>>> a[1] = 4
>>> a
[1, 4, 3]
#不可变对象
>>> b = (1,2,3)
>>> b[1] = 4
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'tuple' object does not support item assignment
地址问题
1
2
3
4
5
6
>>> a = [1,2,3]
>>> id(a)
1883034300352
>>> a[1] = 4
>>> id(a)
1883034300352

可变对象改变后,地址没有变化

下面讨论两个变量同时指向一个地址:

1.可变对象
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
>>> a=[1,2,3]
>>> id(a)
1790029213632
>>> b = a
>>> id(b)
1790029213632
>>> a[1] = 4
>>> a
[1, 4, 3]
>>> b
[1, 4, 3]
>>> id(a)
1790029213632
>>> id(b)
1790029213632

a和b始终指向同一个地址

2.不可变对象
1
2
3
4
5
6
7
8
9
10
11
12
13
>>> a = (1,2,3)
>>> id(a)
1790029573312
>>> b = a
>>> a = (4,5,6)
>>> a
(4, 5, 6)
>>> b
(1, 2, 3)
>>> id(a)
1790029766080
>>> id(b)
1790029573312

a改变后,它的地址也发生了变化,而b则维持原来的地址,原来地址中的内容也没有发生变化

函数传参数问题
1.可变对象

可变对象作为参数传入时,在函数中对其本身进行修改,是会影响到全局中的这个变量值的,因为函数直接对该地址的值进行了修改。

2.不可变对象

函数中的值改变,但全局的值没有改变

原因:函数中的值对应另一个地址了,全局中的值仍然指向原来地址

示例2-森林火灾

概述

  • 正在燃烧的树变成空格位
  • 如果绿树格位的最近邻居中有一个树在燃烧,则它变成正在燃烧的树
  • 在空格位,树以概率p生长
  • 在最近的邻居中没有正在燃烧情况下树在每一时步以概率f(闪电)变为正在燃烧的树

代码前置知识

Try-Except异常处理机制

语法结构
1
2
3
4
5
6
7
8
9
10
11
12
13
try:
可能产生的异常代码块
except[(Error1,Error2,...)[as e]]:
处理异常代码块1
except[(Error3,Error4,...)[as e]]:
处理异常代码块2
except [Exception]:
处理其他异常
==================================
(Error1, Error2,...) 、(Error3, Error4,...):其中,Error1、Error2、Error3 和 Error4 都是具体的异常类型。
显然,一个 except 块可以同时处理多种异常。
[as e]:作为可选参数,表示给异常类型起一个别名 e,这样做的好处是方便在 except 块中调用异常类型(后续会用到)。
[Exception]:作为可选参数,可以代指程序可能发生的所有异常情况,其通常用在最后一个 except 块。
执行流程

1.首先执行 try 中的代码块,如果执行过程中出现异常,系统会自动生成一个异常类型,并将该异常提交给 Python 解释器,此过程称为捕获异常。

2.当 Python 解释器收到异常对象时,会寻找能处理该异常对象的 except 块,如果找到合适的 except 块,则把该异常对象交给该 except 块处理,这个过程被称为处理异常。如果 Python 解释器找不到处理异常的 except 块,则程序运行终止,Python 解释器也将退出。

举例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
try:
a = int(input("输入被除数:"))
b = int(input("输入除数:"))
c = a / b
print("您输入的两个数相除的结果是:", c )
except (ValueError, ArithmeticError):
print("程序发生了数字格式异常、算术异常之一")
except :
print("未知异常")
print("程序继续运行")
==================================================
结果:
输入被除数:a
程序发生了数字格式异常、算术异常之一
程序继续运行
获取特定异常有关信息
  • args:返回异常的错误编号和描述字符串;
  • str(e):返回异常信息,但不包括异常信息的类型;
  • repr(e):返回较全的异常信息,包括异常信息的类型。

举例:

1
2
3
4
5
6
7
8
9
10
11
try:
1/0
except Exception as e:
# 访问异常的错误编号和详细信息
print(e.args)
print(str(e))
print(repr(e))
=================================
('division by zero',)
division by zero
ZeroDivisionError('division by zero',)

深入Random库

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
import random

print(random.random())
#uniform
print("random.uniform->",random.uniform(1,10))
print("random.uniform->",random.uniform(8,2))
#randint
print("random.randint->",random.randint(1,10))
print("random.randint->",random.randint(6,6))
#randrange
print("random.randrange->",random.randrange(10, 18, 2))
#choice
print (random.choice("Google.com"))
print (random.choice(["Python", "Thu", "tcp"]))
print (random.choice(("Python", "Thu", "tcp")))
#shuffle
list = [0,1,2,3,4,5,6,7,8,9]
random.shuffle(list)
print("list:",list)
#sample
slice = random.sample(list,5)
print("slice",slice)
#seed
random.seed()
print("Default Random Seed ->:",random.random())

random.seed(5)
print("Random Seed 5 ->:",random.random())

random.seed(10)
print("Random Seed 10 ->:",random.random())

random.seed("Nexus",8)
print("Random Seed Str ->:",random.random())
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
##Results:##
0.4515479335794669
random.uniform-> 5.102234346234854
random.uniform-> 6.097686432426142
random.randint-> 5
random.randint-> 6
random.randrange-> 12
g
tcp
Thu
list: [7, 0, 5, 2, 4, 8, 6, 3, 9, 1]
slice [7, 8, 1, 5, 3]
Default Random Seed ->: 0.9249849829416343
Random Seed 5 ->: 0.6229016948897019
Random Seed 10 ->: 0.5714025946899135
Random Seed Str ->: 0.4589358762046045

生成[0,1)随机浮点数。

生成一个指定范围内的随机浮点数,两个参数其中一个是上限,一个是下限。如果a > b,则生成的随机数n: b <= n <= a。如果 a <b, 则 a <= n <= b。

生成一个指定范围内的整数。其中参数a是下限,参数b是上限,生成的随机数n: a <= n <= b,注意: 下限必须小于上限。

从指定范围内,按指定基数递增的集合中 获取一个随机数。

从序列中获取一个随机元素。

将一个列表中的元素打乱.

从指定序列中随机获取指定长度的片断,不会修改原有序列。

入门Seaborn库

官网介绍

Seaborn is a Python data visualization library based on matplotlib. It provides a high-level interface for drawing attractive and informative statistical graphics.

For a brief introduction to the ideas behind the library, you can read the introductory notes or the paper. Visit the installation page to see how you can download the package and get started with it. You can browse the example gallery to see some of the things that you can do with seaborn, and then check out the tutorial or API reference to find out how.

To see the code or report a bug, please visit the GitHub repository. General support questions are most at home on stackoverflow or discourse, which have dedicated channels for seaborn.

推荐文章

seaborn绘图的基本使用

十分钟掌握Seaborn,进阶Python数据可视化分析

some tips for Numpy库

对于不同的输入,where返回的值是不同的。

1.

满足条件(condition),输出x,不满足输出y。

2.

只有条件 (condition),没有x和y,则输出满足条件 (即非0) 元素的坐标 (等价于numpy.nonzero)。这里的坐标以tuple的形式给出,通常原数组有多少维,输出的tuple中就包含几个数组,分别对应符合条件元素的各维坐标。

·shape:int或int的序列,为新数组的形状;如果我们仅指定一个int变量,则将返回一维数组。如果是一个整数元组,将返回给定形状的数组。
·dtype(可选 ):数组的所需数据类型;默认是 numpy.float64。
·order: {‘C’,‘F’},可选,默认值:C 是否在内存中以行主(C-风格)或列主(Fortran-风格)顺序存储多维数据。

返回值:返回具有给定形状,数据类型和顺序的数组。

代码实现

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
from ast import Try
from multiprocessing.heap import Arena
import numpy as np
import random
import seaborn as sbn
import matplotlib.pyplot as plt

def Forest_Fire(current_matrix,p,f):
matrix = current_matrix

# (1)空位生长树木 (0 --> 1) 储存位置
i_C_indexes = []
j_C_indexes = []
for i in range(area):
for j in range(area):
if matrix[i,j] == 0 and random.random<p:
i_C_indexes.append(i)
j_C_indexes.append(j)
else:
pass

# (2)周围树木燃烧 (1 --> -1) 储存位置,并存储上一时刻的燃烧数据
fire_memory = np.where(matrix==-1)
i_indexes = []
j_indexes = []
for i in range(area):
for j in range(area):
if matrix[i,j] == -1:
try:
if matrix[i-1,j] == 1:
i_indexes.append(i-1)
j_indexes.append(j)
except:
pass
try:
if matrix[i+1,j] == 1:
i_indexes.append(i+1)
j_indexes.append(j)
except:
pass
try:
if matrix[i,j-1] == 1:
i_indexes.append(i)
j_indexes.append(j-1)
except:
pass
try:
if matrix[i,j+1] == 1:
i_indexes.append(i)
j_indexes.append(j+1)
except:
pass
else:
pass

for k in range(len(i_indexes)):
matrix[i_indexes[k],j_indexes[k]] = -1

# (3)燃烧树木清除 (-1 --> 0)
matrix[fire_memory] = 0
# (4)雷电击中正常树木 (1 --> -1) 储存位置
i_indexes = []
j_indexes = []
for i in range(area):
for j in range(area):
if matrix[i,j] == 1:

try:
if matrix[i-1,j] == -1:
continue
else:
pass
except:
pass

try:
if matrix[i+1,j] == -1:
continue
else:
pass
except:
pass

try:
if matrix[i,j-1] == -1:
continue
else:
pass
except:
pass

try:
if matrix[i,j+1] == -1:
continue
else:
pass
except:
pass

if random.random() < f:
i_indexes.append(i)
j_indexes.append(j)
else:
pass
else:
pass
for k in range(len(i_indexes)):
matrix[i_indexes[k],j_indexes[k]] = -1
# (5)完成空位生长
for k in range(len(i_indexes)):
matrix[i_indexes[k],j_indexes[k]] = 1

return matrix

def main(area,N,p,f):
matrix = np.ones([area,area]).astype("int")
#N次模拟火灾
for time in range(N):
matrix = Forest_Fire(matrix,p,f)
C_count.append(len(np.where(matrix==0)[0]))
G_count.append(len(np.where(matrix==1)[0]))
R_count.append(len(np.where(matrix==-1)[0]))

if time<=5:
plt.figure(time+1, figsize=(19.20, 9.61))
sbn.heatmap(matrix,
cmap=[(239 / 255, 29 / 255, 31 / 255),
(165 / 255, 165 / 255, 165 / 255),
(28 / 255, 172 / 255, 76 / 255)], annot=True)
plt.savefig('C:/Users/{}.jpg'.format(time+1))

plt.figure(7,figsize=(19.20,9.61))
T = [i for i in range(N+1)]
plt.plot(T,C_count,label='Vacancy',lw=2,color=(165/255,165/255,165/255))
plt.plot(T, G_count, label='Trees',lw=2, color=(28/255,172/255,76/255))
plt.plot(T, R_count, label='Burning',lw=2, color=(239/255,29/255,31/255))
plt.grid(linestyle=":")
plt.legend()
plt.savefig('C:/Users/森林火灾曲线图')
plt.show()

global area
area = 100
C_count = [0]
G_count = [area*2]
R_count = [0]

final_matrix = main(area,100,0.25,0.01)
plt.figure()
sbn.heatmap(final_matrix,
cmap = [(239/255,29/255,31/255),
(165/255,165/255,165/255),
(28/255,172/255,76/255)], annot=True)
plt.show()

img

img

img

img

img

img

img

应用

案例

1.容易与GIS、遥感数据处理等系统结合

2.城市发展演变、土地利用变化

3.应用于物理模拟,生物模拟等领域

4.森林火灾模拟

社会学

元胞自动机用于研究经济危机的形成与爆发过程、个人行为的社会性,流行现象,如服装流行色的形成等。在生物学中,元胞自动机的设计思想本身就来源于生物学自繁殖的思想,因而它在生物学上的应用更为自然而广泛。

例如元胞自动机用于肿瘤细胞的增长机理和过程模拟、人类大脑的机理探索(Victor.Jonathan.D.,1990)、艾滋病病毒HIV的感染过程(Sieburg,H.B.. 1990)、自组织、自繁殖等生命现象的研究以及最新流行的克隆 (Clone)技术的研究等 。

生态学

用于兔子-草,鲨鱼-小鱼等生态动态变化过程的模拟,展示出令人满意的动态效果;元胞自动机还成功地应用于蚂蚁、大雁、鱼类洄游等动物的群体行为的模拟;另外,基于元胞自动机模型的生物群落的扩散模拟也是当前的一个应用热点。

计算机科学

可以被看作是并行计算机而用于并行计算的研究(Wolfram.S.1983)。另外。元胞自动机还应用于计算机图形学的研究中。

在数学中,元胞自动机可用来研究数论和并行计算。例如Fischer(1965)设计的素数过滤器(Prime Number Sieves)(Wolfram,S.1983)。

在信息学中,元胞自动机用于研究信息的保存、传递、扩散的过程。另外。Deutsch(1972)、Sternberg(1980)和Rosenfeld(1979)等人还将二维元胞自动机应用到图像处理和模式识别中 (WoIfram.S.,1983)。

物理学

流体力学,磁场、电场等场的模拟,以及热扩散、热传导和机械波的模拟

模拟雪花等枝晶的形成

-------------本文结束感谢您的阅读-------------
请作者喝一杯蜜雪冰城吧!