数学娱乐:推特生活游戏
今天我想介绍一位客座博主,Matt,他是英国MathWorks的顾问。你们中的一些人可能遇到过他的客户项目和关于使用的系列演示MATLAB在物理学中的应用.他会讲一个有趣的一行MATLAB程序。
目录
介绍
一个星期六下午我看到了一个链接黑客新闻到A.YouTube视频显示康威游戏的一行APL。这让我想知道Matlab®是否可以表现。
答案:也许不是一条线,但绝对是一个推特.
代码复制如下:
s = [1 1 1]';n = @(a)conv2(s,s',1 * a,'sider') - a;lf = @(a)n(a)== 2&a | n(a)== 3;a = rand(128)> 0.8;对于II = 1:500,间谍(a);绘制; a = lf(a);结束
在下面的代码中,我已经注释掉了人口初始化和可视化代码,并将其替换为该发布版本的各种备选方案,以及输出的动画gif。
A=accumarray([33;34;42;44;54],1[7]);imagesc(~A);彩色地图(灰色);对于ii=1:9,imagesc(~A);现在抽;A=lf(A);终止
在这篇文章中,我将展示代码从最初的概念到最终版本的演变,以及在矩阵中思考如何产生新的算法。
康威的人生游戏
生命游戏是一种二维细胞自动化,显示复杂的行为。
它由一个单元格网格组成,每个单元格可能处于两种可能状态中的一种,即0(“死亡”)或1(“存活”)。游戏下一次迭代中每个单元格的状态取决于周围八个单元格的状态,如下所示:
- 一个有两个邻居的活细胞仍然活着
- 任何有3个邻居的细胞都可以存活
- 任何其他的牢房都会因为孤独或过度拥挤而死亡
算法的核心由两个步骤组成:
- 计算每个单元的活动邻居数
- 使用此选项,根据每个单元格的当前状态确定其新状态
计算邻居数量
为了计算每个细胞的邻居数量,一种方法是循环遍历数组中的每个细胞,将周围3x3平方的活细胞数量相加,最后减去细胞本身的状态。
YouTube视频使用了不同的方法,创建了8个原始数组的副本,在水平和/或垂直方向上对每个副本进行一步偏移,然后对数组求和。
我的算法开发的关键部分是意识到这种与之过上的邻居只是2D卷积。在Matlab中,我们可以使用2D卷积conv2.
S=[11;10;11]邻居=@(a)conv2(double(a),S,“一样”)
S=10111邻居=@(a)conv2(双(a),S,'same')
“相同”参数用于限制conv2的输出与原始输入矩阵的大小相同。
例如:
B =兰特(5)> 0.5邻居(B)
b = 0 0 1 1 1 1 1 0 1 0 1 0 1 0 1 0 1 1 0 0 0 0 1 0 1 ans = 2 3 3 3 2 5 4 3 2 4 5 6 4 2 4 1 2 3 4 5 1 2 3 0
计算下一个状态
在计算了邻居的数量之后,下一步是使用康威的生活游戏规则来确定下一个状态。
生活=@(a)(邻居(a)=2&a)...%两个邻居的规则|(邻居(a)== 3)%规则为3个邻居B生命(b)
生活= @ (a)(邻居(a) = = 2和)|(邻居(a) = = 3) b = 0 0 1 1 1 1 1 0 1 0 1 0 1 0 1 0 1 1 0 0 0 0 1 0 1 ans = 0 1 1 1 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 0
让我们用它作为参考实现来测试对函数的修改做同样的事情:
t = @ (fOrig f)断言(所有(所有(fOrig (a) = = f (a))));
减少尺寸
推特允许用户发布长度不超过140个字符的“tweet”。生命进化博弈函数的拟合和在这个极限下的可视化需要一些技巧:
使用使用一维向量作为过滤器的conv2语法。这碰巧也更快,但需要一个额外的矩阵减元素:
S = [1 1 1]';N2 = @(a) conv2(s,s',double(a),“一样”)——;t(邻居,n2, b)
通过使用乘法乘以1.删除空格来删除更多字符
n = @(a)conv2(s,s',1 * a,“一样”)——;t(邻居,n2, b)
现在,通过删除空格和括号来缩短寿命规则函数,而不是依赖运算符优先级规则:
lf=@(a)n(a)==2&a|n(a)==3;t(寿命,lf,b)
最后,初始化一个随机总体,并使用间谍在一个循环:
a=兰特(128)>0.8;对于ii=1:25,间谍(a);现在抽;a=lf(a);终止
修改
通过将'for'循环更改为'while 1'循环(直到永远),将s的定义更改为行向量,将0.8更改为0.8,等等,可能会损失更多的字符。我在我所做的地方停止了,因为它允许我将代码放入tweet中,并为#MATLAB标签留出空间。
修改将值得制作是引入定期边界条件:
makeperiodic = @ (a)((结束,结束),(最终:),(,1);...(:,结束),a,a(:,1);...a(1,end),a(1,:),a(1,1)];非周期=@(a)a(2:end-1,2:end-1);np=@(a)非周期(n(makeperiodic(a)));lfp=@(a)np(a)==2&a|np(a)==3;
(另一种选择是使用图像处理工具箱imfilter具有使用周期边界选项的命令)
... 并使可视化效果更好:
A = accumarray([3 3;3 4;4 2;4 4;7 5 4] 1 [7]);显示亮度图像(~);colormap(灰色);2 = 1:25,显示亮度图像(~);drawnow; = lfp (A),结束
其他的事情留给读者作为练习:
结论
我在这里显示了如何在矩阵上的操作方面的思考而不是循环构造可能导致紧凑的代码。在这种情况下,动机只是为了有趣,但一般来说它可以利用内置的Matlab功能,避免重新实现现有功能。
你有什么好的单线(或一条推特)MATLAB程序吗?我很想听听你的意见这里.
评论
要留下评论,请点击这里登录到您的MathWorks帐户或创建一个新帐户。