在processing里使用80行代码制作一个元胞自动机之癌细胞扩散模型

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在processing里使用80行代码制作一个元胞自动机之癌细胞扩散模型相关的知识,希望对你有一定的参考价值。


今天研究了一下元胞自动机,在学习之前,总觉得这个名词很陌生,今天我们就来把这张纸捅破,看看到底什么是"元胞自动机"

下面是百度百科的结果:

元胞自动机(cellular automata,CA)
是一种时间、空间、状态都离散,空间相互作用和时间因果关系为局部的网格动力学模型,具有模拟复杂系统时空演化过程的能力。

通俗来说,元胞自动机就是一个盒子,这个盒子里有很多"细胞",每个"细胞"可以有自己的状态,与此同时,这些"细胞"的运动是随机的且受周围"细胞"的影响。

下面是元胞自动机的特征,了解这些特征后,你会对它有更深的认识:

  1. 同步计算(并行性):元胞自动机的处理是同步进行的
  2. 同质性:元胞空间内的每个元胞都服从相同的规则
  3. 时空局域性:
    每个元胞在t+1时刻的状态,取决于其邻居的元胞在t时刻的状态;
    t时刻的状态只对t+1时刻的状态产生影响

今天要做的模型是癌细胞的扩散模型,在写代码前,我们先来分析一下这个模型的具体内容:

  1. ​​制定元胞自动机的基本规则​​
  2. ​​从一个癌细胞开始,探究感染率与时间的关系​​

在processing里使用80行代码制作一个元胞自动机之癌细胞扩散模型_二维数组

制定元胞自动机的基本规则

我们今天从最简单的癌细胞扩散模型开始
首先,我们先定义一个400400的空间,里面有400400个细胞,在生物学中,我们知道癌细胞是突变的细胞,在模型中,我们把时间点拖到产生癌细胞那一刻,因此,程序开始时,会随机从400*400个细胞中选择一个正常细胞,并把它变成癌细胞。这是整个程序刚开始的思路,我们来看一下细节:

int[][] beds = new int[400][400];
int x_limit = 400;
int y_limit = 400;

这里是定义空间大小,我们用一个二维数组表示,beds[0][0]表示第一行第一列的细胞,可以想象成一个沿X轴对称的二维坐标轴

color red = color(255, 0, 0); // red
color white = color(255, 255, 255); // white
int Healthy = 0;
int Infected = 1;

这里我们定义正常细胞为0,癌细胞为1:
若beds[0][0] = 0,则表示第一行第一列的细胞为正常的细胞,并标识为白色;
若beds[0][0] = 1,则表示第一行第一列的细胞为癌细胞,并标识为红色

int count = 0;
float tau = 0.5;

count用来统计时间点;tau表示癌变的概率。

boolean prob( float p )

if (random(0, 1) < p) return true;
else return false;

这里我们自定义一个函数,在0和1之间随机生成一个浮点数,若该数小于癌变的概率,则让该细胞感染,具体调用方法如下,我们在后面会用到:

if (prob(tau)) cell = 1;

下面我们在processing编辑器里编写setup初始化函数:

void setup()

size(400, 400);
frameRate(50);

for (int x = 0 ; x < x_limit ; x++)
for (int y = 0 ; y < y_limit ; y++)
beds[x][y] = Healthy;
//println("beds[" + x + "][" + y + "]:" + beds[x][y]);
stroke( white );


int lucky_x = int(random(0, 400));
int lucky_y = int(random(0, 400));
beds[lucky_x][lucky_y] = 1;
//println("beds[" + lucky_x + "][" + lucky_y + "]:" + beds[lucky_x][lucky_y]);

那两个println语句大家可以在自己敲的时候补上,看看它的初始化过程,第二个println语句展示了是哪个细胞癌变了

从一个癌细胞开始探究感染率与时间的关系

下面开始制定癌细胞的感染规则,假设一个正常细胞的位置是(X,Y),那么它周围的细胞里,如果有癌细胞的话,那么它自己就有被感染的风险,在上面我们也讲过了,这个风险值为0.5,我们来看看怎么表示细胞(X,Y)周围的细胞:

在processing里使用80行代码制作一个元胞自动机之癌细胞扩散模型_初始化_02


用代码可以这样表示:

if (cell == Healthy) 
if (beds[x][y-1]==1 || beds[x][y+1]==1 || beds[x-1][y]==1 || beds[x+1][y]==1 || beds[x-1][y+1]==1 || beds[x+1][y+1]==1 || beds[x+1][y-1]==1 || beds[x-1][y-1]==1)
if (prob(tau))
cell = 1;

如果一个细胞是正常的细胞,那就去判断它周围的8个细胞,只要这8个细胞里有一个癌细胞,那么它就有被感染为癌细胞的可能,把风险带入prob函数计算,如果条件符合,则这个正常细胞变成癌细胞

变成癌细胞以后,我们还需要用颜色直观的表示出来,为了并行性,我们把感染过程和绘图分成两个函数,在绘图函数中调用感染过程的函数:

