用元胞自动机实现多数分类算法

元胞自动机(Cellular automaton)

元胞自动机是由元胞组成的网格,每个元胞都根据邻域的状态来选择开或关。所有的元胞都遵循同样的规则,也称为元胞的更新规则,规则根据各元胞邻域的当前状态决定元胞的下一步状态。同自然界的复杂系统一样,元胞自动机也是由大量简单个体(元胞)组成,不存在中央控制,每个个体都只与少量其他个体交互。而且元胞自动机也能表现出非常复杂的行为,它们的行为很难甚至不可能通过其更新规则来预测。元胞自动机有很多种类型,著名的“生命游戏”也是元胞自动机的一种。

初等元胞自动机(Elementary cellular automaton)

初等元胞自动机是一维两状态的元胞自动机,每个元胞仅与两个相邻元胞相连。元胞自动机的时空图表现了元胞自动机的立体构型随时间的变化,最顶上一行是一维元胞自动机的初始状态设置,下面跟着的依次是每一步更新后的状态。

执行“多数分类(Majority classification)”任务的元胞自动机

该元胞自动机要能区分初始状态中是开状态还是关状态占多数。如果是开状态占多数,最后所有元胞就应当都变成开状态。同样,如果是关状态占多数,最后所有元胞就应该都变成关状态。多数分类任务有点类似于选举,是在大家都只知道最近邻居政治观点下预测两个候选人谁会赢。

我们使用一维元胞自动机,每个元胞与相邻的6个元胞相连,这样元胞的邻域中就有7个元胞(包括自己)。一个合理的想法是:“元胞应当变成邻域中当前占多数的状态。”这就好象根据你自己和邻居的多数意见来预测哪个候选人会当选。然而,这个“局部多数投票”元胞自动机并不能完成任务。

我们使用的是梅拉妮·米歇尔(Melanie Mitchell)在《复杂》(Complexity: A Guided Tour)一书第203页给出的规则:

0000010100000110000101011000011100000111000001000001010101
0101110110010001110111000001010000000101111101111111111011
011101111111

第1位是邻域全为0时中间元胞的更新状态,第2位是邻域为0000001时中间元胞的更新状态,依次往后。由于邻域状态有 27 = 128 种可能,因此该规则有128位。但是光看这些数位是看不出这个规则如何运作,也无法知道为何它进行多数分类时适应度很高。

实现该算法的 C# 程序

