转自:https://instruct1.cit.cornell.edu/courses/bionb441/CA/
中文翻译:http://download.csdn.net/detail/caiye917015406/5032699
Cornell University
BioNB 441
Cellular Automata in Matlab
Introduction
Cellular Automata (CA) are a scheme for computing using local rules and local communication. Typcally a CA is defined on a grid, with each point on the grid representing a cell with a finite number of states. A transition rule is applied to each cell simultaneously. Typical transition rules depend on the state of the cell and its (4 or 8) nearest neighbors, although other neighborhoods are used. CAs have applications in parallel computing research, physical simulations, and biological simulations. This page will consider how to write efficient matlab code to implememt CAs and look at some interesting rules.
Matlab code considerations
The following considerations will be illustrated using a Matlab program which computes Conway's life. Parts of the code are explained below.
cells
contains the binary state of each cell and the arrayz
contains zeros, then thecat
command builds an RGB image, which is displayed by theimage
command. Theimage
command also returns a handle. imh = image(cat(3,cells,z,z)); set(imh, 'erasemode', 'none') axis equal axis tight
z = zeros(n,n); cells = z; cells(n/2,.25*n:.75*n) = 1; cells(.25*n:.75*n,n/2) = 1;
x = 2:n-1; y = 2:n-1; sum(x,y) = cells(x,y-1) + cells(x,y+1) + ... cells(x-1, y) + cells(x+1,y) + ... cells(x-1,y-1) + cells(x-1,y+1) + ... cells(x+1,y-1) + cells(x+1,y+1); cells = (sum==3) | (sum==2 & cells);
%build the GUI %define the plot button plotbutton=uicontrol('style','pushbutton',... 'string','Run', ... 'fontsize',12, ... 'position',[100,400,50,20], ... 'callback', 'run=1;'); %define the stop button erasebutton=uicontrol('style','pushbutton',... 'string','Stop', ... 'fontsize',12, ... 'position',[200,400,50,20], ... 'callback','freeze=1;'); %define the Quit button quitbutton=uicontrol('style','pushbutton',... 'string','Quit', ... 'fontsize',12, ... 'position',[300,400,50,20], ... 'callback','stop=1;close;'); number = uicontrol('style','text', ... 'string','1', ... 'fontsize',12, ... 'position',[20,400,50,20]);After the controls (and CA) are initialized, the program drops into a loop which tests the state of the variables which are set in the callback functions of each button. For the moment, just look at the nested structure of the while loop and if statements. The program loops until the Quit button is pushed. The other two buttons cause an if statement to execute when pushed.
stop= 0; %wait for a quit button push run = 0; %wait for a draw freeze = 0; %wait for a freeze while (stop==0) if (run==1) %nearest neighbor sum sum(x,y) = cells(x,y-1) + cells(x,y+1) + ... cells(x-1, y) + cells(x+1,y) + ... cells(x-1,y-1) + cells(x-1,y+1) + ... cells(3:n,y-1) + cells(x+1,y+1); % The CA rule cells = (sum==3) | (sum==2 & cells); %draw the new image set(imh, 'cdata', cat(3,cells,z,z) ) %update the step number diaplay stepnumber = 1 + str2num(get(number,'string')); set(number,'string',num2str(stepnumber)) end if (freeze==1) run = 0; freeze = 0; end drawnow %need this in the loop for controls to work end
Examples
x = 2:n-1; y = 2:n-1; %nearest neighbor sum sum(x,y) = cells(x,y-1) + cells(x,y+1) + ... cells(x-1, y) + cells(x+1,y) + ... cells(x-1,y-1) + cells(x-1,y+1) + ... cells(3:n,y-1) + cells(x+1,y+1); % The CA rule cells = (sum==3) | (sum==2 & cells);
x = 2:n-1; y = 2:n-1; sum(x,y) = cells(x,y-1) + cells(x,y+1) + ... cells(x-1, y) + cells(x+1,y) + ... cells(x-1,y-1) + cells(x-1,y+1) + ... cells(3:n,y-1) + cells(x+1,y+1)+... cells(x,y); % The CA rule cells = ~((sum< 4) | (sum==5));
sum(2:a-1,2:b-1) = cells(2:a-1,1:b-2) + cells(2:a-1,3:b) + ... cells(1:a-2, 2:b-1) + cells(3:a,2:b-1) + ... cells(1:a-2,1:b-2) + cells(1:a-2,3:b) + ... cells(3:a,1:b-2) + cells(3:a,3:b); pick = rand(a,b); cells = cells | ((sum>=1) & (pick>=threshold) & (visit==0)) ; visit = (sum>=1) ;The variables a and b are the size of the image. The inital image is determined by graphics operations. The following statements set up axes of a fixed size, write text into the axes, then grab the contents of the axes and put them back into an array using the
getframe
function.. ax = axes('units','pixels','position',[1 1 500 400],'color','k'); text('units', 'pixels', 'position', [50,255,0],... 'string','BioNB','color','w','fontname','helvetica','fontsize',100) text('units', 'pixels', 'position', [120,120,0],... 'string','441','color','w','fontname','helvetica','fontsize',100) initial = getframe(gca); [a,b,c]=size(initial.cdata); z=zeros(a,b); cells = double(initial.cdata(:,:,1)==255); visit = z ; sum = z;After a few dozen time steps (starting with the BioNB 441 image) we get the following image. Click on it to see a full size image.
x = [2:n-1]; y = [2:n-1]; sum(x,y) = ((cells(x,y-1)> 0)&(cells(x,y-1)< t)) + ((cells(x,y+1)> 0)&(cells(x,y+1)< t)) + ... ((cells(x-1, y)> 0)&(cells(x-1, y)< t)) + ((cells(x+1,y)> 0)&(cells(x+1,y)< t)) + ... ((cells(x-1,y-1)> 0)&(cells(x-1,y-1)< t)) + ((cells(x-1,y+1)> 0)&(cells(x-1,y+1)< t)) + ... ((cells(x+1,y-1)> 0)&(cells(x+1,y-1)< t)) + ((cells(x+1,y+1)> 0)&(cells(x+1,y+1)< t)); cells = ((cells==0) & (sum>=t1)) + ... 2*(cells==1) + ... 3*(cells==2) + ... 4*(cells==3) + ... 5*(cells==4) + ... 6*(cells==5) +... 7*(cells==6) +... 8*(cells==7) +... 9*(cells==8) +... 0*(cells==9);An image from this CA after spiral waves develop is shown below.
sum = (veg(1:n,[n 1:n-1])==1) + (veg(1:n,[2:n 1])==1) + ... (veg([n 1:n-1], 1:n)==1) + (veg([2:n 1],1:n)==1) ; veg = ... 2*(veg==2) - ((veg==2) & (sum> 0 | (rand(n,n)< Plightning))) + ... 2*((veg==0) & rand(n,n)< Pgrowth) ;Note that the toroidal connection is implemented by the ordering of subscripts.
even | even | |
even | cell | odd |
odd | odd |
The rule:
0 | 0 | goes | 0 | 0 |
0 | 0 | to | 0 | 0 |
1 | 0 | goes | 0 | 0 |
0 | 0 | to | 0 | 1 |
1 | 0 | goes | 1 | 0 |
0 | 1 | to | 0 | 1 |
1 | 0 | goes | 0 | 1 |
1 | 0 | to | 0 | 1 |
1 | 1 | goes | 0 | 1 |
1 | 0 | to | 1 | 1 |
1 | 1 | goes | 1 | 1 |
1 | 1 | to | 1 | 1 |
1 | 0 | goes | 0 | 1 |
0 | 1 | to | 1 | 0 |
p=mod(i,2); %margolis neighborhood, where i is the time step %upper left cell update xind = [1+p:2:nx-2+p]; yind = [1+p:2:ny-2+p]; %See if exactly one diagonal is ones %only (at most) one of the following can be true! diag1(xind,yind) = (sand(xind,yind)==1) & (sand(xind+1,yind+1)==1) & ... (sand(xind+1,yind)==0) & (sand(xind,yind+1)==0); diag2(xind,yind) = (sand(xind+1,yind)==1) & (sand(xind,yind+1)==1) & ... (sand(xind,yind)==0) & (sand(xind+1,yind+1)==0); %The diagonals both not occupied by two particles and12(xind,yind) = (diag1(xind,yind)==0) & (diag2(xind,yind)==0); %One diagonal is occupied by two particles or12(xind,yind) = diag1(xind,yind) | diag2(xind,yind); %for every gas particle see if it near the boundary sums(xind,yind) = gnd(xind,yind) | gnd(xind+1,yind) | ... gnd(xind,yind+1) | gnd(xind+1,yind+1) ; % cell layout: % x,y x+1,y % x,y+1 x+1,y+1 %If (no walls) and (diagonals are both not occupied) %then there is no collision, so move opposite cell to current cell %If (no walls) and (only one diagonal is occupied) %then there is a collision so move ccw cell to the current cell %If (a wall) %then don't change the cell (causes a reflection) sandNew(xind,yind) = ... (and12(xind,yind) & ~sums(xind,yind) & sand(xind+1,yind+1)) + ... (or12(xind,yind) & ~sums(xind,yind) & sand(xind,yind+1)) + ... (sums(xind,yind) & sand(xind,yind)); sandNew(xind+1,yind) = ... (and12(xind,yind) & ~sums(xind,yind) & sand(xind,yind+1)) + ... (or12(xind,yind) & ~sums(xind,yind) & sand(xind,yind))+ ... (sums(xind,yind) & sand(xind+1,yind)); sandNew(xind,yind+1) = ... (and12(xind,yind) & ~sums(xind,yind) & sand(xind+1,yind)) + ... (or12(xind,yind) & ~sums(xind,yind) & sand(xind+1,yind+1))+ ... (sums(xind,yind) & sand(xind,yind+1)); sandNew(xind+1,yind+1) = ... (and12(xind,yind) & ~sums(xind,yind) & sand(xind,yind)) + ... (or12(xind,yind) & ~sums(xind,yind) & sand(xind+1,yind))+ ... (sums(xind,yind) & sand(xind+1,yind+1)); sand = sandNew;
The rule:
p=mod(i,2); %margolis neighborhood %upper left cell update xind = [1+p:2:nx-2+p]; yind = [1+p:2:ny-2+p]; %random velocity choice vary = rand(nx,ny)< .5 ; vary1 = 1-vary; %diffusion rule -- margolus neighborhood %rotate the 4 cells to randomize velocity sandNew(xind,yind) = ... vary(xind,yind).*sand(xind+1,yind) + ... %cw vary1(xind,yind).*sand(xind,yind+1) ; %ccw sandNew(xind+1,yind) = ... vary(xind,yind).*sand(xind+1,yind+1) + ... vary1(xind,yind).*sand(xind,yind) ; sandNew(xind,yind+1) = ... vary(xind,yind).*sand(xind,yind) + ... vary1(xind,yind).*sand(xind+1,yind+1) ; sandNew(xind+1,yind+1) = ... vary(xind,yind).*sand(xind,yind+1) + ... vary1(xind,yind).*sand(xind+1,yind) ; sand = sandNew; %for every sand grain see if it near the fixed, sticky cluster sum(2:nx-1,2:ny-1) = gnd(2:nx-1,1:ny-2) + gnd(2:nx-1,3:ny) + ... gnd(1:nx-2, 2:ny-1) + gnd(3:nx,2:ny-1) + ... gnd(1:nx-2,1:ny-2) + gnd(1:nx-2,3:ny) + ... gnd(3:nx,1:ny-2) + gnd(3:nx,3:ny); %add to the cluster gnd = ((sum> 0) & (sand==1)) | gnd ; %and eliminate the moving particle sand(find(gnd==1)) = 0;The following image shows the fixed cluster after many time steps.
The rule:
0 | 0 | goes | 0 | 0 |
0 | 0 | to | 0 | 0 |
1 | 0 | goes | 0 | 0 |
0 | 0 | to | 1 | 0 |
0 | 1 | goes | 0 | 0 |
0 | 0 | to | 0 | 1 |
1 | 0 | goes | 0 | 0 |
1 | 0 | to | 1 | 1 |
1 | 0 | goes | 0 | 0 |
0 | 1 | to | 1 | 1 |
0 | 1 | goes | 0 | 0 |
1 | 0 | to | 1 | 1 |
0 | 1 | goes | 0 | 0 |
0 | 1 | to | 1 | 1 |
1 | 1 | goes | 1 | 0 |
1 | 0 | to | 1 | 1 |
1 | 1 | goes | 0 | 1 |
0 | 1 | to | 1 | 1 |
The update code:
p=mod(i,2); %margolis neighborhood sand(nx/2,ny/2) = 1; %add a grain at the top %upper left cell update xind = [1+p:2:nx-2+p]; yind = [1+p:2:ny-2+p]; %randomize the flow -- 10% of the time vary = rand(nx,ny)< .9 ; vary1 = 1-vary; sandNew(xind,yind) = ... gnd(xind,yind).*sand(xind,yind) + ... (1-gnd(xind,yind)).*sand(xind,yind).*sand(xind,yind+1) .* ... (sand(xind+1,yind+1)+(1-sand(xind+1,yind+1)).*sand(xind+1,yind)); sandNew(xind+1,yind) = ... gnd(xind+1,yind).*sand(xind+1,yind) + ... (1-gnd(xind+1,yind)).*sand(xind+1,yind).*sand(xind+1,yind+1) .* ... (sand(xind,yind+1)+(1-sand(xind,yind+1)).*sand(xind,yind)); sandNew(xind,yind+1) = ... sand(xind,yind+1) + ... (1-sand(xind,yind+1)) .* ... ( sand(xind,yind).*(1-gnd(xind,yind)) + ... (1-sand(xind,yind)).*sand(xind+1,yind).*(1-gnd(xind+1,yind)).*sand(xind+1,yind+1)); sandNew(xind+1,yind+1) = ... sand(xind+1,yind+1) + ... (1-sand(xind+1,yind+1)) .* ... ( sand(xind+1,yind).*(1-gnd(xind+1,yind)) + ... (1-sand(xind+1,yind)).*sand(xind,yind).*(1-gnd(xind,yind)).*sand(xind,yind+1)); %scramble the sites to make it look better temp1 = sandNew(xind,yind+1).*vary(xind,yind+1) + ... sandNew(xind+1,yind+1).*vary1(xind,yind+1); temp2 = sandNew(xind+1,yind+1).*vary(xind,yind+1) + ... sandNew(xind,yind+1).*vary1(xind,yind+1); sandNew(xind,yind+1) = temp1; sandNew(xind+1,yind+1) = temp2; sand = sandNew;
References
[1] Cellular Automata Machines by Tommaso Toffoli and Norman Margolus, MIT Press, 1987.
[2] Cellular Automata Modeling of Physical Systems by Bastien Chopard and Michel Droz, Cambridge University Press, 1998.