void draw()

update();
int sum = 0;
for (int x = 0 ; x < x_limit ; x++)
for (int y = 0 ; y < y_limit ; y++)
//println("beds[" + x + "][" + y + "]:" + beds[x][y]);
if (beds[x][y] == Infected)
sum++;
stroke( red );

else
stroke( white );

point( x, y );


println("Time:"+count);
println("Sum:"+sum);
println("--------------------");
count++;
//toDraw = (toDraw == 0) ? 1 : 0;


void update()

int x, y, cell;
//int toCompute = (toDraw == 0) ? 1 : 0;

for (x = 1 ; x < x_limit-1 ; x++)
for (y = 1 ; y < y_limit-1 ; y++)

cell = beds[x][y];

if (cell == Healthy)
if (beds[x][y-1]==1 || beds[x][y+1]==1 || beds[x-1][y]==1 || beds[x+1][y]==1 || beds[x-1][y+1]==1 || beds[x+1][y+1]==1 || beds[x+1][y-1]==1 || beds[x-1][y-1]==1)
if (prob(tau))
cell = 1;


beds[x][y] = cell;



核心思想就是上面讲的那些,其他代码主要是遍历每个细胞的过程,因为是二维数组,因此这里用两个for循环,想做成三维的话,就放三个for循环。

下面来看一下效果:


前两个时间点

在processing里使用80行代码制作一个元胞自动机之癌细胞扩散模型_java_03


第五个时间点

在processing里使用80行代码制作一个元胞自动机之癌细胞扩散模型_二维数组_04


第二十六个时间点

在processing里使用80行代码制作一个元胞自动机之癌细胞扩散模型_二维数组_05


第五十二个时间点

在processing里使用80行代码制作一个元胞自动机之癌细胞扩散模型_java_06


可以看到,癌细胞在不断扩散,并且速度越来越快 第九十个时间点


在processing里使用80行代码制作一个元胞自动机之癌细胞扩散模型_java_07

第一百二十五个时间点


在processing里使用80行代码制作一个元胞自动机之癌细胞扩散模型_java_08

第一百六十六个时间点


在processing里使用80行代码制作一个元胞自动机之癌细胞扩散模型_初始化_09


现在有144862个细胞被感染成癌细胞,再往下看 第二百六十六个时间点

在processing里使用80行代码制作一个元胞自动机之癌细胞扩散模型_二维数组_10


癌细胞大获全胜

声明:

  1. 这里的时间节点指一个正常细胞被完全感染的时间
  2. 该模型是比较简单的版本,实际情况中,还要考虑其他问题

以上就是全部内容,如有疑问,欢迎大家在下方评论区留言!


Qt获取命令行的执行结果|在标签上显示图片

分享两种获取CMd命令行执行结果的方法
     //写在源代码部分
    QProcess process;
    //执行开始,括号里的字符串是执行的命令
    process.start("tasklist");
    //设置命令执行过后,多少时间后来获取执行结果,单位毫秒
    process.waitForFinished(2000);
    QByteArray output = process.readAllStandardOutput();
    //声明字符串用来接收执行的结果
    QString stroutput = output;
    //将执行结果赋值给label标签,这样就可以用label来显示命令执行结果
    ui->label->setText(stroutput);
    //关闭执行
    process.close();


        //写在源代码部分
        QProcess process;
        //执行输入行内的内容
        process.start("cmd", QStringList()<<"/c"<<ui->lineEdit->text());
        //设置命令执行过后,多少时间后来获取执行结果,单位毫秒
        process.waitForFinished(200);
        QByteArray output = process.readAllStandardOutput();
        QString stroutput = QString::fromLocal8Bit(output);
        //将执行的命令赋值给文本框
        ui->textEdit->append(stroutput);
        //关闭执行
        process.close();

获取命令的示例

技术图片

    //写在源代码部分
    //引入头文件 #include <QMovie>
    QMovie *movie = new QMovie(":/new/img/23.gif");

       movie->start();
       ui->label->setMovie(movie);

      //原理是在label上新建一个标签用来播放图片

在标签上显示图片示例

技术图片

//图片弹框源码
#include "imgshow.h"
#include "ui_imgshow.h"

#include <QMovie>

imgShow::imgShow(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::imgShow)
{
    ui->setupUi(this);

    QMovie *movie = new QMovie(":/new/img/23.gif");
       ui->label->setMovie(movie);
       movie->start();
}

imgShow::~imgShow()
{
    delete ui;
}

以上是关于在processing里使用80行代码制作一个元胞自动机之癌细胞扩散模型的主要内容,如果未能解决你的问题,请参考以下文章

代码行最大长度宜控制在 70 至 80 个字符以内

请问如何使用MATLAB进行元胞数组批量提取数据。

如何在 Matlab 中使用元胞数组?

元胞自动机简介

MATLAB将元胞数组中特定行列转换为矩阵

MATLAB的cell数组