下面就是相应的 C# 源程序 MainForm.cs:

  1 using System;
  2 using System.Drawing;
  3 using System.Windows.Forms;
  4
  5 namespace Skyiv.CellularAutomaton.MajorityClassification
  6 {
  7   sealed class MainForm : Form
  8   {
  9     static readonly int sizeCellular = 3;
 10     static readonly int nCellular = 201;
 11     static readonly int lines = nCellular;
 12     static readonly Pen pen = new Pen(Color.Black, sizeCellular);
 13     static readonly string strRuler =
 14       "0000010100000110000101011000011100000111000001000001010101" +
 15       "0101110110010001110111000001010000000101111101111111111011" +
 16       "011101111111";
 17     static readonly bool[] ruler = new bool[strRuler.Length];
 18
 19     Graphics gc;
 20
 21     MainForm()
 22     {
 23       Text = "Majority Classification";
 24       BackColor = Color.White;
 25       ClientSize = new Size(nCellular * sizeCellular + 1, lines * sizeCellular + 1 + 32);
 26       for (var i = 0; i < ruler.Length; i++) ruler[i] = strRuler[i] == ‘1‘;
 27     }
 28
 29     protected override void OnPaint(PaintEventArgs e)
 30     {
 31       gc = e.Graphics;
 32       DrawGrid(true);
 33       var cellulars = GetInitCellulars();
 34       DrawCellulars(cellulars, 0);
 35       DisplayMessage(cellulars);
 36       for (var i = 1; i < lines; i++)
 37       {
 38         StepIt(cellulars);
 39         DrawCellulars(cellulars, i);
 40       }
 41       base.OnPaint(e);
 42     }
 43
 44     void StepIt(bool[] cellulars)
 45     {
 46       var buf = new bool[cellulars.Length];
 47       for (var i = 0; i < nCellular; i++)
 48         buf[i] = ruler[GetValue(cellulars, i)];
 49       Array.Copy(buf, cellulars, cellulars.Length);
 50     }
 51
 52     int GetValue(bool[] cellulars, int idx)
 53     {
 54       var n = 0;
 55       idx = (idx + 3) % nCellular;
 56       for (var i = 0; i < 7; i++)
 57         if (cellulars[(idx - i + nCellular) % nCellular])
 58           n += 1 << i;
 59       return n;
 60     }
 61
 62     void DrawCellulars(bool[] cellulars, int line)
 63     {
 64       for (var i = 0; i < cellulars.Length; i++)
 65         if (cellulars [i])
 66           Set(i, line);
 67     }
 68
 69     void DisplayMessage(bool[] cellulars)
 70     {
 71       var blacks = 0;
 72       foreach (var cellular in cellulars)
 73         if (cellular)
 74           blacks++;
 75       Out("Black:{0} White:{1}", blacks, cellulars.Length - blacks);
 76     }
 77
 78     void Out(string fmt, params object[] args)
 79     {
 80       gc.DrawString(string.Format(fmt, args), new Font("Courier New", 10),
 81         Brushes.Blue, new Point(5, lines * sizeCellular + 9));
 82     }
 83
 84     bool[] GetInitCellulars()
 85     {
 86       var rand = new Random();
 87       var cellulars = new bool[nCellular];
 88       for (var i = 0; i < cellulars.Length; i++)
 89         cellulars [i] = rand.Next() % 2 == 0;
 90       return cellulars;
 91     }
 92
 93     void DrawGrid(bool onlyBorder)
 94     {
 95       var pen = new Pen(Color.Red, 1);
 96       var len = nCellular * sizeCellular;
 97       for (var i = onlyBorder ? lines : 0; i <= lines; i++)
 98       {
 99         var k = i * sizeCellular;
100         gc.DrawLine(pen, 0, k, len, k);
101       }
102       len = lines * sizeCellular;
103       for (var i = onlyBorder ? nCellular : 0; i <= nCellular; i++)
104       {
105         var k = i * sizeCellular;
106         gc.DrawLine(pen, k, 0, k, len);
107       }
108     }
109
110     void Set(int x, int y)
111     {
112       var y2 = y * sizeCellular + sizeCellular / 2;
113       gc.DrawLine(pen, x * sizeCellular, y2, (x + 1) * sizeCellular, y2);
114     }
115
116     static void Main()
117     {
118       Application.Run(new MainForm());
119     }
120   }
121 }

简要分析

  1. 第9行的静态只读变量 sizeCellular 表示每个元胞方格的边长,必须为奇数。
  2. 第10行的静态只读变量 nCellular 表示每行有多少个元胞,最好为奇数,以免在多数分类时出现平局的情况。
  3. 第11行的静态只读变量 lines 表示要迭代多少次。
  4. 第13行的静态只读变量 strRuler 表示迭代的规则。
  5. 主要工作在从第29行到42行的 OnPaint 方法中进行。
  6. 第84行到第91行的 GetInitCellulars 方法随机地初始化元胞的初始状态。
  7. 第36行到第40行的循环按照指定的规则进行迭代。
  8. 第44行到第50行的 StepIt 方法执行具体的迭代步骤。
  9. 第52行到第60行的 GetValue 方法计算元胞邻域的值。

运行结果

该程序几次典型的运行结果如下所示:

上图显示白色占优,结果正确。这种情况很常见。

上图显示黑色占优,结果正确。这种情况也很常见。

上图显示白色占优,结果错误。这种情况比较少见。

上图显示黑色占优,结果错误。这个结果错误在于最终的迭代结果不是全黒,而混入了少量的白色元胞。这个程序只迭代 200 步,其实只要再迭代几步后就可以得到正确的结果。这种情况非常的少见。

版权声明:本文为博主http://www.zuiniusn.com原创文章,未经博主允许不得转载。

时间: 2024-10-09 18:21:48

用元胞自动机实现多数分类算法的相关文章

编程模拟自然(九):元胞自动机

序 旧书有云:发鸠之山,其上多柘木.有鸟焉,其状如乌,文首.白喙.赤足,名曰精卫,其鸣自詨. 一日,精卫游于码海,溺而不返,后常衔西山之木石,以堙于海.有诗为证: 万事有不平,尔何空自苦: 长将一寸身,衔木到终古? 我愿平码海,身沉心不改: 码海无平期,我心无绝时. 呜呼!君不见,西山衔木众鸟多,鹊来燕去自成窠! (前情提要:主角元乘坐返回舱降落到了码海上,随后遇到了个鸟人...) “咳咳,远道的客人,我名精卫XIV,乃是先祖精卫鸟的第十四代后裔...”鸟人作自我介绍 “...你是谁,从哪里来又

