目录
1.元胞自动机(Cellular Automation,CA)
1.元胞自动机(Cellular Automation,CA)
元胞自动机(Cellular Automation,简称CA)是一个时间和空间都离散的动力系统,是一种常用的仿真方法。
散布在规则格网中的每一元胞(cell)取有限的离散状态,遵循同样的作用规则,依据确定的局部规则作同步更新。大量元胞通过简单的相互作用而构成系统的演化。由冯诺依曼在20世纪50年代发明。
元胞自动机不是由严格定义的物理方程或函数确定,而是由一系列规则构成。凡是满足这些规则的模型都可以算作是元胞自动机模型。因此,元胞自动机是一类模型的总称,或者说是一个方法框架。其特点是时间、空间、状态都离散,每个变量只取有限多个状态,且其状态改变的规则在时间和空间上都是局部的。
元胞自动机的核心:状态和状态随时间演变的规则


2.森林火灾
<参考程序>
(1)正在燃烧的树变成空格位;
(2)如果绿树格位的最近邻居中有一个树在燃烧,则它变成正在燃烧的树;
(3)在空格位,树以概率 p 生长;
(4)在最近的邻居中没有正在燃烧的树的情况下,树以概率 f (闪电)变为正在燃烧的树


3.伪代码

4.元胞自动机模拟森林火灾(Python实现)
(1)导入相关的库
# 元胞自动机模拟森林火灾
import numpy as np
import random
import seaborn as sbn
import matplotlib.pyplot as plt
numpy库为科学计算库,用来处理多维数组(矩阵);
random库为Python标准库,用来生成随机数,描述森林火灾的随机性;
matplotlib库是最常用的绘图工具库,与seaborn库结合操作。
seaborn库底层是基于Matplotlib的,在此用来绘制热力图,使矩阵可视化(森林火灾可视化);
(2)定义森林火灾函数(Forest_Fire函数)
Forest_Fire函数如下,共有4个操作部分:
# 森林火灾函数
# 传入参数为:(1)当前的燃烧矩阵;(2)空格位 树的生长概率p;(3)正常位 树的燃烧概率f
# 假定:空格位 --> 0 正常位 --> 1 燃烧位 --> -1
# 总量:空格位 --> C 正常位 --> G 燃烧位 --> R
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
# 完成空位生长树木的操作
for k in range(len(i_C_indexes)):
matrix[i_C_indexes[k],j_C_indexes[k]]=1
return matrix
①空位生长树木 (0 --> 1)
# (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
每当一个新的演化时间点到来时,首先要执行 空位生长树木 (0 --> 1) 的操作。若这一操作滞后,则会导致前一时刻燃烧的树木在这一时刻烧尽后重新生长为树木,故这一演化的优先级较高。并且需要将符合条件的坐标存储(而不是直接将矩阵元素更改),若不如此处理,则会导致中心灰烬点重焕生机后再次被周围的余火吞噬,无法达到 空位生长树木 (0 --> 1) 的效果。
综上,该演化优先级最高并且需要储存符合要求的坐标位置。
②周围树木燃烧 (1 --> -1)
# (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
Python的 try-except 机制 可以很好地避免边界特殊情况导致的矩阵索引越界报错,从而高效简洁地完成算法处理。
存储上一时刻的燃烧数据 fire_memory 的目的是为了在之后的树木烧尽操作中区分出上一时刻燃烧的树木,避免与当前时刻新燃烧的树木产生混淆。
储存符合条件坐标的原因是避免当前时刻新燃烧的树木引燃树木(这是一个很严重的bug),所以需要先存储所有坐标信息,再统一赋新值处理。
③烧树木清除 (-1 --> 0)
matrix[fire_memory]=0
直接将上一操作存储的燃烧数据坐标 fire_memory 对应位置的元素归零,实现烧树木清除 (-1 --> 0)效果。
④雷电击中正常树木 (1 --> -1)
# (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
这一部分的算法实现过程与操作2类似,不再赘述。
# 完成空位生长树木的操作
for k in range(len(i_C_indexes)):
matrix[i_C_indexes[k],j_C_indexes[k]]=1
return matrix
函数的最后完成第一步 空位生长树木 (0 --> 1) 的操作,最终返回一个矩阵(二维数组)。
(3)定义主函数(main函数)
# 主函数
# 传入参数为:(1)方形区域的边长;(2)模拟次数N;
(3)空格位 树的生长概率p;(4)正常位 树的燃烧概率f
def main(area,N,p,f):
# 创建一个 area*area 的实验区域,该区域均为正常位
matrix=np.ones([area,area]).astype("int")
#matrix[random.randint(0,79),random.randint(0,79)]=-1
# 开始进行森林火灾模拟 N次循环 (燃烧概率f引发森林火灾)
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/熊锐成/Desktop/Math/{}.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/熊锐成/Desktop/森林火灾曲线图')
plt.show()
cmap的传参顺序反映到数值上为从小到大:
即先传入的红色对应 -1,再传入的灰色对应 0,最后传入的绿色对应 1。
(4)执行命令
global area
area=100
C_count=[0]
G_count=[area**2]
R_count=[0]
# 传入参数为:(1)方形区域的边长;(2)模拟次数N;
# (3)空格位 树的生长概率p;(4)正常位 树的燃烧概率f
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()
5.森林火灾可视化呈现
(1)森林火灾各成分曲线图(趋势图)

(2)稳态分布图

(3)前置阶段演化图
第1时刻

第2时刻

第3时刻

第4时刻

第5时刻

第6时刻

6678

被折叠的 条评论
为什么被折叠?