元胞自动机+生命游戏

元胞自动机 元胞自动机(Cellular Automaton,复数为Cellular Automata,简称CA,也有人译为细胞自动机.点格自动机.分子自动机或单元自动机).是一时间和空间都离散的动力系统.散布在规则格网 (Lattice Grid)中的每一元胞(Cell)取有限的离散状态,遵循同样的作用规则,依据确定的局部规则作同步更新.大量元胞通过简单的相互作用而构成动态系统的演化. 不同于一般的动力学模型,元胞自动机不是由严格定义的物理方程或函数确定,而是用一系列模型构造的规则构成.凡是满

元胞自动机

元胞自动机(cellular automata,CA)  元胞自动机(cellular automata,CA) 是一种时间.空间.状态都离散,空间相互作用和时间因果关系为局部的网格动力学模型,具有模拟复杂系统时空演化过程的能力. 元胞自动机是一类模型的总称,或者说是一个方法框架.其特点是时间.空间.状态都离散,每个变量只取有限多个状态,且其状态改变的规则在时间和空间上都是局部的. 有限自动机 有限自动机是一种控制状态有限.符号集有限的自动机,是一种离散输入输出系统的数学模型. 从数学上来定义,

【转载】【元胞自动机】生命游戏(时间简史)

原帖:http://www.cnblogs.com/lvpengms/archive/2010/02/08/1666095.html 晚上闲着没事干,鉴于前一段时间数学建模中看到了生命游戏 Game of Life,所以用C++实现一下,效果还不错. 本程序是用vs2005 C++编写,有意想要程序和源码的朋友可以给我发邮件. 更新:程序源码可以从这个地址下载:下载元胞自动机源码及程序 =======================================================

简要概述元胞自动机及其应用

谈一些自己的所学,有错误请指正. 元胞自动机( Cellular Automata) 是 20 世纪 50 年代初由计算机之父冯·诺依曼( J. von Neumann) 为了模拟生命系统所具有的自复制功能而提出来的.此后,史蒂芬·沃尔夫勒姆( Stephen Wolfram) 对元胞自动机理论进行了深入的研究,例如,他对一维初等元胞机全部 256 种规则所产生的模型进行了深入研究,并将元胞自动机分为平稳型.周期型.混沌型和复杂型 4 种类型. 元胞自动机采用离散的空间布局和离散的时间间隔,将元

元胞自动机简介

摘要: 元胞自动机能利用简单的局部规则和离散方法描述复杂的全局的连续系统,已成为探索复杂系统的一种有效工具. 文章 阐述了元胞自动机的发展历程.结构.特征及基本理论与方珐: 介绍了元胞自动机在寡头垄断行为.交通管理及工程运输.城市发展.市场营销.股票投资.企业战略等管理领域中的应用: 指出元胞自动机理论的优势与不足, 并提出进一步的研究展望. 1引言 复杂科学 20世纪80年代,以美国圣塔菲(SantaFe)学派为首提出了复杂科学,一经提出,在世界范围内引起了广泛的关注.目前,关于复杂性和复杂系

基于元胞自动机NaSch模型的多车道手动-自动混合驾驶仿真模型的Matlab实现

模型的建立基本来自于:http://www.doc88.com/p-2078634086043.html 花了一天半的时间用新学会的matlab实现了一下. NaSch模型主函数: function [ret_Vave] = NaSch() rng('shuffle'); global CellsNum; CellsNum = 200; %The number of cells in each lane global LanesNum; LanesNum = 3; %The number of

几个设计元胞自动机式智能的挑战

知道我的理论的人不多,但是这个问题完全可以当成一个小游戏,规则如下: 有若干"神经元",每个处在激活态或未激活态(一共2个状态) 神经元有"能量"和"阈值",为方便理解,先假设每个神经元都一样 神经元间存在单向的联系,允许两个神经元间有多个联系(比如一正一反) 这若干个神经元可以进行"演化",每次演化,神经元同时行动,先把自己的能量平均分给联系到的神经元,然后如果接收到超过阈值的能量,就激活,否则不激活. 如果两个神经元同时激

Python案例(一):协程实现康威生命游戏,元胞自动机

from collections import namedtuple import os,time import random Query=namedtuple('Query',('y','x')) Transition=namedtuple('Transition',('y','x','state')) ALIVE="*" EMPTY="-" def count_neighbors(y,x): n_=yield Query(y+1,x+0) ne=yield Qu